agents 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +24 -19
  2. package/dist/{agent-tool-types-BNUGGBzQ.d.ts → agent-tool-types-Btk9ETS-.d.ts} +997 -356
  3. package/dist/agent-tool-types.d.ts +1 -1
  4. package/dist/{agent-tools-BFbzVLFc.d.ts → agent-tools-UuScsJg3.d.ts} +2 -2
  5. package/dist/agent-tools.d.ts +1 -1
  6. package/dist/browser/ai.js +1 -1
  7. package/dist/browser/index.js +1 -1
  8. package/dist/chat/index.d.ts +2 -2
  9. package/dist/chat-sdk/index.d.ts +1 -1
  10. package/dist/client-invoker-BNSZxAkv.d.ts +20 -0
  11. package/dist/client-invoker-VNZ7X0nn.js +57 -0
  12. package/dist/client-invoker-VNZ7X0nn.js.map +1 -0
  13. package/dist/{client-CcjiFpTf.js → client-zqKcsyFa.js} +434 -168
  14. package/dist/client-zqKcsyFa.js.map +1 -0
  15. package/dist/client.d.ts +1 -1
  16. package/dist/{connector-CdldGF3h.js → connector-KEJnl6e5.js} +2 -2
  17. package/dist/connector-KEJnl6e5.js.map +1 -0
  18. package/dist/{do-oauth-client-provider-D4ZwyBDu.d.ts → do-oauth-client-provider-VTZj2VtM.d.ts} +23 -11
  19. package/dist/experimental/webmcp.js +1 -1
  20. package/dist/handler-stateless-8hQN_kC3.js +367 -0
  21. package/dist/handler-stateless-8hQN_kC3.js.map +1 -0
  22. package/dist/handler-stateless-C_bo-Ytq.d.ts +107 -0
  23. package/dist/index.d.ts +12 -12
  24. package/dist/index.js +3 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp/client.d.ts +22 -18
  27. package/dist/mcp/client.js +1 -1
  28. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  29. package/dist/mcp/do-oauth-client-provider.js +25 -12
  30. package/dist/mcp/do-oauth-client-provider.js.map +1 -1
  31. package/dist/mcp/index.d.ts +48 -34
  32. package/dist/mcp/index.js +84 -79
  33. package/dist/mcp/index.js.map +1 -1
  34. package/dist/mcp/server.d.ts +17 -0
  35. package/dist/mcp/server.js +2 -0
  36. package/dist/mcp/x402.d.ts +21 -9
  37. package/dist/mcp/x402.js +8 -7
  38. package/dist/mcp/x402.js.map +1 -1
  39. package/dist/react.d.ts +1 -1
  40. package/dist/serializable.d.ts +1 -1
  41. package/dist/sub-routing.d.ts +6 -6
  42. package/dist/workflows.d.ts +1 -1
  43. package/docs/human-in-the-loop.md +63 -82
  44. package/docs/mcp-client.md +31 -7
  45. package/docs/mcp-servers.md +125 -88
  46. package/docs/securing-mcp-servers.md +9 -6
  47. package/package.json +28 -7
  48. package/dist/client-CcjiFpTf.js.map +0 -1
  49. package/dist/connector-CdldGF3h.js.map +0 -1
@@ -4,23 +4,27 @@ This guide covers the different ways to create MCP servers with the Agents SDK a
4
4
 
5
5
  ## Choosing an Approach
6
6
 
7
- | Approach | Stateful? | Requires Durable Objects? | Best for |
8
- | ---------------------------------------------- | --------- | ------------------------- | ---------------------------------------------- |
9
- | `createMcpHandler()` | No | No | Stateless tools, simplest setup |
10
- | `McpAgent` | Yes | Yes | Stateful tools, per-session state, elicitation |
11
- | Raw `WebStandardStreamableHTTPServerTransport` | No | No | Full control, no SDK dependency |
7
+ | Approach | Stateful? | Requires Durable Objects? | Best for |
8
+ | ---------------------------------------------- | --------- | ------------------------- | ------------------------------------------------- |
9
+ | `createMcpHandler()` | No | No | New servers and the draft MCP protocol |
10
+ | `McpAgent` (deprecated legacy path) | Yes | Yes | Existing stateful SDK v1 deployments |
11
+ | Raw `WebStandardStreamableHTTPServerTransport` | No | No | Low-level control without the Agents HTTP wrapper |
12
12
 
