Conversation
Contributor
PreviewPreview deployments for this PR have been cleaned up. |
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-preact
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-solid
@modelcontextprotocol/server-basic-svelte
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-basic-vue
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-debug
@modelcontextprotocol/server-lazy-auth
@modelcontextprotocol/server-map
@modelcontextprotocol/server-pdf
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-shadertoy
@modelcontextprotocol/server-sheet-music
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-transcript
@modelcontextprotocol/server-video-resource
@modelcontextprotocol/server-wiki-explorer
commit: |
npm pack runs the prepare script for directory specs even with --ignore-scripts and its output can pollute stdout, so locate the packed tarball on disk instead of parsing --json output. Run npm with a minimal environment so caller npm config cannot leak into the synthetic consumers, and require exact versions for the consumers' dependencies. Add a CI job that runs the check on Node 22.
The client, core and server packages become ^2.0.0 peers and client is now a required peer (App and AppBridge extend its Protocol class); server stays optional for View-only consumers. Examples move to zod ^4.2.0 to match the library peer range. The root package is not yet published at 2.0.0, so the lockfile now links the examples' @modelcontextprotocol/ext-apps dependency to the repository root instead of a registry copy. This drops the stale 1.x tarball (and its sdk 1.x peer) from the lockfile and makes scripts/link-self.mjs a no-op.
spec.types.ts previously inferred CallToolResult, ContentBlock and friends from core's Zod schemas via a local core-types module so that the type surface stayed free of a client package edge. Now that client is a required peer, take the types from it directly and delete the indirection. Generated schemas are unchanged.
SDK v2 registerTool takes Standard JSON Schema objects (z.object(...))
and keeps a deprecated overload for the v1 raw-shape form. Mirror that
here so existing servers passing { field: z.string() } keep compiling;
the call is forwarded to the SDK, which auto-wraps the shape. Tests
exercise both forms end to end through a real McpServer and Client.
The app-only consumer now also exercises the ./react entry. The server-only consumer no longer asserts that client is absent from node_modules (npm auto-installs required peers) but still checks that the server entry does not bundle it. Surface npm and esbuild errors instead of swallowing them.
Consumers using moduleResolution NodeNext need explicit extensions in the emitted declaration files. Covers every source file except app.ts, app-bridge.ts and events.ts (and their tests), which are being reworked separately.
The zod peer range is ^4.2.0, whose schemas implement ~standard.jsonSchema, so the lazy zod/v4 toJSONSchema fallback for zod 3.25 is dead code. Re-export StandardSchemaWithJSON from the client package instead of keeping a structurally identical local copy.
Install instructions now list the split base MCP SDK packages at ^2.0.0 by role (core comes in transitively, server only for server authors), require Node 20+, and state that the wire protocol is unchanged so 2.x Views and 1.x hosts interoperate. The agent skills lose the exact prerelease wording and add-app-to-server gains a v1 to v2 import mapping. docs/migrate-to-2.md lists the breaking changes, the peer matrix and the host-side error deltas.
Replay JSON-RPC messages recorded from ext-apps 1.7.x (sdk 1.x key order and ids) through the 2.x App and AppBridge over a raw in-memory transport and assert exactly what 2.x emits: the ui/initialize handshake, params-less ui/notifications/initialized, tools/call in both directions, and the -32002 to -32602 re-encoding on the host side. Also check that AppBridge never sends an MCP initialize toward the View and that the outer-client proxy works with a default (non-legacy) 2.x Client/Server pair.
The base SDK Protocol silently replaces an existing request or notification handler. v1's ProtocolWithEvents threw instead, so a stray setRequestHandler / setNotificationHandler could not disconnect on* handlers or addEventListener listeners. Restore that guard on both App and AppBridge with a small MethodRegistry, keep replace semantics for the on* setters via a protected replaceRequestHandler, and release methods on removeRequestHandler / removeNotificationHandler. Also: - give oncreatesamplingmessage a getter, a replace warning and the same clearable shape as the other request setters - let App register handlers for custom (non-spec) methods; the default branch of assertRequestHandlerCapability threw a misleading "No handler for method X registered" error - move the RESOURCE_URI_META_KEY / RESOURCE_MIME_TYPE docs to src/constants.ts where the constants now live - fix stale "inherited from Server" wording and point @see links at @modelcontextprotocol/client, which is what hosts install
Add explicit .js extensions to the relative imports in app.ts, app-bridge.ts and their tests so the emitted declarations resolve under NodeNext (#704). Replace the zod 3 JSON Schema fallback test, whose code path was removed, with the remaining non-Standard-JSON-Schema rejection case as its own test.
- pdf-server build-mcpb.mjs packs the ext-apps build from this checkout
into the staging dir instead of asking the registry for ^2.0.0, which
is not published yet; CI's "Build MCPB bundle" step failed on ETARGET.
- Claim notifications/cancelled and notifications/progress in the
MethodRegistry right after super() so a direct setNotificationHandler
cannot silently replace the base Protocol's own handlers.
- Migration guide and add-app-to-server skill: custom methods use the
three-argument setRequestHandler("m", { params }, handler) form (the
two-argument form is only for spec methods); zod schemas live in
@modelcontextprotocol/core, not client/server; it is
toolInfo.tool.outputSchema that loosened in schema.json, and the
recursive JSON-value def is nested under three definitions; core is a
required peer that client already depends on.
- app-bridge.ts: fix "forthe"/"forresult" typos in @see links, update
three JSDoc examples to the method-string setNotificationHandler form,
move the UntypedHandlerSetter type below the import block (same in
app.ts).
- wire-compat.test.ts: say the fixtures are 1.x-shaped, not captures.
This was referenced Sep 8, 2026
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.
Follow-up to #720 (merged as-is) and #705: the fixups needed before cutting ext-apps 2.0.0. Note
maincannotnpm ciuntil this lands (the lockfile fix is the first commit here).npm cifailed on Migrate to SDK v2 with official Protocol and isolated role peers #720's head because 47 nestedexamples/*/node_modules/@types/node/undici-typesentries were missing; regenerated.check-dependency-isolation.mjs:npm pack --ignore-scripts --jsonstill runsprepareon npm 10 and the build output brokeJSON.parse; the script now finds the tarball on disk, runs installs with a minimal env, asserts exact versions, covers./react, and runs as a CI job. TypeDoc validation runs with--treatValidationWarningsAsErrors.^2.0.0peers: the SDK packages version together, so exact2.0.0pins would ERESOLVE at the first 2.0.1.clientis now a required peer (the view entry imports it at runtime);serverstays optional.@modelcontextprotocol/clientinstead ofcore-types.ts, so ext-apps'CallToolResultetc. are the same aliases consumers already import. Generated schemas unchanged.Protocolsilently replaces handlers, so a directsetRequestHandler/setNotificationHandlercould disconnecton*handlers oraddEventListenerlisteners without a warning. Back to v1's throw, withreplaceRequestHandlerfor theon*setters.oncreatesamplingmessagegets a getter and a replace warning;Appaccepts custom-method handlers (the default branch ofassertRequestHandlerCapabilitythrew a misleading error).registerAppToolraw zod shapes kept as a deprecated overload mirroring the SDK's, so existing servers don't have to rewrite every tool registration..jsextensions on the library sources; this adds the last three test/spec files it did not touch.standardSchemaToJsonSchemalazily importedzod/v4and calledz.toJSONSchema()for zod 3.25 schemas, which implement~standard.validatebut not~standard.jsonSchema(that field only arrived in zod 4.2.0).@modelcontextprotocol/core@2.0.0declareszod ^4.2.0as a regular dependency, so a consumer on zod 3 can no longer satisfy the SDK at all, and the SDK's ownMcpServer.registerToolperforms the sametoJSONSchemafallback (with a warning) for the 4.0 to 4.1 window. Keeping our copy would have been dead code behind a peer range (^3.25.0 || ^4.0.0) that no longer exists; the peer is now^4.2.0to match core.docs/migrate-to-2.md(breaking changes, peer matrix, host-side wire deltas,schema.jsonchanges),Protocolattributed toclientrather thancore, Node 20+.src/wire-compat.test.tsreplays captured 1.x JSON through the 2.xAppandAppBridgein both directions (including the-32002→-32602re-encoding), checks the bridge sends no MCPinitializetoward the view, and exercises a default-negotiation outerClient/Serverproxy.Verified in the Playwright CI image:
npm ci, build, 418 unit tests, 28 example builds,test:dependency-isolation, TypeDoc strict, prettier, and the e2e suite (65 functional tests pass; the 9 golden-screenshot comparisons fail identically onmainin the same image, so that's the goldens, not this change).One thing to flag: the examples now depend on
@modelcontextprotocol/ext-apps@^2.0.0, which isn't published, so the lockfile resolves that name to a link to the repo root. Side effect: npm runs the rootprepareon install even with--ignore-scripts. A plainnpm installafter the 2.0.0 release drops the link entry.Review pass on this branch (three independent checks: code, consumer installs plus executed 1.x interop, docs fact-check) turned up and fixed in the last commit: the pdf-server MCPB packaging step installed from the registry and could not find ext-apps 2.0.0 (it now packs the checkout's build into the staging dir), the guard now also covers the base
Protocol's ownnotifications/cancelledandnotifications/progresshandlers, three factual errors in the migration guide (custom-methodsetRequestHandlerform, where the zod schemas live, whichschema.jsonfield loosened), and some JSDoc typos and stale v1 snippets.