Skip to content

Use public Protocol with isolated SDK role peers - #5

Draft
tonxxd wants to merge 6 commits into
khandrew1:codex/mcp-sdk-v2-beta4-migrationfrom
tonxxd:fix/official-protocol-role-peers
Draft

Use public Protocol with isolated SDK role peers#5
tonxxd wants to merge 6 commits into
khandrew1:codex/mcp-sdk-v2-beta4-migrationfrom
tonxxd:fix/official-protocol-role-peers

Conversation

@tonxxd

@tonxxd tonxxd commented Jul 20, 2026

Copy link
Copy Markdown

Summary

This is the official Protocol + role-isolated peers alternative to #4.

It starts from Andrew's PR modelcontextprotocol#710 head (f50ec6e) and replaces the temporary Client/Server inheritance on the iframe channel with the public v2 Protocol base restored by modelcontextprotocol/typescript-sdk#2501. Unlike #4, it does not maintain a local JSON-RPC protocol implementation.

The package remains a single npm package, but its entry points no longer have cross-role runtime or declaration edges:

  • ., ./react, and ./app-bridge use the client package
  • ./server uses the server package
  • client and server peers are optional, so consumers install only the role they import
  • shared Apps constants and core wire types live in role-neutral modules

Dependency shape

Before (modelcontextprotocol#710)

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

A server-only consumer therefore acquired both SDK roles.

This PR

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

Why this alternative

Compared with #4:

  • Less ext-apps-owned protocol code: request lifecycle, cancellation, validation, and transport behavior stay in the official SDK.
  • Closer SDK behavior: future Protocol fixes arrive through the official packages.
  • Tradeoff: consumers still install one role package appropriate to their entry point; fix: isolate ext-apps from MCP role packages #4 aims to depend on core alone.

The iframe wire flow remains Apps-specific:

sequenceDiagram
  participant View as View (App)
  participant Host as Host (AppBridge)
  View->>Host: ui/initialize
  Host-->>View: Apps capabilities + context
  View->>Host: ui/notifications/initialized
Loading

There is no additional standard MCP initialize handshake on the iframe channel.

Implementation

  • Port App and AppBridge to the official public Protocol<BaseContext>.
  • Preserve the existing Apps-only initialization sequence and ready gate.
  • Move resource constants out of app.ts, eliminating the server-to-app runtime edge.
  • Infer shared wire types from public @modelcontextprotocol/core schemas.
  • Mark client and server peers optional.
  • Clear dist before building to prevent stale entry-point artifacts from being packed.
  • Add a packed-consumer test that:
    • installs app/host entry points with client but without server;
    • installs the server entry point with server but without client;
    • compiles both consumers with full declaration checking;
    • bundles both and inspects esbuild metafiles for unintended opposite-role edges.

Upstream dependency status

modelcontextprotocol/typescript-sdk#2501 was merged on July 17, after 2.0.0-beta.4 was published. Per the maintainer's comment on #712, the public Protocol base will be available in the next beta.

For review, this draft uses the maintainer's pkg.pr.new artifacts for #2501. Before merge, replace those preview specifications with the next published beta and regenerate the lockfile.

Verification

Passed:

  • npm run build
  • npm run build:all (all example workspaces)
  • npm test — 392 passed, 1 skipped
  • npm run test:dependency-isolation
  • TypeDoc with validation warnings treated as errors
  • Prettier and git diff --check
  • Focused Playwright host/security E2E — 38 passed, 2 skipped; one PDF example discovery timeout

The full local Playwright run completed all 84 cases but was not green: visual goldens differed consistently in this macOS rendering environment, and the PDF group was timing-sensitive. No snapshots are updated in this PR. CI's Linux run should be treated as authoritative for those environment-sensitive checks.

Scope

This draft does not modify Andrew's branch or PR modelcontextprotocol#710 directly. It is intended for comparing the official-Protocol/role-peer design with the core-only design in #4.

felixweinberger and others added 3 commits July 20, 2026 11:14
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.
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