13
- - **`createMcpHandler()`** is the fastest way to get a stateless MCP server running. Use it when your tools do not need per-session state.
14
- - **`McpAgent`** gives you a Durable Object per session with built-in state management, elicitation support, and both SSE and Streamable HTTP transports.
15
- - **Raw transport** gives you full control if you want to use the `@modelcontextprotocol/sdk` directly without the Agents SDK helpers.
13
+ - **`createMcpHandler()`** is the current server-development path. It serves draft MCP `2026-07-28` and supports stateless published 2025 clients by default.
14
+ - **`McpAgent`** is a retained, feature-frozen SDK v1 path for existing stateful deployments. New servers should use `createMcpHandler()`.
15
+ - **Raw transport** gives you low-level control if the standard handler lifecycle is not suitable.
16
16
 
17
17
  ## Stateless MCP Server with `createMcpHandler()`
18
18
 
19
- The simplest way to create an MCP server. No Durable Objects or bindings required:
19
+ The simplest way to create an MCP server. Install the exact SDK v2 server peer, then use the isolated server entry point so legacy Agents transports and MCP clients stay out of your Worker bundle:
20
+
21
+ ```sh
22
+ pnpm add agents @modelcontextprotocol/server@2.0.0-beta.5 zod
23
+ ```
20
24
 
21
25
  ```typescript
22
- import { createMcpHandler } from "agents/mcp";
23
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
26
+ import { McpServer } from "@modelcontextprotocol/server";
27
+ import { createMcpHandler } from "agents/mcp/server";
24
28
  import { z } from "zod";
25
29
 
26
30
  function createServer() {
@@ -44,45 +48,77 @@ function createServer() {
44
48
  }
45
49
 
46
50
  export default {
47
- fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
48
- const server = createServer();
49
- return createMcpHandler(server)(request, env, ctx);
51
+ fetch(request, env, ctx) {
52
+ return createMcpHandler(createServer)(request, env, ctx);
50
53
  }
51
- };
54
+ } satisfies ExportedHandler;
52
55
  ```
53
56
 
54
- > **Important:** Create a new `McpServer` instance per request. The MCP SDK does not allow connecting an already-connected server to a new transport.
57
+ `createMcpHandler` requires a factory so concurrent Worker requests receive isolated server instances. A function input is always treated as an SDK v2 factory.
55
58
 
56
- ### `createMcpHandler` Options
59
+ ### `createMcpHandler` options
57
60
 
58
61
  ```typescript
59
- createMcpHandler(server, {
60
- route: "/mcp", // path to handle (default: "/mcp")
61
- enableJsonResponse: true, // use JSON responses instead of SSE streaming
62
- sessionIdGenerator: () => crypto.randomUUID(),
63
- corsOptions: { ... }, // CORS configuration
64
- authContext: { props: {} }, // manually set auth context
65
- transport: workerTransport // provide your own WorkerTransport instance
62
+ createMcpHandler(() => createServer(), {
63
+ route: "/mcp", // exact path to handle (default: "/mcp")
64
+ corsOptions: {
65
+ origin: "https://app.example.com"
66
+ },
67
+ allowedHostnames: ["mcp.example.com"], // custom-domain Host policy
68
+ allowedOriginHostnames: ["app.example.com"], // browser Origin policy
69
+ authContext: { props: {} }, // optional application props override
70
+ legacy: "stateless", // upstream default; use "reject" for Stateless-only
71
+ responseMode: "auto" // upstream SDK response shaping
66
72
  });
67
73
  ```
68
74
 
