Skip to content

Migrate to SDK v2 with official Protocol and isolated role peers - #720

Merged
ochafik merged 13 commits into
modelcontextprotocol:mainfrom
tonxxd:fix/official-protocol-role-peers
Sep 8, 2026
Merged

Migrate to SDK v2 with official Protocol and isolated role peers#720
ochafik merged 13 commits into
modelcontextprotocol:mainfrom
tonxxd:fix/official-protocol-role-peers

Conversation

@tonxxd

@tonxxd tonxxd commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR brings @khandrew1's SDK v2 migration from #710 upstream together with Felix's public-Protocol port and the role-isolated optional peers alternative.

Problem

The migration to SDK v2 makes both role packages peers of one ext-apps package. A server entry point also imported constants through app.ts, creating a server → app → client edge.

flowchart LR
  Consumer["server-only consumer"] --> ServerEntry["ext-apps/server"]
  ServerEntry --> App["app.js"]
  App --> Client["@modelcontextprotocol/client"]
  ServerEntry --> Server["@modelcontextprotocol/server"]
Loading

Proposed architecture

This alternative reuses the official public Protocol base while isolating each entry point to its matching optional role peer.

flowchart TB
  subgraph ClientSide["App / host entry points"]
    AppEntry[". / react"] -. "optional peer" .-> Client["@modelcontextprotocol/client"]
    BridgeEntry["app-bridge"] -. "optional peer" .-> Client
  end

  subgraph ServerSide["Server entry point"]
    ServerEntry["server"] -. "optional peer" .-> Server["@modelcontextprotocol/server"]
  end

  AppEntry --> Core["@modelcontextprotocol/core"]
  BridgeEntry --> Core
  ServerEntry --> Core
Loading
Consumer Installs Does not install or bundle
App / host ext-apps + client + core server
MCP server ext-apps + server + core client

Implementation

  • Preserves @khandrew1's v2 migration.
  • Ports App and AppBridge to the official Protocol<BaseContext>.
  • Preserves the Apps-only ui/initialize handshake used by v1 hosts.
  • Moves resource constants and shared core wire types into neutral modules.
  • Marks client and server peers optional.
  • Adds packed app/host-only and server-only compile/install/bundle assertions.
  • Clears dist before builds so stale role edges cannot enter published packages.

SDK package status

The public Protocol export from typescript-sdk#2501 is published in @modelcontextprotocol/client@2.0.0-beta.5.

This branch now uses the complete registry-published beta.5 package set (client, core, server, express, and node). The temporary pkg.pr.new specifications and MCP overrides have been removed, and the lockfile contains only npmjs.org HTTP(S) package resolutions.

Tradeoff

This keeps request lifecycle, cancellation, validation, and transport behavior in the official SDK. Consumers still install the one role package used by their entry point. The core-only alternative in #719 avoids both role packages but owns more protocol code in ext-apps.

Verification

  • npm run build
  • npm run build:all
  • npm test: 392 passed, 1 skipped
  • npm run test:dependency-isolation
  • TypeDoc validation with warnings treated as errors
  • Prettier, version consistency, and git diff --check
  • Registry-only lockfile invariant used by CI
  • Functional integration-server E2E: 5 passed

khandrew1 and others added 10 commits July 14, 2026 13:35
Replaces the Client/Server subclassing from the v2 migration with direct
Protocol extension, now that the SDK exports Protocol from the client
package root. This restores the v1 wire contract on the iframe channel:
ui/initialize is the first and only handshake, so deployed hosts keep
working unchanged.

Deleted with the double handshake: the inner MCP initialize round-trip
and its pinned protocol version, the contentless inner capabilities and
their retro-registration plumbing, the oninitialized defineProperty
shadow, and the getCapabilities/getHostCapabilities split (v1
getCapabilities restored). Tests pin the wire order and assert no MCP
initialize is sent in either direction.

Note: package.json overrides point the SDK packages at locally built
tarballs carrying the Protocol export; replace with published versions
before any upstream PR.
The Protocol-based migration needs the Protocol class exported from the
package roots, which lands in modelcontextprotocol/typescript-sdk#2501.
Pin the preview builds so the branch is installable; swap to the next
published beta once that PR is released.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates @modelcontextprotocol/ext-apps to the split MCP SDK v2 packages while switching the Apps iframe channel to the official public Protocol base (preserving the v1 ui/initialize-first wire contract) and enforcing role-isolated optional peers for client/server dependencies.

