- 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.
6.1 KiB
| title | group | description |
|---|---|---|
| Migrate to v2 | Getting Started | Upgrade from ext-apps 1.x to 2.x — new base MCP SDK peer packages, API changes for Views and hosts, and what stays wire-compatible. |
Migrating from ext-apps 1.x to 2.x
ext-apps 2.x is built on the base MCP TypeScript SDK 2.x, which replaced the
single @modelcontextprotocol/sdk package with @modelcontextprotocol/client,
server, core, node and express. The MCP Apps wire protocol did not
change; the breaking changes are in dependencies and in the TypeScript API.
Host compatibility
The ui/* messages exchanged over the iframe channel are byte-identical to
1.x. A 2.x View runs in a 1.x host and a 2.x host renders 1.x Views. The only
host-side deltas are in error responses (see below).
Peer dependencies by role
| Role | Install |
|---|---|
| View author | @modelcontextprotocol/ext-apps, @modelcontextprotocol/client@^2.0.0, zod@^4.2.0 (+ react/react-dom for ./react) |
| Host author | same as View author |
| MCP server author | View author packages + @modelcontextprotocol/server@^2.0.0; @modelcontextprotocol/node and express for HTTP transports |
CDN / *-with-deps |
nothing extra: ./app-with-deps and ./react-with-deps bundle client, core and zod (about 25% larger than the 1.x bundles) |
@modelcontextprotocol/client is a required peer (App and AppBridge extend
its Protocol class); @modelcontextprotocol/core is a required peer that client already depends on, so npm installs it without you listing it;
@modelcontextprotocol/server stays optional and is only needed for the
./server helpers. Node.js 20+ is required.
Breaking changes
- Peer packages.
@modelcontextprotocol/sdk@^1is replaced by the split 2.x packages above, all at^2.0.0. Remove the 1.x package from your project; the two SDKs do not interoperate. - zod 3 dropped. The peer range is
zod@^4.2.0. Tool schemas must implement Standard JSON Schema (~standard.jsonSchema): zod v4, ArkType, Valibot. Raw zod shapes ({ q: z.string() }) still work withregisterAppToolbut are deprecated; wrap them withz.object({...}). App/AppBridgeextendProtocolfrom@modelcontextprotocol/client.ProtocolWithEvents,AppRequest,AppNotificationandAppResultare gone; use the SDK'sProtocol,Request,NotificationandResult.- Handler context. Custom handlers receive the SDK 2.x context:
extra.signal→extra.mcpReq.signal,extra.requestId→extra.mcpReq.id. setRequestHandler/setNotificationHandlertake method names.app.setRequestHandler(SomeRequestSchema, handler)becomesapp.setRequestHandler("some/method", { params: SomeParamsSchema }, (params, ctx) => …)for custom methods (the handler receives the parsed params); the two-argumentsetRequestHandler("tools/call", handler)form exists only for spec-defined method names.- Errors. Remote JSON-RPC errors are
ProtocolError(numericcode); local conditions areSdkErrorwith a stringcode: request timeout →"REQUEST_TIMEOUT", connection closed →"CONNECTION_CLOSED". Cancelling a request with anAbortSignalalso rejects with"REQUEST_TIMEOUT"(the message is the abort reason). Messages no longer carry theMCP error N:prefix.
Host-side wire deltas
Observed when a 2.x AppBridge answers a View; a 1.x View sees these too.
| Situation | 1.x host | 2.x host |
|---|---|---|
A handler throws -32002 (resource not found) |
error.code: -32002 |
error.code: -32602 (the SDK never emits -32002) |
Invalid params on a ui/* request |
-32603 with a zod issue dump |
-32602 Invalid params for <method>: … |
| Error message text | MCP error -32602: … prefix |
plain message |
tools/call to an unknown tool through a 2.x McpServer |
result.isError: true |
JSON-RPC error -32602 (callServerTool rejects) |
schema.json
The published ./schema.json export is regenerated from the 2.x core schemas:
McpUiToolResultNotification.params.structuredContentis any JSON value (wastype: "object").McpUiToolResultNotification.params._metadocumentsio.modelcontextprotocol/serverInfoand no longer listsprogressToken/related-task(both still pass through).McpUiHostContext.toolInfo.tool.outputSchemais a loose object (only$schemais documented);inputSchema.propertiesvalues are now typed as JSON values.- A recursive JSON-value definition (
__schema0) is added under the$defsofMcpUiHostContext,McpUiHostContextChangedNotificationandMcpUiInitializeResult.
Checklist
npm uninstall @modelcontextprotocol/sdkand install the packages for your role from the table above.- Replace
sdk/...imports with the split packages (sdk/server/mcp.js→@modelcontextprotocol/server,sdk/server/streamableHttp.js→NodeStreamableHTTPServerTransportfrom@modelcontextprotocol/node,sdk/server/stdio.js→@modelcontextprotocol/server/stdio,sdk/types.js→@modelcontextprotocol/clientorserverfor the types,@modelcontextprotocol/corefor the zod schemas). - Wrap raw zod shapes with
z.object({...}). - Update custom handlers to the
extra.mcpReq.*context and method-keyedsetRequestHandlercalls. - Replace
McpError/ numeric-code checks withProtocolError/SdkError.