75
+ All upstream SDK v2 handler options pass through. Use `createLegacyMcpHandler` for WorkerTransport, storage, session, and event-store options.
76
+
77
+ The handler validates every present `Origin` header before serving the request. It rejects malformed, opaque, and non-HTTP origins. Requests without `Origin` remain valid for non-browser MCP clients.
78
+
79
+ Its default allowlist includes localhost-class origins and the endpoint's `workers.dev` hostname. A concrete `corsOptions.origin` adds that hostname automatically. The handler also applies matching Host checks to localhost and `workers.dev` endpoints. For a custom domain with wildcard CORS, configure `allowedHostnames` and `allowedOriginHostnames` explicitly. Values are hostnames without a scheme or port, and matching ignores the Origin's scheme and port.
80
+
81
+ Pass `allowedOriginHostnames: "*"` only when equivalent Origin validation runs in trusted middleware before the handler. This explicitly disables the handler's Origin check, including malformed and opaque Origin rejection. MCP HTTP servers are required to validate browser Origins, so do not use this as an unauthenticated public-server shortcut.
82
+
83
+ ### 2025 compatibility and elicitation
84
+
85
+ The default `legacy: "stateless"` lane supports ordinary 2025 tools, resources, and prompts. It has no session return path for push-style server-to-client requests; attempts to sample, elicit, or list roots fail immediately with guidance to use a sessionful transport.
86
+
87
+ Applications that must serve both generations can route before `createMcpHandler`: send Stateless requests to a strict handler and Legacy requests to an existing session-addressed Agent or transport. See [`examples/mcp-elicitation-mrtr`](../../examples/mcp-elicitation-mrtr/) for Stateless Elicitation and [`examples/mcp-elicitation`](../../examples/mcp-elicitation/) for Legacy Elicitation.
88
+
89
+ For an explicit Legacy handler, use the retained Legacy API:
90
+
91
+ ```typescript
92
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
93
+ import { createLegacyMcpHandler } from "agents/mcp";
94
+
95
+ const server = new McpServer({ name: "legacy", version: "1.0.0" });
96
+ export default createLegacyMcpHandler(server);
97
+ ```
98
+
99
+ Passing an SDK v1 server directly to `createMcpHandler` still forwards to this API for compatibility, but that overload is deprecated, emits a migration warning, and is removed in the next major release. `createLegacyMcpHandler` and `WorkerTransport` themselves are not deprecated.
100
+
69
101
  ### Accessing Authenticated User Context
70
102
 
71
- When your MCP server is wrapped with `OAuthProvider` from `@cloudflare/workers-oauth-provider`, authenticated user information is available inside tools via `getMcpAuthContext()`:
103
+ When your MCP server is wrapped with `OAuthProvider` from `@cloudflare/workers-oauth-provider`, provider-issued tokens are available through standard SDK v2 `AuthInfo`. The existing `getMcpAuthContext()` application-props helper remains supported:
72
104
 
73
105
  ```typescript
74
- import { createMcpHandler, getMcpAuthContext } from "agents/mcp";
106
+ import { createMcpHandler, getMcpAuthContext } from "agents/mcp/server";
75
107
 
76
108
  server.registerTool(
77
109
  "whoami",
78
110
  { description: "Returns the authenticated user" },
79
- async () => {
111
+ async (context) => {
80
112
  const auth = getMcpAuthContext();
81
113
  return {
82
114
  content: [
83
115
  {
84
116
  type: "text",
85
- text: auth ? JSON.stringify(auth.props) : "Not authenticated"
117
+ text: JSON.stringify({
118
+ clientId: context.http?.authInfo?.clientId,
119
+ scopes: context.http?.authInfo?.scopes,
120
+ props: auth?.props
121
+ })
86
122
  }
87
123
  ]
88
124
  };
@@ -90,11 +126,11 @@ server.registerTool(
90
126
  );
91
127
  ```
92
128
 
93
- The `OAuthProvider` sets `ctx.props` on the execution context, which `createMcpHandler` automatically picks up and makes available via `getMcpAuthContext()`.
129
+ Do not log or return `context.http.authInfo.token`. External-token resolvers continue providing `getMcpAuthContext().props` but do not synthesize incomplete standard metadata.
94
130
 
95
- ## Stateful MCP Server with `McpAgent`
131
+ ## Stateful MCP Server with `McpAgent` (legacy)
96
132
 
97
- `McpAgent` gives each client session its own Durable Object with persistent state. Use this when your tools need to track per-session data.
133
+ `McpAgent` gives each client session its own Durable Object with persistent state. It remains available for existing SDK v1 deployments but is deprecated and feature-frozen; new servers should use the stateless handler or explicitly compose a separate legacy route where a session is required.
98
134
 
