From fa236ea2c7bf519ab40f6dcef8a7e9fdb4bbe665 Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 6 May 2025 15:36:18 -0700 Subject: [PATCH 1/6] handle the case that client disconnects so that the server does not crash --- server/src/index.ts | 62 ++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index c967b60c7..587911bbf 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -141,7 +141,7 @@ let backingServerTransport: Transport | undefined; app.get("/mcp", async (req, res) => { const sessionId = req.headers["mcp-session-id"] as string; - console.log(`Received GET message for sessionId ${sessionId}`); + console.log(`GET /mcp for sessionId ${sessionId}`); try { const transport = webAppTransports.get( sessionId, @@ -160,7 +160,7 @@ app.get("/mcp", async (req, res) => { app.post("/mcp", async (req, res) => { const sessionId = req.headers["mcp-session-id"] as string | undefined; - console.log(`Received POST message for sessionId ${sessionId}`); + console.log(`POST /mcp for sessionId ${sessionId}`); if (!sessionId) { try { console.log("New streamable-http connection"); @@ -228,7 +228,7 @@ app.post("/mcp", async (req, res) => { app.get("/stdio", async (req, res) => { try { - console.log("New connection"); + console.log("GET /stdio"); try { await backingServerTransport?.close(); @@ -254,18 +254,44 @@ app.get("/stdio", async (req, res) => { console.log("Created web app transport"); await webAppTransport.start(); - (backingServerTransport as StdioClientTransport).stderr!.on( - "data", - (chunk) => { - webAppTransport.send({ - jsonrpc: "2.0", - method: "notifications/stderr", - params: { - content: chunk.toString(), - }, - }); - }, - ); + + // Handle client disconnection + res.on('close', () => { + console.log(`Client disconnected from session ${webAppTransport.sessionId}`); + // Clean up the transport map + webAppTransports.delete(webAppTransport.sessionId); + }); + + // Create a stderr handler that checks connection state + const stderrHandler = (chunk: Buffer) => { + try { + // Only send if the transport exists in our map (meaning it's still active) + if (webAppTransports.has(webAppTransport.sessionId)) { + webAppTransport.send({ + jsonrpc: "2.0", + method: "notifications/stderr", + params: { + content: chunk.toString(), + }, + }); + } + } catch (error: any) { + console.log(`Error sending stderr data to client: ${error.message}`); + // If we hit an error sending, clean up the transport + webAppTransports.delete(webAppTransport.sessionId); + } + }; + + if ((backingServerTransport as StdioClientTransport).stderr) { + (backingServerTransport as StdioClientTransport).stderr!.on("data", stderrHandler); + + // Store the handler reference so we can remove it when client disconnects + res.on('close', () => { + if ((backingServerTransport as StdioClientTransport).stderr) { + (backingServerTransport as StdioClientTransport).stderr!.removeListener("data", stderrHandler); + } + }); + } mcpProxy({ transportToClient: webAppTransport, @@ -282,7 +308,7 @@ app.get("/stdio", async (req, res) => { app.get("/sse", async (req, res) => { try { console.log( - "New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http", + "GET /sse (NOTE: The sse transport is deprecated and has been replaced by streamable-http)", ); try { @@ -324,7 +350,7 @@ app.get("/sse", async (req, res) => { app.post("/message", async (req, res) => { try { const sessionId = req.query.sessionId; - console.log(`Received message for sessionId ${sessionId}`); + console.log(`POST /message for sessionId ${sessionId}`); const transport = webAppTransports.get( sessionId as string, @@ -341,6 +367,7 @@ app.post("/message", async (req, res) => { }); app.get("/health", (req, res) => { + console.log("GET /health"); res.json({ status: "ok", }); @@ -348,6 +375,7 @@ app.get("/health", (req, res) => { app.get("/config", (req, res) => { try { + console.log("GET /config"); res.json({ defaultEnvironment, defaultCommand: values.env, From b9b3682350bf3ae45636a9704ff501fdcfcab870 Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 6 May 2025 15:44:58 -0700 Subject: [PATCH 2/6] format fix --- server/src/index.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index 587911bbf..afd30243e 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -254,14 +254,16 @@ app.get("/stdio", async (req, res) => { console.log("Created web app transport"); await webAppTransport.start(); - + // Handle client disconnection - res.on('close', () => { - console.log(`Client disconnected from session ${webAppTransport.sessionId}`); + res.on("close", () => { + console.log( + `Client disconnected from session ${webAppTransport.sessionId}`, + ); // Clean up the transport map webAppTransports.delete(webAppTransport.sessionId); }); - + // Create a stderr handler that checks connection state const stderrHandler = (chunk: Buffer) => { try { @@ -281,14 +283,19 @@ app.get("/stdio", async (req, res) => { webAppTransports.delete(webAppTransport.sessionId); } }; - + if ((backingServerTransport as StdioClientTransport).stderr) { - (backingServerTransport as StdioClientTransport).stderr!.on("data", stderrHandler); + (backingServerTransport as StdioClientTransport).stderr!.on( + "data", + stderrHandler, + ); // Store the handler reference so we can remove it when client disconnects - res.on('close', () => { + res.on("close", () => { if ((backingServerTransport as StdioClientTransport).stderr) { - (backingServerTransport as StdioClientTransport).stderr!.removeListener("data", stderrHandler); + ( + backingServerTransport as StdioClientTransport + ).stderr!.removeListener("data", stderrHandler); } }); } From 7df1936b3c7125600420808fc92fead1265f53c6 Mon Sep 17 00:00:00 2001 From: Shane Date: Sun, 18 May 2025 23:33:19 -0700 Subject: [PATCH 3/6] fixed the error handling in async call --- server/src/index.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index afd30243e..3ea88f446 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -266,21 +266,20 @@ app.get("/stdio", async (req, res) => { // Create a stderr handler that checks connection state const stderrHandler = (chunk: Buffer) => { - try { - // Only send if the transport exists in our map (meaning it's still active) - if (webAppTransports.has(webAppTransport.sessionId)) { - webAppTransport.send({ - jsonrpc: "2.0", - method: "notifications/stderr", - params: { - content: chunk.toString(), - }, - }); - } - } catch (error: any) { - console.log(`Error sending stderr data to client: ${error.message}`); - // If we hit an error sending, clean up the transport - webAppTransports.delete(webAppTransport.sessionId); + // Only send if the transport exists in our map (meaning it's still active) + if (webAppTransports.has(webAppTransport.sessionId)) { + webAppTransport.send({ + jsonrpc: "2.0", + method: "notifications/stderr", + params: { + content: chunk.toString(), + }, + }) + .catch((error: any) => { + console.error(`Error sending stderr data to client: ${error.message}`); + // If we hit an error sending, clean up the transport + webAppTransports.delete(webAppTransport.sessionId); + }); } }; From a61a1b0df2b557653f55933f98e9781b14ec98c2 Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 20 May 2025 09:25:47 -0700 Subject: [PATCH 4/6] format update with prettier --- server/src/index.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index 3ea88f446..955d02671 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -268,18 +268,21 @@ app.get("/stdio", async (req, res) => { const stderrHandler = (chunk: Buffer) => { // Only send if the transport exists in our map (meaning it's still active) if (webAppTransports.has(webAppTransport.sessionId)) { - webAppTransport.send({ - jsonrpc: "2.0", - method: "notifications/stderr", - params: { - content: chunk.toString(), - }, - }) - .catch((error: any) => { - console.error(`Error sending stderr data to client: ${error.message}`); - // If we hit an error sending, clean up the transport - webAppTransports.delete(webAppTransport.sessionId); - }); + webAppTransport + .send({ + jsonrpc: "2.0", + method: "notifications/stderr", + params: { + content: chunk.toString(), + }, + }) + .catch((error: any) => { + console.error( + `Error sending stderr data to client: ${error.message}`, + ); + // If we hit an error sending, clean up the transport + webAppTransports.delete(webAppTransport.sessionId); + }); } }; From 80377bc914bb6f05a3a695cf3d2d99439e582b4d Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 20 May 2025 22:28:26 -0700 Subject: [PATCH 5/6] fix the PR build error --- client/src/components/ToolsTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index aa67bfcff..8b6255673 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -82,7 +82,7 @@ const ToolsTab = ({ Success )} - {structuredResult.content.map((item, index) => ( + {structuredResult.content?.map((item, index) => (
{item.type === "text" && ( From 3232c0e11eab10b50b01238a0b26b476f56fae1b Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 21 May 2025 10:21:39 -0700 Subject: [PATCH 6/6] Revert "fix the PR build error" This reverts commit 80377bc914bb6f05a3a695cf3d2d99439e582b4d. --- client/src/components/ToolsTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 8b6255673..aa67bfcff 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -82,7 +82,7 @@ const ToolsTab = ({ Success )} - {structuredResult.content?.map((item, index) => ( + {structuredResult.content.map((item, index) => (
{item.type === "text" && (