feat(mcp): migrate to the stateless MCP 2026-07-28 protocol - #297
Merged
Conversation
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
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
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.
antfu
approved these changes
Aug 26, 2026
# 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-Idlifecycle 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/DELETEon the HTTP endpoint now return405(were the 2025 session stream/teardown ops).Mcp-Session-Idis issued; both a default (2025-era) client and a modern client connect + list + call successfully.list_changedpush over HTTP (stateless legacy has no server→client channel); modern clients get it viasubscriptions/listen.Changes
createMcpFetchHandler) moves to the SDK'screateMcpHandler, building a fresh server per request. The loopback origin gate is unchanged.createMcpServer) moves toserveStdio, pinning one server per connection.devframe connectnegotiates the modern era viaserver/discover, falling back to the 2025 handshake for a 2025-only instance.list_changedevents bridge onto modernsubscriptions/listenstreams — over HTTP through the handler's notify bus, on stdio through the pinned server'ssend*ListChangedcalls.buildMcpServerFromContext) is split from the notification bridge (bridgeListChanged); the oldtransports.tsstdio wrapper is removed.Docs
Closes #293
This PR was created with the help of an agent.