Skip to content

feat(mcp): add SDK v2 client and stateless server support - #1557

Merged
mattzcarey merged 21 commits into
cloudflare:mainfrom
mattzcarey:chore/mcp-sdk-v2-upgrade
Jul 27, 2026
Merged

feat(mcp): add SDK v2 client and stateless server support#1557
mattzcarey merged 21 commits into
cloudflare:mainfrom
mattzcarey:chore/mcp-sdk-v2-upgrade

Conversation

@mattzcarey

@mattzcarey mattzcarey commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Upgrade the Agents MCP stack to the split MCP SDK v2 packages. New client and server paths support MCP 2026-07-28, while temporary legacy lanes let existing sessionful deployments migrate without an abrupt cutover.

import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";

function createServer() {
  return new McpServer({ name: "example", version: "1.0.0" });
}

export default {
  fetch(request, env, ctx) {
    return createMcpHandler(createServer)(request, env, ctx);
  }
} satisfies ExportedHandler;

stateless server

  • adds the isolated agents/mcp/server entry for the Agents Worker wrapper;
  • uses exact-pinned @modelcontextprotocol/server@2.0.0-beta.5;
  • keeps McpServer owned by the upstream SDK rather than re-exporting it;
  • excludes McpAgent, WorkerTransport, MCP client transports, PartyServer, and SDK v1 from the stateless bundle;
  • preserves legacy compatibility by default, with legacy: "reject" for a stateless-only endpoint;
  • serves legacy compatibility through the SDK v2 web-standard transport rather than WorkerTransport;
  • preserves reverse-request fail-fast behavior, active-request cleanup, and 25-second SSE keepalives;
  • validates browser Origins by default and supports allowedOriginHostnames: "*" when trusted upstream middleware performs validation;
  • preserves callable Worker routing, CORS, and auth context, and exposes the lower-level fetch(request, options?) method plus typed notify methods while keeping upstream lifecycle and event-bus internals private.

The compatibility agents/mcp entry remains available for migration. Its implementation is now separated into explicit compatibility and legacy modules. createLegacyMcpHandler and WorkerTransport can temporarily retain sessionful SDK v1 behavior while it is replaced. McpAgent is deprecated and feature-frozen.

Client

  • uses exact-pinned @modelcontextprotocol/client@2.0.0-beta.5;
  • probes with server/discover and falls back to the legacy initialize handshake on the same connection;
  • supports stateless Elicitation through SDK-owned multi-round-trip requests (MRTR);
  • keeps callTool, getPrompt, and readResource pending while input is collected;
  • exports elicitation client types from agents/mcp/client;
  • preserves legacy pushed elicitation, Streamable HTTP, SSE, RPC, OAuth, and recovery, and temporarily honors the deprecated explicit result-schema callTool overload;
  • persists stateless discovery state in the beta.5 prior shape for safe HTTP restoration.

OAuth and integrations

  • preserves discovery-triggered authorization and issuer-bound OAuth state;
  • rediscovers changed authorization servers without reusing credentials from the prior issuer;
  • retains the explicit skipIssuerMetadataValidation compatibility option for trusted legacy metadata;
  • keeps x402 compatible with both MCP client generations;
  • uses an SDK-neutral structural boundary in the Code Mode MCP connector;
  • makes @cloudflare/codemode an optional peer, with direct dependencies added to every workspace consumer.

Elicitation examples

  • examples/mcp-elicitation-mrtr: stateless Elicitation, including a two-round tool flow;
  • examples/mcp-elicitation: legacy Elicitation, retaining Durable Object state, WorkerTransport, pushed form/URL requests, and SSE replay.

Structure and coverage

  • adds a full in-process lifecycle test for discovery/initialization, catalogs, tool calls, prompts, resources, and client close through stateless and legacy compatibility paths;
  • adds a bundle graph regression test for agents/mcp/server;
  • documents package boundaries, lifecycles, tradeoffs, and the conformance matrix in design/mcp.md;
  • keeps a workerd adaptation of the upstream SDK v2 conformance fixture with pinned provenance;
  • uses alpha.10’s final-wire assertions, removing the obsolete beta.5 mismatch baseline;
  • audits all changed paths, removes nine non-gating, stale, or redundant files, and reduces custom conformance orchestration by 165 lines.

Deprecations

  • McpAgent is deprecated and feature-frozen; migrate to an SDK v2 factory with createMcpHandler.
  • Passing an SDK v1 server to createMcpHandler is deprecated for removal in the next major version; move the server to an SDK v2 factory and reserve createLegacyMcpHandler for temporary sessionful migration lanes.
  • The explicit result-schema overloads of MCPClientManager.callTool and withX402Client(...).callTool are deprecated; pass request options instead.

Lifecycle boundary

In-flight stateless Elicitation remains memory-only. Durable Object hibernation, isolate restart, transport loss, or connection reconstruction rejects the active operation. This PR does not persist requestState or add a manual continuation API.

