You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MCP spec 2026-07-28 shipped alongside the stable v2 TypeScript SDK (@modelcontextprotocol/server@2.0.0, @modelcontextprotocol/client@2.0.0); the monolithic @modelcontextprotocol/sdk is retired at v1. This tracks adopting it across our MCP surface. Sibling work in buildinternet/sunny: #773, Phase-1 PR #774.
The headline breaking change costs us little. Protocol-level sessions are gone and MCP is stateless — each request carries its protocol version and client capabilities in reserved _meta keys. workers/mcp binds no Durable Objects, so the session state its current transport holds is already per-isolate and best-effort. Nothing durable depends on it. We use none of the deprecated features (Roots, Sampling, Logging, HTTP+SSE transport).
Our migration differs from sunny's in one structural way. Sunny hand-wires the SDK's own transport, so its PR is a direct SDK swap. We serve MCP through agents/mcp (the Cloudflare Agents SDK), which already did this migration upstream:
agents@0.20.1 moves the MCP SDK from a hard dependency to peers on both v1 @modelcontextprotocol/sdk@1.30.0 and v2 @modelcontextprotocol/server@2.0.0 + /client@2.0.0.
agents/mcp's createMcpHandler is now the stateless v2 handler taking an McpServerFactory. The sessionful SDK-v1 handler we use today (agents@0.17.3) is renamed createLegacyMcpHandler.
So Phase 1 is an agents bump plus a call-site change, not a transport rewrite. It also means the legacy leg sunny had to hand-wire (a second WebStandardStreamableHTTPServerTransport with enableJsonResponse: true, to stop 2025-era clients silently receiving SSE) is a single responseMode: "json" option for us.
Already compatible, verified against the v2 type surface:ResourceTemplate + its complete maps (slug-completion.ts), completable() on prompt args, tool annotations, and _meta — which is what carries the MCP Apps UI ui.resourceUri and the ui.cspresourceDomains allowlist (#1230). resultType is a wire-only discriminator, stripped from the handler-facing types, so tool callbacks are unaffected.
Mechanical churn: ~19 raw-shape inputSchema: { … } sites across mcp-agent.ts, follows-tools.ts, whats-changed-tool.ts become z.object(…), and withPagination() returns an object schema. Raw shapes still work via a deprecated overload, so this is de-risking rather than a blocker.
Side benefit: the zod: ~4.3.6 pin in workers/mcp exists only because SDK v1 nested its own copy (#1367). v2 declares zod ^4.2.0, so the pin should be droppable.
Plan
Phase 1 — SDK v2 migration. ✅ Shipped in feat(mcp): adopt MCP 2026-07-28 via the v2 TypeScript SDK #2190 (merged 2026-07-29). Bump agents ^0.17.3 → ^0.20.1, drop the direct @modelcontextprotocol/sdk dep, add @modelcontextprotocol/server@^2.0.0 (+ /client for tests). Switch workers/mcp/src/index.ts to the stateless createMcpHandler(factory) with route, responseMode: "json", and explicit allowedOriginHostnames (the 0.20 wrapper does its own Host/Origin validation and custom domains are not covered by default). Set ttlMs: 3_600_000 / cacheScope: "private" cache hints on tools/list, prompts/list, resources/templates/list — static per deploy but auth-gated. Wrap tool/prompt schemas in z.object. Migrate tests/mcp-test-helpers.ts and the five suites on it to the v2 client; add modern-envelope (_meta + Mcp-Method/Mcp-Name) and legacy-initialize tests driving the real fetch handler. Refresh the carved-out workers/mcp/bun.lock. Update docs/architecture/mcp.md and workers/mcp/server.json.
Phase 2 — auth: better-auth 1.7 + CIMD. DCR is deprecated in favor of Client ID Metadata Documents. better-auth implemented CIMD in better-auth/better-auth#9159, shipping in 1.7.0 — so this is gated on our own 1.6.23 → 1.7 upgrade, not on upstream. Bigger lift here than in sunny: we run api-key, passkey, stripe, oauth-provider, and organization plugins across workers/api and web. DCR stays spec-valid through the deprecation window. Own issue.
Phase 3 — workers/mcp/ui + hardening.@modelcontextprotocol/ext-apps ^1.7.3 → 1.7.5 and its own SDK copy; regenerate the committed release-feed bundle (separate carved-out build with its own lockfile). The server-side _meta contract is unchanged, so the UI keeps working untouched during Phase 1. Consider Mcp-Method-based rate-limit rules now that the method is a header and needs no body parsing.
Not in scope
subscriptions/listen — that is #346, a real feature request, not a migration item. No feature flag: this is a dependency migration with no runtime toggle worth the permanent registry entry.
MCP spec
2026-07-28shipped alongside the stable v2 TypeScript SDK (@modelcontextprotocol/server@2.0.0,@modelcontextprotocol/client@2.0.0); the monolithic@modelcontextprotocol/sdkis retired at v1. This tracks adopting it across our MCP surface. Sibling work inbuildinternet/sunny: #773, Phase-1 PR #774.Design doc:
docs/superpowers/specs/2026-07-29-mcp-sdk-v2-design.md.Where we stand
The headline breaking change costs us little. Protocol-level sessions are gone and MCP is stateless — each request carries its protocol version and client capabilities in reserved
_metakeys.workers/mcpbinds no Durable Objects, so the session state its current transport holds is already per-isolate and best-effort. Nothing durable depends on it. We use none of the deprecated features (Roots, Sampling, Logging, HTTP+SSE transport).Our migration differs from sunny's in one structural way. Sunny hand-wires the SDK's own transport, so its PR is a direct SDK swap. We serve MCP through
agents/mcp(the Cloudflare Agents SDK), which already did this migration upstream:agents@0.20.1moves the MCP SDK from a hard dependency to peers on both v1@modelcontextprotocol/sdk@1.30.0and v2@modelcontextprotocol/server@2.0.0+/client@2.0.0.agents/mcp'screateMcpHandleris now the stateless v2 handler taking anMcpServerFactory. The sessionful SDK-v1 handler we use today (agents@0.17.3) is renamedcreateLegacyMcpHandler.So Phase 1 is an
agentsbump plus a call-site change, not a transport rewrite. It also means the legacy leg sunny had to hand-wire (a secondWebStandardStreamableHTTPServerTransportwithenableJsonResponse: true, to stop 2025-era clients silently receiving SSE) is a singleresponseMode: "json"option for us.Already compatible, verified against the v2 type surface:
ResourceTemplate+ itscompletemaps (slug-completion.ts),completable()on prompt args, toolannotations, and_meta— which is what carries the MCP Apps UIui.resourceUriand theui.cspresourceDomainsallowlist (#1230).resultTypeis a wire-only discriminator, stripped from the handler-facing types, so tool callbacks are unaffected.Mechanical churn: ~19 raw-shape
inputSchema: { … }sites acrossmcp-agent.ts,follows-tools.ts,whats-changed-tool.tsbecomez.object(…), andwithPagination()returns an object schema. Raw shapes still work via a deprecated overload, so this is de-risking rather than a blocker.Side benefit: the
zod: ~4.3.6pin inworkers/mcpexists only because SDK v1 nested its own copy (#1367). v2 declareszod ^4.2.0, so the pin should be droppable.Plan
agents ^0.17.3 → ^0.20.1, drop the direct@modelcontextprotocol/sdkdep, add@modelcontextprotocol/server@^2.0.0(+/clientfor tests). Switchworkers/mcp/src/index.tsto the statelesscreateMcpHandler(factory)withroute,responseMode: "json", and explicitallowedOriginHostnames(the 0.20 wrapper does its ownHost/Originvalidation and custom domains are not covered by default). SetttlMs: 3_600_000/cacheScope: "private"cache hints ontools/list,prompts/list,resources/templates/list— static per deploy but auth-gated. Wrap tool/prompt schemas inz.object. Migratetests/mcp-test-helpers.tsand the five suites on it to the v2 client; add modern-envelope (_meta+Mcp-Method/Mcp-Name) and legacy-initializetests driving the real fetch handler. Refresh the carved-outworkers/mcp/bun.lock. Updatedocs/architecture/mcp.mdandworkers/mcp/server.json.1.6.23 → 1.7upgrade, not on upstream. Bigger lift here than in sunny: we run api-key, passkey, stripe, oauth-provider, and organization plugins acrossworkers/apiandweb. DCR stays spec-valid through the deprecation window. Own issue.workers/mcp/ui+ hardening.@modelcontextprotocol/ext-apps ^1.7.3 → 1.7.5and its own SDK copy; regenerate the committed release-feed bundle (separate carved-out build with its own lockfile). The server-side_metacontract is unchanged, so the UI keeps working untouched during Phase 1. ConsiderMcp-Method-based rate-limit rules now that the method is a header and needs no body parsing.Not in scope
subscriptions/listen— that is #346, a real feature request, not a migration item. No feature flag: this is a dependency migration with no runtime toggle worth the permanent registry entry.