Changes:

  • Ports App/AppBridge and transports/types to v2 split packages (@modelcontextprotocol/{client,core,server}) and updates related tests/snippets.
  • Moves shared wire types/constants into role-neutral modules and updates server helpers accordingly.
  • Adds dependency-isolation verification and improves TypeDoc linking to base SDK docs.

Reviewed changes

Copilot reviewed 122 out of 125 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
typedoc.config.mjs Adds base-SDK external symbol link mapping + plugin.
src/types.ts Removes protocol-wide union types; keeps re-exports.
src/spec.types.ts Switches shared type imports to role-neutral core-types.
src/server/index.ts Removes server→app edge; updates schemas/types to v2.
src/server/index.test.ts Updates server type import to v2 package.
src/server/index.examples.ts Updates examples to v2 server imports + zod objects.
src/react/useApp.tsx Updates Implementation type import to v2 client package.
src/message-transport.ts Moves JSONRPC schema to core; transport types to client.
src/message-transport.test.ts Updates JSONRPCMessage type import to v2 client package.
src/generated/schema.ts Updates MCP schema imports from sdk to core.
src/generated/schema.json Regenerated JSON schema reflecting new schema typing.
src/events.ts Refactors to protocol-independent EventDispatcher with warnings.
src/events.test.ts Adds unit coverage for EventDispatcher behavior.
src/core-types.ts New: role-neutral shared types inferred from core schemas.
src/constants.ts New: role-neutral resource metadata constants.
src/app.ts Migrates App to Protocol base; updates handlers/capabilities/events.
src/app.test.ts New tests pin iframe handshake order + v2 Protocol behavior.
src/app.examples.ts Updates examples to split v2 client/server types.
src/app-bridge.test.ts Updates to v2 packages; adds handshake/validation/proxy tests.
src/app-bridge.examples.ts Updates examples to v2 packages + new context signal shape.
scripts/typedoc-plugin-base-sdk-links.mjs New TypeDoc resolver for base-SDK local refs.
scripts/generate-schemas.ts Updates schema generator commentary/import rewrite to core.
scripts/check-dependency-isolation.mjs New packed install/compile/bundle role-isolation check.
README.md Updates install guidance to split v2 packages.
plugins/mcp-apps/skills/create-mcp-app/SKILL.md Updates dependency guidance for v2 split packages.
plugins/mcp-apps/skills/convert-web-app/SKILL.md Updates migration instructions/snippets for v2 APIs.
plugins/mcp-apps/skills/add-app-to-server/SKILL.md Updates setup + code samples for v2 APIs.
package.json Switches to split v2 peer deps + adds isolation test script.
package-lock.json Updates lockfile for split v2 packages + examples.
examples/wiki-explorer-server/src/mcp-app.ts Updates CallToolResult typing import to v2 client package.
examples/wiki-explorer-server/server.ts Updates server types/imports to v2 server package.
examples/wiki-explorer-server/package.json Adds split v2 dependencies.
examples/wiki-explorer-server/main.ts Updates transports to v2 express/node/server packages.
examples/video-resource-server/src/mcp-app.ts Updates CallToolResult typing import to v2 client package.
examples/video-resource-server/server.ts Updates server types/imports + input schema to z.object.
examples/video-resource-server/package.json Adds split v2 dependencies.
examples/video-resource-server/main.ts Updates transports to v2 express/node/server packages.
examples/transcript-server/server.ts Updates server imports + uses z.object({}) inputSchema.
examples/transcript-server/package.json Adds split v2 dependencies.
examples/transcript-server/main.ts Updates transports to v2 express/node/server packages.
examples/threejs-server/src/mcp-app-wrapper.tsx Updates CallToolResult typing import to v2 client package.
examples/threejs-server/server.ts Updates server imports + uses z.object({}) inputSchema.
examples/threejs-server/package.json Adds split v2 dependencies.
examples/threejs-server/main.ts Updates transports to v2 express/node/server packages.
examples/system-monitor-server/server.ts Updates server imports + outputSchema uses full Zod schema.
examples/system-monitor-server/package.json Adds split v2 dependencies.
examples/system-monitor-server/main.ts Updates transports to v2 express/node/server packages.
examples/sheet-music-server/server.ts Updates server imports to v2 server package.
examples/sheet-music-server/package.json Adds split v2 dependencies.
examples/sheet-music-server/main.ts Updates transports to v2 express/node/server packages.
examples/shadertoy-server/server.ts Updates server imports to v2 server package.
examples/shadertoy-server/package.json Adds split v2 dependencies.
examples/shadertoy-server/main.ts Updates transports to v2 express/node/server packages.
examples/scenario-modeler-server/server.ts Updates imports + uses full Zod schemas (not .shape).
examples/scenario-modeler-server/package.json Adds split v2 dependencies.
examples/scenario-modeler-server/main.ts Updates transports to v2 express/node/server packages.
examples/say-server/package.json Removes sdk v1 dependency from python example package.json.
examples/quickstart/server.ts Updates server import + uses z.object({}) inputSchema.
examples/quickstart/package.json Adds split v2 dependencies.
examples/quickstart/main.ts Updates transports to v2 express/node/server packages.
examples/qr-server/package.json Removes sdk v1 dependency from python example package.json.
examples/pdf-server/src/mcp-app.ts Updates CallToolResult/ContentBlock imports to v2 client package.
examples/pdf-server/server.ts Updates server imports + requestId/signal usage to v2 context.
examples/pdf-server/server.test.ts Updates in-memory client imports to v2 client package.
examples/pdf-server/package.json Adds split v2 dependencies.
examples/pdf-server/main.ts Updates transports to v2 express/node/server packages.
examples/map-server/src/mcp-app.ts Updates ContentBlock typing import to v2 client package.
examples/map-server/server.ts Updates server imports + uses z.object for schemas.
examples/map-server/package.json Adds split v2 dependencies.
examples/map-server/main.ts Updates transports to v2 express/node/server packages.
examples/lazy-auth-server/server.ts Updates to v2 server/node + z.object({}) schemas + context id.
examples/lazy-auth-server/package.json Adds split v2 dependencies.
examples/integration-server/src/mcp-app.tsx Updates CallToolResult typing import to v2 client package.
examples/integration-server/server.ts Updates server imports + uses z.object({}) inputSchema.
examples/integration-server/package.json Adds split v2 dependencies.
examples/integration-server/main.ts Updates transports to v2 express/node/server packages.
examples/debug-server/server.ts Updates server imports to v2 server package.
examples/debug-server/package.json Adds split v2 dependencies.
examples/debug-server/main.ts Updates transports to v2 express/node/server packages.
examples/customer-segmentation-server/server.ts Updates imports + uses full Zod schemas (not .shape).
examples/customer-segmentation-server/package.json Adds split v2 dependencies.
examples/customer-segmentation-server/main.ts Updates transports to v2 express/node/server packages.
examples/cohort-heatmap-server/server.ts Updates imports + uses full Zod schemas (not .shape).
examples/cohort-heatmap-server/package.json Adds split v2 dependencies.
examples/cohort-heatmap-server/main.ts Updates transports to v2 express/node/server packages.
examples/budget-allocator-server/server.ts Updates imports + uses z.object({}) inputSchema.
examples/budget-allocator-server/package.json Adds split v2 dependencies.
examples/budget-allocator-server/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-vue/src/App.vue Updates CallToolResult typing import to v2 client package.
examples/basic-server-vue/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-vue/package.json Adds split v2 dependencies.
examples/basic-server-vue/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-vanillajs/src/mcp-app.ts Updates CallToolResult typing import to v2 client package.
examples/basic-server-vanillajs/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-vanillajs/package.json Adds split v2 dependencies.
examples/basic-server-vanillajs/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-svelte/src/App.svelte Updates CallToolResult typing import to v2 client package.
examples/basic-server-svelte/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-svelte/package.json Adds split v2 dependencies.
examples/basic-server-svelte/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-solid/src/mcp-app.tsx Updates CallToolResult typing import to v2 client package.
examples/basic-server-solid/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-solid/package.json Adds split v2 dependencies.
examples/basic-server-solid/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-react/src/mcp-app.tsx Updates CallToolResult typing import to v2 client package.
examples/basic-server-react/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-react/package.json Adds split v2 dependencies.
examples/basic-server-react/main.ts Updates transports to v2 express/node/server packages.
examples/basic-server-preact/src/mcp-app.tsx Updates CallToolResult typing import to v2 client package.
examples/basic-server-preact/server.ts Updates imports + uses z.object({}) inputSchema.
examples/basic-server-preact/package.json Adds split v2 dependencies.
examples/basic-server-preact/main.ts Updates transports to v2 express/node/server packages.
examples/basic-host/src/index.tsx Updates Tool type import to v2 client package.
examples/basic-host/src/implementation.ts Updates client + transports imports to v2 client package.
examples/basic-host/package.json Updates base SDK dependency to v2 client package.
docs/testing-mcp-apps.md Adds guidance about build/snippet type-checking.
docs/quickstart.md Updates Node requirement + dependencies/snippets to v2.
docs/patterns.tsx Updates imports and example code to v2 APIs.
docs/patterns.md Updates patterns snippets for v2 schema + request usage.
docs/overview.md Updates architecture/lifecycle explanation for v2 approach.
docs/migrate_from_openai_apps.md Updates McpServer import + zod object schema examples.
docs/authorization.md Updates schema example to z.object(...).
build.bun.ts Clears dist before build; updates externals to split peers.
AGENTS.md Updates architecture docs for Protocol-based iframe channel.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/app.ts Outdated
Comment thread src/app.ts Outdated
Comment thread docs/overview.md Outdated
Comment thread README.md
Comment on lines +125 to +129
npm install -S @modelcontextprotocol/ext-apps \
@modelcontextprotocol/client@2.0.0-beta.4 \
@modelcontextprotocol/server@2.0.0-beta.4 \
@modelcontextprotocol/core@2.0.0-beta.4 \
zod@^4.2.0
@ochafik

