Skip to content

Commit a167344

Browse files
authored
Upgrade MCP SDK to latest (#848)
* fix: examples for stateless server * changeset * handler error out on bad stuff * tests * typo * fix: expect server reuse error to throw rather than return 500 Developer misconfiguration errors (reusing a connected server across requests) should fail loudly to be caught during development, not return a 500 response that might go unnoticed.
1 parent 21a7977 commit a167344

File tree

9 files changed

+307
-153
lines changed

9 files changed

+307
-153
lines changed

.changeset/floppy-snakes-know.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agents": minor
3+
---
4+
5+
Upgrade MCP SDK to 1.26.0 to prevent cross-client response leakage. Updated examples for stateless MCP Servers create new `McpServer` instance per request instead of sharing a single instance. A guard is added in this version of the MCP SDK which will prevent connection to a Server instance that has already been connected to a transport. Developers will need to modify their code if they declare their `McpServer` instance as a global variable.

examples/mcp-server/src/index.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,32 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
import { z } from "zod";
33
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
44

5-
const server = new McpServer({
6-
name: "Hello MCP Server",
7-
version: "1.0.0"
8-
});
5+
const createServer = () => {
6+
const server = new McpServer({
7+
name: "Hello MCP Server",
8+
version: "1.0.0"
9+
});
910

10-
server.registerTool(
11-
"hello",
12-
{
13-
description: "Returns a greeting message",
14-
inputSchema: { name: z.string().optional() }
15-
},
16-
async ({ name }) => {
17-
return {
18-
content: [
19-
{
20-
text: `Hello, ${name ?? "World"}!`,
21-
type: "text"
22-
}
23-
]
24-
};
25-
}
26-
);
11+
server.registerTool(
12+
"hello",
13+
{
14+
description: "Returns a greeting message",
15+
inputSchema: { name: z.string().optional() }
16+
},
17+
async ({ name }) => {
18+
return {
19+
content: [
20+
{
21+
text: `Hello, ${name ?? "World"}!`,
22+
type: "text"
23+
}
24+
]
25+
};
26+
}
27+
);
2728

28-
const transport = new WebStandardStreamableHTTPServerTransport();
29-
server.connect(transport);
29+
return server;
30+
};
3031

3132
const corsHeaders = {
3233
"Access-Control-Allow-Origin": "*",
@@ -49,6 +50,9 @@ export default {
4950
if (request.method === "OPTIONS") {
5051
return new Response(null, { headers: corsHeaders });
5152
}
53+
const transport = new WebStandardStreamableHTTPServerTransport();
54+
const server = createServer();
55+
server.connect(transport);
5256
return withCors(await transport.handleRequest(request));
5357
}
5458
};

examples/mcp-worker-authenticated/src/index.ts

Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,76 +4,82 @@ import { z } from "zod";
44
import { OAuthProvider } from "@cloudflare/workers-oauth-provider";
55
import { AuthHandler } from "./auth-handler";
66

7-
const server = new McpServer({
8-
name: "Authenticated MCP Server",
9-
version: "1.0.0"
10-
});
7+
function createServer() {
8+
const server = new McpServer({
9+
name: "Authenticated MCP Server",
10+
version: "1.0.0"
11+
});
1112

12-
server.registerTool(
13-
"hello",
14-
{
15-
description: "Returns a greeting message",
16-
inputSchema: { name: z.string().optional() }
17-
},
18-
async ({ name }) => {
19-
const auth = getMcpAuthContext();
20-
const username = auth?.props?.username as string | undefined;
13+
server.registerTool(
14+
"hello",
15+
{
16+
description: "Returns a greeting message",
17+
inputSchema: { name: z.string().optional() }
18+
},
19+
async ({ name }) => {
20+
const auth = getMcpAuthContext();
21+
const username = auth?.props?.username as string | undefined;
2122

22-
return {
23-
content: [
24-
{
25-
text: `Hello, ${name ?? username ?? "World"}!`,
26-
type: "text"
27-
}
28-
]
29-
};
30-
}
31-
);
23+
return {
24+
content: [
25+
{
26+
text: `Hello, ${name ?? username ?? "World"}!`,
27+
type: "text"
28+
}
29+
]
30+
};
31+
}
32+
);
33+
34+
server.registerTool(
35+
"whoami",
36+
{
37+
description: "Returns information about the authenticated user"
38+
},
39+
async () => {
40+
const auth = getMcpAuthContext();
3241

33-
server.registerTool(
34-
"whoami",
35-
{
36-
description: "Returns information about the authenticated user"
37-
},
38-
async () => {
39-
const auth = getMcpAuthContext();
42+
if (!auth) {
43+
return {
44+
content: [
45+
{
46+
text: "No authentication context available",
47+
type: "text" as const
48+
}
49+
]
50+
};
51+
}
4052

41-
if (!auth) {
4253
return {
4354
content: [
4455
{
45-
text: "No authentication context available",
56+
text: JSON.stringify(
57+
{
58+
userId: auth.props?.userId,
59+
username: auth.props?.username,
60+
email: auth.props?.email
61+
},
62+
null,
63+
2
64+
),
4665
type: "text" as const
4766
}
4867
]
4968
};
5069
}
70+
);
5171

52-
return {
53-
content: [
54-
{
55-
text: JSON.stringify(
56-
{
57-
userId: auth.props?.userId,
58-
username: auth.props?.username,
59-
email: auth.props?.email
60-
},
61-
null,
62-
2
63-
),
64-
type: "text" as const
65-
}
66-
]
67-
};
68-
}
69-
);
72+
return server;
73+
}
7074

7175
/**
7276
* API Handler - handles authenticated MCP requests
7377
* This handler will receive requests that have a valid access token
7478
*/
7579
const apiHandler = {
7680
async fetch(request: Request, env: unknown, ctx: ExecutionContext) {
81+
//create the server instance every request
82+
const server = createServer();
7783
return createMcpHandler(server)(request, env, ctx);
7884
}
7985
};

examples/mcp-worker/src/index.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,37 @@ import { createMcpHandler } from "agents/mcp";
22
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
33
import { z } from "zod";
44

5-
const server = new McpServer({
6-
name: "Hello MCP Server",
7-
version: "1.0.0"
8-
});
5+
function createServer() {
6+
const server = new McpServer({
7+
name: "Hello MCP Server",
8+
version: "1.0.0"
9+
});
910

10-
server.registerTool(
11-
"hello",
12-
{
13-
description: "Returns a greeting message",
14-
inputSchema: { name: z.string().optional() }
15-
},
16-
async ({ name }) => {
17-
return {
18-
content: [
19-
{
20-
text: `Hello, ${name ?? "World"}!`,
21-
type: "text"
22-
}
23-
]
24-
};
25-
}
26-
);
11+
server.registerTool(
12+
"hello",
13+
{
14+
description: "Returns a greeting message",
15+
inputSchema: { name: z.string().optional() }
16+
},
17+
async ({ name }) => {
18+
return {
19+
content: [
20+
{
21+
text: `Hello, ${name ?? "World"}!`,
22+
type: "text"
23+
}
24+
]
25+
};
26+
}
27+
);
28+
29+
return server;
30+
}
2731

2832
export default {
2933
fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
30-
const handler = createMcpHandler(server);
31-
return handler(request, env, ctx);
34+
//create the server instance every request
35+
const server = createServer();
36+
return createMcpHandler(server)(request, env, ctx);
3237
}
3338
};

0 commit comments

Comments
 (0)