Skip to content

Commit e462a43

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 38e0776 + 03edbb0 commit e462a43

File tree

3 files changed

+102
-54
lines changed

3 files changed

+102
-54
lines changed

client/src/components/Sidebar.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,28 @@ const Sidebar = ({
285285
<label className="text-sm font-medium" htmlFor="sse-url-input">
286286
URL
287287
</label>
288-
<Input
289-
id="sse-url-input"
290-
placeholder="URL"
291-
value={sseUrl}
292-
onChange={(e) => setSseUrl(e.target.value)}
293-
className="font-mono"
294-
/>
288+
{sseUrl ? (
289+
<Tooltip>
290+
<TooltipTrigger asChild>
291+
<Input
292+
id="sse-url-input"
293+
placeholder="URL"
294+
value={sseUrl}
295+
onChange={(e) => setSseUrl(e.target.value)}
296+
className="font-mono"
297+
/>
298+
</TooltipTrigger>
299+
<TooltipContent>{sseUrl}</TooltipContent>
300+
</Tooltip>
301+
) : (
302+
<Input
303+
id="sse-url-input"
304+
placeholder="URL"
305+
value={sseUrl}
306+
onChange={(e) => setSseUrl(e.target.value)}
307+
className="font-mono"
308+
/>
309+
)}
295310
</div>
296311
<div className="space-y-2">
297312
<Button

server/src/index.ts

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const serverTransports: Map<string, Transport> = new Map<string, Transport>(); /
9191

9292
const createTransport = async (req: express.Request): Promise<Transport> => {
9393
const query = req.query;
94-
console.log("Query parameters:", query);
94+
console.log("Query parameters:", JSON.stringify(query));
9595

9696
const transportType = query.transportType as string;
9797

@@ -103,7 +103,7 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
103103

104104
const { cmd, args } = findActualExecutable(command, origArgs);
105105

106-
console.log(`Stdio transport: command=${cmd}, args=${args}`);
106+
console.log(`STDIO transport: command=${cmd}, args=${args}`);
107107

108108
const transport = new StdioClientTransport({
109109
command: cmd,
@@ -113,8 +113,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
113113
});
114114

115115
await transport.start();
116-
117-
console.log("Spawned stdio transport");
118116
return transport;
119117
} else if (transportType === "sse") {
120118
const url = query.url as string;
@@ -132,8 +130,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
132130
},
133131
});
134132
await transport.start();
135-
136-
console.log("Connected to SSE transport");
137133
return transport;
138134
} else if (transportType === "streamable-http") {
139135
const headers = getHttpHeaders(req, transportType);
@@ -147,7 +143,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
147143
},
148144
);
149145
await transport.start();
150-
console.log("Connected to Streamable HTTP transport");
151146
return transport;
152147
} else {
153148
console.error(`Invalid transport type: ${transportType}`);
@@ -176,11 +171,10 @@ app.get("/mcp", async (req, res) => {
176171

177172
app.post("/mcp", async (req, res) => {
178173
const sessionId = req.headers["mcp-session-id"] as string | undefined;
179-
console.log(`Received POST message for sessionId ${sessionId}`);
180174
let serverTransport: Transport | undefined;
181175
if (!sessionId) {
182176
try {
183-
console.log("New streamable-http connection");
177+
console.log("New StreamableHttp connection request");
184178
try {
185179
serverTransport = await createTransport(req);
186180
} catch (error) {
@@ -196,16 +190,17 @@ app.post("/mcp", async (req, res) => {
196190
throw error;
197191
}
198192

199-
console.log("Connected MCP client to server transport");
193+
console.log("Created StreamableHttp server transport");
200194

201195
const webAppTransport = new StreamableHTTPServerTransport({
202196
sessionIdGenerator: randomUUID,
203197
onsessioninitialized: (sessionId) => {
204198
webAppTransports.set(sessionId, webAppTransport);
205199
serverTransports.set(sessionId, serverTransport!);
206-
console.log("Created streamable web app transport " + sessionId);
200+
console.log("Client <-> Proxy sessionId: " + sessionId);
207201
},
208202
});
203+
console.log("Created StreamableHttp client transport");
209204

210205
await webAppTransport.start();
211206

@@ -224,6 +219,7 @@ app.post("/mcp", async (req, res) => {
224219
res.status(500).json(error);
225220
}
226221
} else {
222+
console.log(`Received POST message for sessionId ${sessionId}`);
227223
try {
228224
const transport = webAppTransports.get(
229225
sessionId,
@@ -272,15 +268,15 @@ app.delete("/mcp", async (req, res) => {
272268

273269
app.get("/stdio", async (req, res) => {
274270
try {
275-
console.log("New connection");
271+
console.log("New STDIO connection request");
276272
let serverTransport: Transport | undefined;
277273
try {
278274
serverTransport = await createTransport(req);
275+
console.log("Created server transport");
279276
} catch (error) {
280277
if (error instanceof SseError && error.code === 401) {
281278
console.error(
282-
"Received 401 Unauthorized from MCP server:",
283-
error.message,
279+
"Received 401 Unauthorized from MCP server. Authentication failure.",
284280
);
285281
res.status(401).json(error);
286282
return;
@@ -289,31 +285,43 @@ app.get("/stdio", async (req, res) => {
289285
throw error;
290286
}
291287

292-
console.log("Connected MCP client to backing server transport");
293-
294288
const webAppTransport = new SSEServerTransport("/message", res);
289+
console.log("Created client transport");
290+
295291
webAppTransports.set(webAppTransport.sessionId, webAppTransport);
296292
serverTransports.set(webAppTransport.sessionId, serverTransport);
297-
console.log("Created client/server transports");
298293

299294
await webAppTransport.start();
300295

301296
(serverTransport as StdioClientTransport).stderr!.on("data", (chunk) => {
302-
webAppTransport.send({
303-
jsonrpc: "2.0",
304-
method: "notifications/stderr",
305-
params: {
306-
content: chunk.toString(),
307-
},
308-
});
297+
if (chunk.toString().includes("MODULE_NOT_FOUND")) {
298+
webAppTransport.send({
299+
jsonrpc: "2.0",
300+
method: "notifications/stderr",
301+
params: {
302+
content: "Command not found, transports removed",
303+
},
304+
});
305+
webAppTransport.close();
306+
serverTransport.close();
307+
webAppTransports.delete(webAppTransport.sessionId);
308+
serverTransports.delete(webAppTransport.sessionId);
309+
console.error("Command not found, transports removed");
310+
} else {
311+
webAppTransport.send({
312+
jsonrpc: "2.0",
313+
method: "notifications/stderr",
314+
params: {
315+
content: chunk.toString(),
316+
},
317+
});
318+
}
309319
});
310320

311321
mcpProxy({
312322
transportToClient: webAppTransport,
313323
transportToServer: serverTransport,
314324
});
315-
316-
console.log("Set up MCP proxy");
317325
} catch (error) {
318326
console.error("Error in /stdio route:", error);
319327
res.status(500).json(error);
@@ -323,40 +331,46 @@ app.get("/stdio", async (req, res) => {
323331
app.get("/sse", async (req, res) => {
324332
try {
325333
console.log(
326-
"New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http",
334+
"New SSE connection request. NOTE: The sse transport is deprecated and has been replaced by StreamableHttp",
327335
);
328336
let serverTransport: Transport | undefined;
329337
try {
330338
serverTransport = await createTransport(req);
331339
} catch (error) {
332340
if (error instanceof SseError && error.code === 401) {
333341
console.error(
334-
"Received 401 Unauthorized from MCP server:",
335-
error.message,
342+
"Received 401 Unauthorized from MCP server. Authentication failure.",
336343
);
337344
res.status(401).json(error);
338345
return;
346+
} else if (error instanceof SseError && error.code === 404) {
347+
console.error(
348+
"Received 404 not found from MCP server. Does the MCP server support SSE?",
349+
);
350+
res.status(404).json(error);
351+
return;
352+
} else if (JSON.stringify(error).includes("ECONNREFUSED")) {
353+
console.error("Connection refused. Is the MCP server running?");
354+
res.status(500).json(error);
355+
} else {
356+
throw error;
339357
}
340-
341-
throw error;
342358
}
343359

344-
console.log("Connected MCP client to backing server transport");
360+
if (serverTransport) {
361+
const webAppTransport = new SSEServerTransport("/message", res);
362+
webAppTransports.set(webAppTransport.sessionId, webAppTransport);
363+
console.log("Created client transport");
364+
serverTransports.set(webAppTransport.sessionId, serverTransport!);
365+
console.log("Created server transport");
345366

346-
const webAppTransport = new SSEServerTransport("/message", res);
347-
webAppTransports.set(webAppTransport.sessionId, webAppTransport);
348-
console.log("Created client transport");
349-
serverTransports.set(webAppTransport.sessionId, serverTransport);
350-
console.log("Created server transport");
351-
352-
await webAppTransport.start();
353-
354-
mcpProxy({
355-
transportToClient: webAppTransport,
356-
transportToServer: serverTransport,
357-
});
367+
await webAppTransport.start();
358368

359-
console.log("Set up MCP proxy");
369+
mcpProxy({
370+
transportToClient: webAppTransport,
371+
transportToServer: serverTransport,
372+
});
373+
}
360374
} catch (error) {
361375
console.error("Error in /sse route:", error);
362376
res.status(500).json(error);
@@ -366,7 +380,7 @@ app.get("/sse", async (req, res) => {
366380
app.post("/message", async (req, res) => {
367381
try {
368382
const sessionId = req.query.sessionId;
369-
console.log(`Received message for sessionId ${sessionId}`);
383+
console.log(`Received POST message for sessionId ${sessionId}`);
370384

371385
const transport = webAppTransports.get(
372386
sessionId as string,

server/src/mcpProxy.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ function onClientError(error: Error) {
66
}
77

88
function onServerError(error: Error) {
9-
console.error("Error from MCP server:", error);
9+
if (
10+
(error?.message &&
11+
error.message.includes("Error POSTing to endpoint (HTTP 404)")) ||
12+
(error?.cause && JSON.stringify(error.cause).includes("ECONNREFUSED"))
13+
) {
14+
console.error("Connection refused. Is the MCP server running?");
15+
} else {
16+
console.error("Error from MCP server:", error);
17+
}
1018
}
1119

1220
export default function mcpProxy({
@@ -19,6 +27,8 @@ export default function mcpProxy({
1927
let transportToClientClosed = false;
2028
let transportToServerClosed = false;
2129

30+
let reportedServerSession = false;
31+
2232
transportToClient.onmessage = (message) => {
2333
transportToServer.send(message).catch((error) => {
2434
// Send error response back to client if it was a request (has id) and connection is still open
@@ -38,6 +48,15 @@ export default function mcpProxy({
3848
};
3949

4050
transportToServer.onmessage = (message) => {
51+
if (!reportedServerSession) {
52+
if (transportToServer.sessionId) {
53+
// Can only report for StreamableHttp
54+
console.error(
55+
"Proxy <-> Server sessionId: " + transportToServer.sessionId,
56+
);
57+
}
58+
reportedServerSession = true;
59+
}
4160
transportToClient.send(message).catch(onClientError);
4261
};
4362

0 commit comments

Comments
 (0)