99
135
  ### Writing TinyMCP
100
136
 
@@ -428,76 +464,77 @@ The `jurisdiction` option accepts any value supported by [Cloudflare's Durable O
428
464
 
429
465
  ## Elicitation (Human-in-the-Loop)
430
466
 
431
- MCP servers can request additional input from the user during a tool call using elicitation. This is useful for confirmation dialogs, requesting amounts, or any interactive tool flow.
467
+ MCP servers can request additional input during a tool call. The implementation differs by protocol generation.
468
+
469
+ ### Stateless Elicitation
432
470
 
433
- Elicitation is supported via `McpAgent` (which manages the request/response lifecycle through Durable Object storage) or via `WorkerTransport` (for stateful non-McpAgent setups).
471
+ For Stateless Elicitation, return `inputRequired(...)`. The client gathers the input and retries the request with SDK-managed `requestState` and `inputResponses`; the Worker does not suspend while a person responds.
434
472
 
435
473
  ```typescript
436
- import { McpAgent } from "agents/mcp";
437
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
474
+ import {
475
+ McpServer,
476
+ acceptedContent,
477
+ inputRequired
478
+ } from "@modelcontextprotocol/server";
479
+ import { createMcpHandler } from "agents/mcp/server";
438
480
  import { z } from "zod";
439
481
 
440
- export class MyMCP extends McpAgent<Env, { counter: number }> {
441
- server = new McpServer({ name: "Elicitation Demo", version: "1.0.0" });
442
-
443
- initialState = { counter: 0 };
444
-
445
- async init() {
446
- this.server.registerTool(
447
- "increase-counter",
448
- {
449
- description: "Increase the counter",
450
- inputSchema: {
451
- confirm: z.boolean().describe("Do you want to increase the counter?")
452
- }
453
- },
454
- async ({ confirm }, extra) => {
455
- if (!confirm) {
456
- return { content: [{ type: "text", text: "Cancelled." }] };
457
- }
458
-
459
- const result = await this.server.server.elicitInput(
460
- {
461
- message: "By how much?",
462
- requestedSchema: {
463
- type: "object",
464
- properties: {
465
- amount: { type: "number", title: "Amount" }
466
- },
467
- required: ["amount"]
468
- }
469
- },
470
- { relatedRequestId: extra.requestId }
471
- );
472
-
473
- if (result.action !== "accept" || !result.content?.amount) {
474
- return { content: [{ type: "text", text: "Cancelled." }] };
475
- }
476
-
477
- const amount = Number(result.content.amount);
478
- this.setState({ counter: this.state.counter + amount });
479
-
480
- return {
481
- content: [
482
- {
483
- type: "text",
484
- text: `Counter increased by ${amount}, now ${this.state.counter}`
485
- }
486
- ]
487
- };
482
+ function createServer() {
483
+ const server = new McpServer({
484
+ name: "Stateless Elicitation Demo",
485
+ version: "1.0.0"
486
+ });
487
+ server.registerTool(
488
+ "ask-name",
489
+ { inputSchema: z.object({}) },
490
+ async (_args, context) => {
491
+ const answer = acceptedContent(
492
+ context.mcpReq.inputResponses,
493
+ "name",
494
+ z.object({ name: z.string() })
495
+ );
496
+ if (!answer) {
497
+ return inputRequired({
498
+ inputRequests: {
499
+ name: inputRequired.elicit({
500
+ message: "What is your name?",
501
+ requestedSchema: {
502
+ type: "object",
503
+ properties: { name: { type: "string" } },
504
+ required: ["name"]
505
+ }
506
+ })
507
+ }
508
+ });
488
509
  }
489
- );
490
- }
510
+ return { content: [{ type: "text", text: `Hello ${answer.name}` }] };
511
+ }
512
+ );
513
+ return server;
491
514
  }
492
515
 
493
- export default MyMCP.serve("/mcp");
516
+ export default {
517
+ fetch(request, env, ctx) {
518
+ return createMcpHandler(createServer, { legacy: "reject" })(
519
+ request,
520
+ env,
521
+ ctx
522
+ );
523
+ }
524
+ } satisfies ExportedHandler;
494
525
  ```
495
526
 
496
- See the [`examples/mcp-elicitation`](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) example for a full working demo.
527
+ See [`examples/mcp-elicitation-mrtr`](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) for a two-round Stateless Elicitation example.
528
+
529
+ ### Legacy Elicitation
530
+
531
+ Existing Legacy deployments send pushed `elicitation/create` requests over a session-addressed response stream. Use `McpAgent` or `createLegacyMcpHandler` with `WorkerTransport` when that behavior must be retained.
532
+
533
+ See [`examples/mcp-elicitation`](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) for form- and URL-mode Legacy Elicitation with Durable Object state and SSE replay.
497
534
 
498
535
  ## WorkerTransport
499
536
 
500
- `WorkerTransport` is a server-side transport for running MCP servers in stateless Workers while optionally persisting session state. It is used internally by `createMcpHandler()` but can also be used directly for advanced scenarios like stateful sessions without `McpAgent`.
537
+ `WorkerTransport` is the retained Agents transport for stateful Legacy deployments. Use it with `createLegacyMcpHandler` for persistent sessions, storage, event replay, and other explicit legacy configurations. The Stateless handler's Legacy compatibility lane uses the SDK v2 web-standard transport instead and does not import `WorkerTransport`.
501
538
 
502
539
  ```typescript
503
540
  import { WorkerTransport, type TransportState } from "agents/mcp";
@@ -6,14 +6,15 @@ Cloudflare's `workers-oauth-provider` lets you secure your MCP Server (or any ap
6
6
 
7
7
  ```typescript
8
8
  import { OAuthProvider, OAuthError } from "@cloudflare/workers-oauth-provider";
9
- import { createMcpHandler } from "agents/mcp";
9
+ import { McpServer } from "@modelcontextprotocol/server";
10
+ import { createMcpHandler } from "agents/mcp/server";
10
11
 
11
12
  // A Worker that exposes an MCP server
12
- const apiHandler = {
13
- async fetch(request: Request, env: unknown, ctx: ExecutionContext) {
14
- return createMcpHandler(server)(request, env, ctx);
15
- }
16
- };
13
+ function createServer() {
14
+ return new McpServer({ name: "authenticated-server", version: "1.0.0" });
15
+ }
16
+
17
+ const apiHandler = createMcpHandler(createServer);
17
18
 
18
19
  // Wrap with OAuth protection
19
20
  export default new OAuthProvider({
@@ -28,6 +29,8 @@ export default new OAuthProvider({
28
29
  });
29
30
  ```
30
31
 
32
+ For provider-issued tokens, SDK v2 tool callbacks receive standard metadata at `context.http.authInfo`, while `getMcpAuthContext().props` retains the existing application-props shape. Treat `authInfo.token` and `authInfo.extra.props` as sensitive and do not log or return them.
33
+
31
34
  However, most MCP servers aren't just servers, they can actually be OAuth clients too. Your MCP server might sit between Claude Desktop and a third-party API like GitHub or Google. To Claude, you're a server. To GitHub, you're a client. This allows your users to authenticate and use their GitHub credentials to access your MCP server. We call this a proxy server.
32
35
 
33
36
  There are a few security footguns to securely building a proxy server. The rest of this document aims to outline best practises to securing an MCP server.
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "durable objects"
10
10
  ],
11
11
  "type": "module",
12
- "version": "0.19.0",
12
+ "version": "0.20.0",
13
13
  "license": "MIT",
14
14
  "repository": {
15
15
  "directory": "packages/agents",
@@ -26,8 +26,6 @@
26
26
  "dependencies": {
27
27
  "@babel/plugin-proposal-decorators": "^8.0.2",
28
28
  "@cfworker/json-schema": "^4.1.1",
29
- "@cloudflare/codemode": "^0.5.0",
30
- "@modelcontextprotocol/sdk": "1.29.0",
31
29
  "@rolldown/plugin-babel": "^0.2.3",
32
30
  "cron-schedule": "^6.0.0",
33
31
  "esbuild": "^0.28.1",
@@ -40,7 +38,11 @@
40
38
  },
41
39
  "devDependencies": {
42
40
  "@ai-sdk/react": "^4.0.0",
43
- "@modelcontextprotocol/conformance": "0.1.16",
41
+ "@cloudflare/codemode": "^0.5.1",
42
+ "@modelcontextprotocol/client": "2.0.0-beta.5",
43
+ "@modelcontextprotocol/conformance-v2": "npm:@modelcontextprotocol/conformance@0.2.0-alpha.10",
44
+ "@modelcontextprotocol/sdk": "1.29.0",
45
+ "@modelcontextprotocol/server": "2.0.0-beta.5",
44
46
  "@tanstack/ai": "0.38.0",
45
47
  "@types/react": "^19.2.17",
46
48
  "@types/yargs": "^17.0.35",
@@ -57,6 +59,10 @@
57
59
  },
58
60
  "peerDependencies": {
59
61
  "@ai-sdk/react": "^3.0.0 || ^4.0.0",
62
+ "@cloudflare/codemode": ">=0.5.0",
63
+ "@modelcontextprotocol/client": "2.0.0-beta.5",
64
+ "@modelcontextprotocol/sdk": "1.29.0",
65
+ "@modelcontextprotocol/server": "2.0.0-beta.5",
60
66
  "@tanstack/ai": ">=0.10.2 <1.0.0",
61
67
  "@x402/core": "^2.0.0",
62
68
  "@x402/evm": "^2.0.0",
@@ -71,6 +77,9 @@
71
77
  "@ai-sdk/react": {
72
78
  "optional": true
73
79
  },
80
+ "@cloudflare/codemode": {
81
+ "optional": true
82
+ },
74
83
  "@tanstack/ai": {
75
84
  "optional": true
76
85
  },
@@ -130,6 +139,11 @@
130
139
  "import": "./dist/mcp/client.js",
131
140
  "require": "./dist/mcp/client.js"
132
141
  },
142
+ "./mcp/server": {
143
+ "types": "./dist/mcp/server.d.ts",
144
+ "import": "./dist/mcp/server.js",
145
+ "require": "./dist/mcp/server.js"
146
+ },
133
147
  "./mcp/do-oauth-client-provider": {
134
148
  "types": "./dist/mcp/do-oauth-client-provider.d.ts",
135
149
  "import": "./dist/mcp/do-oauth-client-provider.js",
@@ -293,9 +307,16 @@
293
307
  "test:webmcp": "vitest --project webmcp",
294
308
  "test:x402": "vitest --project x402",
295
309
  "test:e2e": "vitest --run -c src/e2e-tests/vitest.config.ts",
296
- "test:conformance": "pnpm run test:conformance:client && pnpm run test:conformance:server:mcp-agent && pnpm run test:conformance:server:handler",
297
- "test:conformance:client": "bash conformance/run.sh client --suite all",
310
+ "test:conformance": "pnpm run test:conformance:client && pnpm run test:conformance:server",
311
+ "test:conformance:client": "pnpm run test:conformance:client:stateless && pnpm run test:conformance:client:2025-11-25 && pnpm run test:conformance:client:2025-06-18 && pnpm run test:conformance:client:2025-03-26",
312
+ "test:conformance:client:stateless": "bash conformance/run.sh client-stateless",
313
+ "test:conformance:client:2025-11-25": "bash conformance/run.sh client-2025-11-25",
314
+ "test:conformance:client:2025-06-18": "bash conformance/run.sh client-2025-06-18",
315
+ "test:conformance:client:2025-03-26": "bash conformance/run.sh client-2025-03-26",
316
+ "test:conformance:server": "pnpm run test:conformance:server:handler && pnpm run test:conformance:server:handler:legacy-compat && pnpm run test:conformance:server:handler:legacy && pnpm run test:conformance:server:mcp-agent",
298
317
  "test:conformance:server:mcp-agent": "bash conformance/run.sh server-mcp-agent",
299
- "test:conformance:server:handler": "bash conformance/run.sh server-handler"
318
+ "test:conformance:server:handler": "bash conformance/run.sh server-handler",
319
+ "test:conformance:server:handler:legacy-compat": "bash conformance/run.sh server-handler-legacy-compat",
320
+ "test:conformance:server:handler:legacy": "bash conformance/run.sh server-handler-legacy"
300
321
  }
301
322
  }