ochafik commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Thanks @tonxxd and @khandrew1 for carrying this through, and for the #719 / #720 side by side! I've gone through both against the now-stable SDK 2.0.0 and went with #720: keeping request lifecycle in the official Protocol is less code for ext-apps to own, the optional server peer plus the packed-install check gives view-only and server-only consumers what they need, and the wire stays exactly ui/initialize (I replayed captured 1.x traffic through it both ways, no diffs).

Update: rather than block on a round trip, I've merged this as-is (merge commit, so your commits keep their authorship) and put the fixups in a follow-up against main: #768. That supersedes the PR I'd opened on the fork. All mechanical:

  • npm ci failed on the head here (47 nested @types/node / undici-types entries fell out of the lockfile); regenerated.
  • check-dependency-isolation.mjs crashes on npm 10 (npm pack --json still runs prepare); fixed and wired into CI, TypeDoc validation now strict.
  • 2.0.0 with ^2.0.0 peers (the SDK packages version together, an exact pin would ERESOLVE at 2.0.1); client required since the view entry imports it, server optional.
  • Types from @modelcontextprotocol/client rather than core-types.ts, so CallToolResult is the alias consumers already use.
  • v1's throw on double setRequestHandler / setNotificationHandler restored (the SDK's silent replace let a stray registration disconnect on* handlers), oncreatesamplingmessage gets a getter and replace warning, App accepts custom-method handlers.
  • Deprecated raw-shape overload kept on registerAppTool, mirroring the SDK's, so existing servers don't have to rewrite every registration.
  • .js on relative imports for NodeNext (Emitted .d.ts use extensionless relative imports — types break under NodeNext/Node16 (addEventListener invisible, TS2339) #704), zod 3 fallback removed, docs/skills off beta.5 with an install matrix and a 1.x → 2.x migration page, wire-compat tests replaying captured 1.x JSON both directions.

Once #768 is in I'll cut 2.0.0. Reviews welcome there if you spot anything :-)

@ochafik
ochafik marked this pull request as ready for review September 8, 2026 11:44

@ochafik ochafik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving to land as-is; fixups follow in a separate PR against main (see comment below).

ochafik added a commit that referenced this pull request Sep 8, 2026
…sts (#768)

Follow-up to #720 and #705: regenerated lockfile, ^2.0.0 peers with client required, types from @modelcontextprotocol/client, restored double-registration guard, deprecated raw-shape registerAppTool overload, migration guide, wire-compat tests, MCPB build from the local package.
@tonxxd

tonxxd commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Awesome thanks @ochafik , glad we could be helpful

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.

5 participants