Skip to content

feat(mcp): migrate to the stateless MCP 2026-07-28 protocol - #297

Merged
antfu merged 4 commits into
mainfrom
feat/mcp-stateless-2026
Aug 27, 2026
Merged

feat(mcp): migrate to the stateless MCP 2026-07-28 protocol#297
antfu merged 4 commits into
mainfrom
feat/mcp-stateless-2026

Conversation

@antfubot

@antfubot antfubot commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

What & why

Migrates devframe's MCP surface to the stateless MCP 2026-07-28 protocol, as tracked in #293. It retires devframe's hand-rolled Mcp-Session-Id lifecycle in favor of the SDK's stateless serving entry points, so requests reach any server instance without session affinity and modern MCP clients are first-class.

The endpoints keep serving 2025-era clients through the SDK's default stateless legacy path — the custom session registry is gone, but existing clients keep listing and calling tools/resources.

Compatibility (ships within 0.9)

This is source-compatible — no public API, option-type, or dependency changes (the tsnapi snapshot is unchanged), so consumers need zero code changes and it lands as a 0.9 minor rather than a dedicated major.

The changes are on the wire only:

  • GET/DELETE on the HTTP endpoint now return 405 (were the 2025 session stream/teardown ops).
  • No Mcp-Session-Id is issued; both a default (2025-era) client and a modern client connect + list + call successfully.
  • The one regression: a 2025-era client no longer receives live list_changed push over HTTP (stateless legacy has no server→client channel); modern clients get it via subscriptions/listen.

Changes

  • HTTP (createMcpFetchHandler) moves to the SDK's createMcpHandler, building a fresh server per request. The loopback origin gate is unchanged.
  • stdio (createMcpServer) moves to serveStdio, pinning one server per connection.
  • devframe connect negotiates the modern era via server/discover, falling back to the 2025 handshake for a 2025-only instance.
  • list_changed events bridge onto modern subscriptions/listen streams — over HTTP through the handler's notify bus, on stdio through the pinned server's send*ListChanged calls.
  • The pure server factory (buildMcpServerFromContext) is split from the notification bridge (bridgeListChanged); the old transports.ts stdio wrapper is removed.

Docs

  • Rewrites the MCP adapter page's serving model (stateless, per-request).
  • Documents the change as a section in the "Migrating to 0.9" guide.

Closes #293

This PR was created with the help of an agent.

Serve the MCP surface through the SDK's stateless 2026-07-28 entry points,
retiring devframe's custom Mcp-Session-Id lifecycle:

- HTTP moves to `createMcpHandler`, building a fresh server per request
  (no session registry, no session-local routing, GET/DELETE -> 405).
  2025-era clients are still served through the SDK's stateless legacy path.
- stdio moves to `serveStdio`, pinning one server per connection.
- `devframe connect` negotiates the modern era via `server/discover`,
  falling back to the 2025 handshake for a 2025-only instance.
- `list_changed` events bridge onto modern `subscriptions/listen` streams
  (HTTP via the handler's notify bus; stdio via the pinned server's
  send*ListChanged calls).

The devframe API surface (createMcpServer, createMcpFetchHandler,
mountMcpHttp, cli.mcp) and the origin gate are unchanged.

Closes #293
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
devframe Ignored Ignored Preview Aug 27, 2026 1:56am
@antfu antfu changed the title feat(mcp): migrate to the stateless MCP 2026-07-28 protocol Aug 26, 2026
The hub aggregate-MCP and Next handler tests still exercised the 2025
initialize/Mcp-Session-Id handshake. Serve them statelessly: the hub test
lists tools with a single per-request POST, and both assert no session id
is issued.
# Conflicts:
#	docs/content/2.adapters/7.mcp.md
Retarget the stateless MCP 2026-07-28 migration to ship within 0.9: the
change is source-compatible (no public API or dependency changes), so it
lands as a 0.9 minor rather than a dedicated 0.10 clean break. Remove the
separate 0.10 guide, revert the migration renumbering, and document the
stateless endpoints as a section in the 0.9 guide.
@antfu antfu changed the title feat(mcp)!: migrate to the stateless MCP 2026-07-28 protocol Aug 27, 2026
@antfu
antfu merged commit 8d58eb5 into main Aug 27, 2026
18 of 19 checks passed
@antfu
antfu deleted the feat/mcp-stateless-2026 branch August 27, 2026 02:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants