Skip to content

feat(core)!: migrate to @modelcontextprotocol/sdk v2 (MCP 2026-07-28) - #1008

Draft
harijoe wants to merge 6 commits into
mainfrom
v2
Draft

feat(core)!: migrate to @modelcontextprotocol/sdk v2 (MCP 2026-07-28)#1008
harijoe wants to merge 6 commits into
mainfrom
v2

Conversation

@harijoe

@harijoe harijoe commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

What

Migrates packages/core from the v1 monolith @modelcontextprotocol/sdk to the v2 split packages @modelcontextprotocol/{core,client,server,express} (2.0.0-beta.5).

sdk v2 is the reference implementation of the MCP 2026-07-28 protocol RC (stateless core, per-request envelope, input_required, auth hardening). This is a breaking, semver-major change for Skybridge — no back-compat shims are kept.

Status on-branch: tsc --noEmit 0 errors · test:unit 361/361 · biome clean. Full core migrated, auth included.

Non-trivial changes

HTTP transport → v2 stateless / per-request model (the protocol's headline change, and the bulk of the work)

  • v2 has no StreamableHTTPServerTransport.handleRequest(req,res,body). The /mcp route now wraps createMcpHandler(factory), which is per-request by construction.
  • Skybridge already did per-request-fresh-instance internally: connectStatelessTransport(transport) became createStatelessServerInstance() (fresh SdkServer + grafted _requestHandlers/_notificationHandlers), used directly as the createMcpHandler factory body. No singleton rearchitecture.
  • Express↔Fetch bridge: build a WHATWG Request from the Express req and call handler.fetch(request, { authInfo: req.auth, parsedBody: req.body }), then pipe the Response back. The SDK now owns method rules (GET/DELETE → 405), classification, and error→500. The concurrent-request "Already connected" race is gone.

Per-request handler context (RequestHandlerExtraServerContext)

  • Handlers read ctx.http?.req (a Fetch Request — headers via .headers.get(), url via new URL(req.url)) and ctx.http?.authInfo.
  • The public McpExtra type is now type McpExtra = ServerContext — the v1-shaped shim and its as unknown as McpExtra cast were removed.

zod-compat removed → Standard Schema

  • SchemaOutput/ZodRawShapeCompat/AnySchema re-derived over StandardSchemaV1. Zod v4 schemas satisfy Standard Schema, so app-facing tool definitions are unchanged.

Errors & misc

  • McpError/ErrorCodeProtocolError + code constants; InvalidTokenErrorOAuthError (real v2 name exposed, no back-compat alias — intended v2 break).
  • setRequestHandler is now 3-arg in v2 (adapted the skills directory-read handler).
  • Import flattening: inferred types from server/client roots, Zod schemas from core, auth middleware/router from express.

Choices

  • No defensive shims. v2 is a breaking major, so old public names (InvalidTokenError, v1-shaped McpExtra) are gone rather than aliased.
  • ext-apps stays on v1 (web/bridges/mcp-app/* + a few types.ts types) — the only remaining v1 monolith imports. Migrating them breaks ext-apps' App.registerTool handler type; gated on an upstream ext-apps v2.
  • packages/devtools untouched — separate follow-up.
  • Two test rewires worth noting: the express error-pipeline tests now trigger a real throwing /mcp middleware (v2's createMcpHandler absorbs factory errors into a 500 itself, so a mocked factory throw can't reach next(error)); the skills tests updated for the 3-arg setRequestHandler.

Not in scope / gating

  • Pinned to beta.5 (pre-RC). Do not merge to ship — gated on protocol 2026-07-28 final + SDK 2.0.0 stable + an ext-apps v2 rebase. Draft until then.
  • Templates (create-skybridge blank/demo) + the core peerDependencies swap to the v2 packages are the next step.

Tracked in SKY-514.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can't use peerDeps model anymore for dependency to the SDK ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We can, but we now need to import 4 deps instead of just the sdk. It's a discussion to have but it makes sense on a DX perspective to not use peerDeps anymore.

},
"dependencies": {
"@babel/core": "^7.29.7",
"@modelcontextprotocol/client": "2.0.0-beta.5",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can be moved to dev deps, only used in .test.ts files

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.

2 participants