Verification

  • rebased onto main at 6c01c8d8 (agents@0.19.0), with no merge commits or base divergence
  • pnpm install --frozen-lockfile
  • pnpm run ci — all 33 build/test targets, package exports, formatting, lint, and all 118 TypeScript projects
  • pnpm --filter agents run test:conformance
  • official referee: @modelcontextprotocol/conformance@0.2.0-alpha.10
  • stateless client: 32 scenarios — 28 clean / 4 documented expected failures
  • legacy client: 18 scenarios — 16 clean / 2 SHOULD-level failures; earlier lanes 5/5 and 2/2 clean
  • stateless server: 40/40 clean
  • legacy compatibility: 26 clean / 6 documented session/reverse-request failures
  • legacy handler and McpAgent: 29 clean / 3 documented failures each
  • stateless Worker dry-run: 616 KiB / 120 KiB gzip, versus 2,839 KiB / 527 KiB through the compatibility barrel
  • migration documentation and the July 27, 2026 v0.20.0 changelog: [Agents] Add MCP SDK v2 migration guide cloudflare-docs#32175

Fixes #1848.

@changeset-bot

changeset-bot Bot commented May 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4995470

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
agents Minor
@cloudflare/codemode Patch
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mattzcarey mattzcarey changed the title chore(mcp): migrate agents to MCP SDK v2 packages feat(mcp): add SDK v2 createMcpHandler with v1 compatibility Jul 7, 2026
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch from bbb79a9 to 384c432 Compare July 7, 2026 12:51
@pkg-pr-new

pkg-pr-new Bot commented Jul 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1557

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1557

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1557

create-think

npm i https://pkg.pr.new/create-think@1557

hono-agents

npm i https://pkg.pr.new/hono-agents@1557

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1557

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1557

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1557

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1557

commit: 4995470

@mattzcarey
mattzcarey marked this pull request as ready for review July 7, 2026 13:03

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@mattzcarey mattzcarey changed the title feat(mcp): add SDK v2 createMcpHandler with v1 compatibility feat(mcp): add stateless SDK v2 handler with v1 compatibility Jul 14, 2026
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch from 42ce495 to 8059e94 Compare July 14, 2026 10:57
@mattzcarey mattzcarey changed the title feat(mcp): add stateless SDK v2 handler with v1 compatibility feat(mcp): add SDK v2 client and stateless server support Jul 14, 2026
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch 2 times, most recently from c86cbec to 80a8fbd Compare July 14, 2026 18:15
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch 2 times, most recently from 6be2cac to c38957c Compare July 22, 2026 15:19
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch 2 times, most recently from 4d6b303 to 483a8f4 Compare July 27, 2026 14:16
The SDK v2 handler intentionally leaves deployment validation to its host, but the Agents Worker wrapper previously delegated present Origin headers without a guard. Validate them against localhost-class hostnames by default, expose an explicit browser-host allowlist, and keep Origin-less non-browser clients working.

Also allow the modern Mcp-Method and Mcp-Name headers in default CORS preflights and remove the now-clean v2 conformance baselines.
- delegate scenario execution to the official conformance CLI
- remove non-gating extension lanes, empty baselines, and redundant tests
- keep bounded concurrency and truthful process/warning handling
- create a fresh legacy chess server for each request
Remove the two stale modern-protocol exceptions fixed by alpha.10, leaving the stateless server lane 40/40 clean and the modern client lane with four documented expected failures. Also drop the temporary MCP release-age exclusions.
Wrap callable Agents handlers inside Worker object fetch exports so Wrangler does not treat them as WorkerEntrypoint classes. Carry multi-round elicitation data in signed requestState because each retry includes only the current round's input responses.
Match the existing Agents and Sentry migration pattern: keep the Worker object export and pass the SDK v2 factory to the callable handler. The .fetch method remains available for request-options composition but is not required for Worker dispatch.
Expose only callable/fetch request handling and typed change notifications. Keep upstream close and bus internals private, reject the bus option, and remove now-unreachable close-race machinery from the legacy compatibility adapter.
Keep Worker dispatch on the callable signature and expose only the lower-level fetch(request, options?) method from the SDK. Remove the redundant fetch(request, env, ctx) overload.
Direct deprecated SDK v1 handler and McpAgent users to SDK v2 factories first, reserving legacy handlers for temporary sessionful migration lanes. Document the full v0.20.0 deprecation set and correct the x402 result-schema guidance.
@mattzcarey
mattzcarey force-pushed the chore/mcp-sdk-v2-upgrade branch from 6e39342 to 60d720f Compare July 27, 2026 16:56
Use the package-defined start scripts and describe the McpAgent example as a deprecated migration reference rather than a new-server path.
@mattzcarey
mattzcarey merged commit 447013d into cloudflare:main Jul 27, 2026
14 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP v2 typescript sdk

1 participant