Skip to content

Commit 37225ce

Browse files
fix: create fresh Server per request in auth test helpers (#141)
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 <[email protected]>
1 parent a1b8aaa commit 37225ce

File tree

2 files changed

+61
-47
lines changed

2 files changed

+61
-47
lines changed

examples/servers/typescript/no-dns-rebinding-protection.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,27 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1313
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
1414
import express from 'express';
1515

16-
// Create minimal MCP server
17-
const server = new McpServer({
18-
name: 'no-dns-rebinding-protection-server',
19-
version: '1.0.0'
20-
});
16+
// Create a fresh MCP server per request to avoid "Already connected" errors
17+
// after the v1.26.0 security fix (GHSA-345p-7cg4-v4c7)
18+
function createMcpServer() {
19+
const server = new McpServer({
20+
name: 'no-dns-rebinding-protection-server',
21+
version: '1.0.0'
22+
});
23+
24+
server.registerTool(
25+
'echo',
26+
{
27+
description: 'Echo the input back',
28+
inputSchema: { message: { type: 'string' } }
29+
},
30+
async ({ message }) => ({
31+
content: [{ type: 'text', text: `Echo: ${message}` }]
32+
})
33+
);
2134

22-
// Add a simple tool
23-
server.tool(
24-
'echo',
25-
'Echo the input back',
26-
{ message: { type: 'string' } },
27-
async ({ message }) => ({
28-
content: [{ type: 'text', text: `Echo: ${message}` }]
29-
})
30-
);
35+
return server;
36+
}
3137

3238
// === VULNERABLE EXPRESS APP ===
3339
// This intentionally does NOT use createMcpExpressApp() or localhostHostValidation()
@@ -37,6 +43,7 @@ app.use(express.json());
3743

3844
app.post('/mcp', async (req, res) => {
3945
try {
46+
const server = createMcpServer();
4047
// Stateless: no session ID
4148
const transport = new StreamableHTTPServerTransport({
4249
sessionIdGenerator: undefined

src/scenarios/client/auth/helpers/createServer.ts

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,43 +41,49 @@ export function createServer(
4141
tokenVerifier,
4242
prmResourceOverride
4343
} = options;
44-
const server = new Server(
45-
{
46-
name: 'auth-prm-pathbased-server',
47-
version: '1.0.0'
48-
},
49-
{
50-
capabilities: {
51-
tools: {}
44+
// Factory: create a fresh Server per request to avoid "Already connected" errors
45+
// after the v1.26.0 security fix (GHSA-345p-7cg4-v4c7)
46+
function createMcpServer() {
47+
const server = new Server(
48+
{
49+
name: 'auth-prm-pathbased-server',
50+
version: '1.0.0'
51+
},
52+
{
53+
capabilities: {
54+
tools: {}
55+
}
5256
}
53-
}
54-
);
57+
);
58+
59+
server.setRequestHandler(ListToolsRequestSchema, async () => {
60+
return {
61+
tools: [
62+
{
63+
name: 'test-tool',
64+
inputSchema: { type: 'object' }
65+
}
66+
]
67+
};
68+
});
5569

56-
server.setRequestHandler(ListToolsRequestSchema, async () => {
57-
return {
58-
tools: [
59-
{
60-
name: 'test-tool',
61-
inputSchema: { type: 'object' }
70+
server.setRequestHandler(
71+
CallToolRequestSchema,
72+
async (request): Promise<CallToolResult> => {
73+
if (request.params.name === 'test-tool') {
74+
return {
75+
content: [{ type: 'text', text: 'test' }]
76+
};
6277
}
63-
]
64-
};
65-
});
66-
67-
server.setRequestHandler(
68-
CallToolRequestSchema,
69-
async (request): Promise<CallToolResult> => {
70-
if (request.params.name === 'test-tool') {
71-
return {
72-
content: [{ type: 'text', text: 'test' }]
73-
};
78+
throw new McpError(
79+
ErrorCode.InvalidParams,
80+
`Tool ${request.params.name} not found`
81+
);
7482
}
75-
throw new McpError(
76-
ErrorCode.InvalidParams,
77-
`Tool ${request.params.name} not found`
78-
);
79-
}
80-
);
83+
);
84+
85+
return server;
86+
}
8187

8288
const app = express();
8389
app.use(express.json());
@@ -151,6 +157,7 @@ export function createServer(
151157

152158
authMiddleware(req, res, async (err?: any) => {
153159
if (err) return next(err);
160+
const server = createMcpServer();
154161
const transport = new StreamableHTTPServerTransport({
155162
sessionIdGenerator: undefined
156163
});

0 commit comments

Comments
 (0)