From f04470ace7080f53233d1387e2dbb4d232bd5f7d Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 21 May 2025 17:45:19 -0400 Subject: [PATCH 1/4] Allow multiple client connections to the MCP server, by making a unique server tranpsort for each web app transport. * In server/src/index.ts - add serverTransports map - remove backingServerTransport var - in /mcp POST handler, when a new connection is being made - create a server transport - map the server transport using the session id from the web app connection - pass serverTransport to the mcpProxy instead of backingServerTransport - in /stdio GET handler, when a new connection is being made - create a server transport - map the server transport using the session id from the web app connection - pass serverTransport to the mcpProxy instead of backingServerTransport - in /sse GET handler, when a new connection is being made - create a server transport - map the server transport using the session id from the web app connection - pass serverTransport to the mcpProxy instead of backingServerTransport --- server/src/index.ts | 57 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index c967b60c7..8bc8a53c1 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -48,7 +48,8 @@ app.use((req, res, next) => { next(); }); -const webAppTransports: Map = new Map(); // Transports by sessionId +const webAppTransports: Map = new Map(); // Web app transports by web app sessionId +const serverTransports: Map = new Map(); // Server Transports by web app sessionId const createTransport = async (req: express.Request): Promise => { const query = req.query; @@ -137,8 +138,6 @@ const createTransport = async (req: express.Request): Promise => { } }; -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}`); @@ -161,12 +160,12 @@ 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}`); + let serverTransport: Transport | undefined; if (!sessionId) { try { console.log("New streamable-http connection"); try { - await backingServerTransport?.close(); - backingServerTransport = await createTransport(req); + serverTransport = await createTransport(req); } catch (error) { if (error instanceof SseError && error.code === 401) { console.error( @@ -180,12 +179,13 @@ app.post("/mcp", async (req, res) => { throw error; } - console.log("Connected MCP client to backing server transport"); + console.log("Connected MCP client to server transport"); const webAppTransport = new StreamableHTTPServerTransport({ sessionIdGenerator: randomUUID, onsessioninitialized: (sessionId) => { webAppTransports.set(sessionId, webAppTransport); + serverTransports.set(sessionId, serverTransport!); console.log("Created streamable web app transport " + sessionId); }, }); @@ -194,7 +194,7 @@ app.post("/mcp", async (req, res) => { mcpProxy({ transportToClient: webAppTransport, - transportToServer: backingServerTransport, + transportToServer: serverTransport, }); await (webAppTransport as StreamableHTTPServerTransport).handleRequest( @@ -229,10 +229,9 @@ app.post("/mcp", async (req, res) => { app.get("/stdio", async (req, res) => { try { console.log("New connection"); - + let serverTransport: Transport | undefined; try { - await backingServerTransport?.close(); - backingServerTransport = await createTransport(req); + serverTransport = await createTransport(req); } catch (error) { if (error instanceof SseError && error.code === 401) { console.error( @@ -250,26 +249,24 @@ app.get("/stdio", async (req, res) => { const webAppTransport = new SSEServerTransport("/message", res); webAppTransports.set(webAppTransport.sessionId, webAppTransport); - - console.log("Created web app transport"); + serverTransports.set(webAppTransport.sessionId, serverTransport); + console.log("Created client/server transports"); await webAppTransport.start(); - (backingServerTransport as StdioClientTransport).stderr!.on( - "data", - (chunk) => { - webAppTransport.send({ - jsonrpc: "2.0", - method: "notifications/stderr", - params: { - content: chunk.toString(), - }, - }); - }, - ); + + (serverTransport as StdioClientTransport).stderr!.on("data", (chunk) => { + webAppTransport.send({ + jsonrpc: "2.0", + method: "notifications/stderr", + params: { + content: chunk.toString(), + }, + }); + }); mcpProxy({ transportToClient: webAppTransport, - transportToServer: backingServerTransport, + transportToServer: serverTransport, }); console.log("Set up MCP proxy"); @@ -284,10 +281,9 @@ app.get("/sse", async (req, res) => { console.log( "New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http", ); - + let serverTransport: SSEServerTransport | undefined; try { - await backingServerTransport?.close(); - backingServerTransport = await createTransport(req); + serverTransport = (await createTransport(req)) as SSEServerTransport; } catch (error) { if (error instanceof SseError && error.code === 401) { console.error( @@ -305,13 +301,14 @@ app.get("/sse", async (req, res) => { const webAppTransport = new SSEServerTransport("/message", res); webAppTransports.set(webAppTransport.sessionId, webAppTransport); - console.log("Created web app transport"); + serverTransports.set(webAppTransport.sessionId, serverTransport); + console.log("Created client/server transports"); await webAppTransport.start(); mcpProxy({ transportToClient: webAppTransport, - transportToServer: backingServerTransport, + transportToServer: serverTransport, }); console.log("Set up MCP proxy"); From bc90f11dc88ae15de0adc059164ea35ed7f77d48 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 28 May 2025 13:44:55 -0400 Subject: [PATCH 2/4] Address [comment](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2109509222) by @olaservo --- server/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index 8bc8a53c1..c4345ae64 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -281,9 +281,9 @@ app.get("/sse", async (req, res) => { console.log( "New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http", ); - let serverTransport: SSEServerTransport | undefined; + let serverTransport: Transport | undefined; try { - serverTransport = (await createTransport(req)) as SSEServerTransport; + serverTransport = (await createTransport(req)); } catch (error) { if (error instanceof SseError && error.code === 401) { console.error( From 9bc6bd725ee5e974047d2949644355dac5615828 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 28 May 2025 13:46:58 -0400 Subject: [PATCH 3/4] Address [comment](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2109509222) [by](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2108137150) @olaservo --- server/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/index.ts b/server/src/index.ts index c4345ae64..0b2aeec93 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -301,8 +301,9 @@ app.get("/sse", async (req, res) => { const webAppTransport = new SSEServerTransport("/message", res); webAppTransports.set(webAppTransport.sessionId, webAppTransport); + console.log("Created client transport"); serverTransports.set(webAppTransport.sessionId, serverTransport); - console.log("Created client/server transports"); + console.log("Created server transport"); await webAppTransport.start(); From 0c1962c2d06e11f7dab395a38c7104a9c0121640 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 28 May 2025 15:46:07 -0400 Subject: [PATCH 4/4] prettier --- server/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/index.ts b/server/src/index.ts index 0b2aeec93..73288f672 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -283,7 +283,7 @@ app.get("/sse", async (req, res) => { ); let serverTransport: Transport | undefined; try { - serverTransport = (await createTransport(req)); + serverTransport = await createTransport(req); } catch (error) { if (error instanceof SseError && error.code === 401) { console.error(