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 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 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate migration to stateless MCP 2026-07-28

2 participants