From ba02a1a47caf44a4019f7f4d739704fe98076577 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Tue, 10 Feb 2026 18:42:28 +0000 Subject: [PATCH] fix: create fresh Server per request in auth test helpers The auth test server helper and no-dns-rebinding-protection example reused a single Server instance across requests, calling connect() on each new transport. SDK v1.26.0's security fix (GHSA-345p-7cg4-v4c7) now throws "Already connected to a transport" in this case. Fix by wrapping Server creation in a factory function called per request, matching the pattern already used by tools_call.ts and everything-server.ts. Also updates no-dns-rebinding-protection.ts to use registerTool() instead of the deprecated tool() API. Co-Authored-By: Claude Opus 4.6 --- .../typescript/no-dns-rebinding-protection.ts | 35 +++++---- .../client/auth/helpers/createServer.ts | 73 ++++++++++--------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/examples/servers/typescript/no-dns-rebinding-protection.ts b/examples/servers/typescript/no-dns-rebinding-protection.ts index f1ff754..1e0fc3c 100644 --- a/examples/servers/typescript/no-dns-rebinding-protection.ts +++ b/examples/servers/typescript/no-dns-rebinding-protection.ts @@ -13,21 +13,27 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import express from 'express'; -// Create minimal MCP server -const server = new McpServer({ - name: 'no-dns-rebinding-protection-server', - version: '1.0.0' -}); +// Create a fresh MCP server per request to avoid "Already connected" errors +// after the v1.26.0 security fix (GHSA-345p-7cg4-v4c7) +function createMcpServer() { + const server = new McpServer({ + name: 'no-dns-rebinding-protection-server', + version: '1.0.0' + }); + + server.registerTool( + 'echo', + { + description: 'Echo the input back', + inputSchema: { message: { type: 'string' } } + }, + async ({ message }) => ({ + content: [{ type: 'text', text: `Echo: ${message}` }] + }) + ); -// Add a simple tool -server.tool( - 'echo', - 'Echo the input back', - { message: { type: 'string' } }, - async ({ message }) => ({ - content: [{ type: 'text', text: `Echo: ${message}` }] - }) -); + return server; +} // === VULNERABLE EXPRESS APP === // This intentionally does NOT use createMcpExpressApp() or localhostHostValidation() @@ -37,6 +43,7 @@ app.use(express.json()); app.post('/mcp', async (req, res) => { try { + const server = createMcpServer(); // Stateless: no session ID const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined diff --git a/src/scenarios/client/auth/helpers/createServer.ts b/src/scenarios/client/auth/helpers/createServer.ts index 35b89b1..c836630 100644 --- a/src/scenarios/client/auth/helpers/createServer.ts +++ b/src/scenarios/client/auth/helpers/createServer.ts @@ -41,43 +41,49 @@ export function createServer( tokenVerifier, prmResourceOverride } = options; - const server = new Server( - { - name: 'auth-prm-pathbased-server', - version: '1.0.0' - }, - { - capabilities: { - tools: {} + // Factory: create a fresh Server per request to avoid "Already connected" errors + // after the v1.26.0 security fix (GHSA-345p-7cg4-v4c7) + function createMcpServer() { + const server = new Server( + { + name: 'auth-prm-pathbased-server', + version: '1.0.0' + }, + { + capabilities: { + tools: {} + } } - } - ); + ); + + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: 'test-tool', + inputSchema: { type: 'object' } + } + ] + }; + }); - server.setRequestHandler(ListToolsRequestSchema, async () => { - return { - tools: [ - { - name: 'test-tool', - inputSchema: { type: 'object' } + server.setRequestHandler( + CallToolRequestSchema, + async (request): Promise => { + if (request.params.name === 'test-tool') { + return { + content: [{ type: 'text', text: 'test' }] + }; } - ] - }; - }); - - server.setRequestHandler( - CallToolRequestSchema, - async (request): Promise => { - if (request.params.name === 'test-tool') { - return { - content: [{ type: 'text', text: 'test' }] - }; + throw new McpError( + ErrorCode.InvalidParams, + `Tool ${request.params.name} not found` + ); } - throw new McpError( - ErrorCode.InvalidParams, - `Tool ${request.params.name} not found` - ); - } - ); + ); + + return server; + } const app = express(); app.use(express.json()); @@ -151,6 +157,7 @@ export function createServer( authMiddleware(req, res, async (err?: any) => { if (err) return next(err); + const server = createMcpServer(); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });