Document the 2.x install matrix and add a migration guide
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.
This commit is contained in:
parent
09bf2aae3c
commit
c5b2543115
11 changed files with 145 additions and 27 deletions
|
|
@ -60,8 +60,8 @@ rm -fR package-lock.json node_modules && \
|
|||
|
||||
### Key Source Files
|
||||
|
||||
- `src/app.ts` - `App` subclasses the base MCP SDK `Protocol`, handles View initialization, tool calls, and messaging
|
||||
- `src/app-bridge.ts` - `AppBridge` subclasses the base MCP SDK `Protocol` for the iframe channel and proxies through a separate outer `Client`
|
||||
- `src/app.ts` - `App` subclasses `Protocol` from `@modelcontextprotocol/client`, handles View initialization, tool calls, and messaging
|
||||
- `src/app-bridge.ts` - `AppBridge` subclasses `Protocol` from `@modelcontextprotocol/client` for the iframe channel and proxies through a separate outer `Client`
|
||||
- `src/server/index.ts` - Helpers for MCP servers to register tools/resources with UI metadata
|
||||
- `src/types.ts` - Protocol types re-exported from `spec.types.ts` and Zod schemas from `generated/schema.ts` (auto-generated during build)
|
||||
- `src/message-transport.ts` - `PostMessageTransport` for iframe communication
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -122,27 +122,33 @@ resources:
|
|||
|
||||
## Getting Started
|
||||
|
||||
Requires Node.js 20+. The base MCP SDK packages are `^2.0.0` peers of
|
||||
`ext-apps` (`@modelcontextprotocol/core` is pulled in transitively).
|
||||
|
||||
For a View or host:
|
||||
|
||||
```bash
|
||||
npm install -S @modelcontextprotocol/ext-apps \
|
||||
@modelcontextprotocol/client@2.0.0-beta.5 \
|
||||
@modelcontextprotocol/core@2.0.0-beta.5 \
|
||||
@modelcontextprotocol/client@^2.0.0 \
|
||||
zod@^4.2.0
|
||||
```
|
||||
|
||||
For an MCP server:
|
||||
For an MCP server, add the server package (and, for HTTP transports, the Node
|
||||
and Express adapters):
|
||||
|
||||
```bash
|
||||
npm install -S @modelcontextprotocol/ext-apps \
|
||||
@modelcontextprotocol/server@2.0.0-beta.5 \
|
||||
@modelcontextprotocol/core@2.0.0-beta.5 \
|
||||
@modelcontextprotocol/client@^2.0.0 \
|
||||
@modelcontextprotocol/server@^2.0.0 \
|
||||
@modelcontextprotocol/node@^2.0.0 \
|
||||
@modelcontextprotocol/express@^2.0.0 \
|
||||
zod@^4.2.0
|
||||
```
|
||||
|
||||
Applications that implement both roles should install both `client` and
|
||||
`server`. Keep all installed base MCP SDK packages on the exact same published
|
||||
beta so they share one compatible protocol implementation.
|
||||
The wire protocol is unchanged between `ext-apps` 1.x and 2.x: a 2.x View works
|
||||
in a 1.x host and a 2.x host renders 1.x Views. See the
|
||||
[migration guide](https://apps.extensions.modelcontextprotocol.io/api/documents/migrate-to-v2.html)
|
||||
when upgrading from 1.x.
|
||||
|
||||
**New here?** Start with the
|
||||
[Quickstart Guide](https://apps.extensions.modelcontextprotocol.io/api/documents/Quickstart.html)
|
||||
|
|
|
|||
94
docs/migrate-to-2.md
Normal file
94
docs/migrate-to-2.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
title: Migrate to v2
|
||||
group: Getting Started
|
||||
description: 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 installed transitively;
|
||||
`@modelcontextprotocol/server` stays optional and is only needed for the
|
||||
`./server` helpers. Node.js 20+ is required.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
- **Peer packages.** `@modelcontextprotocol/sdk@^1` is 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 with
|
||||
`registerAppTool` but are deprecated; wrap them with `z.object({...})`.
|
||||
- **`App` / `AppBridge` extend `Protocol` from `@modelcontextprotocol/client`.**
|
||||
`ProtocolWithEvents`, `AppRequest`, `AppNotification` and `AppResult` are
|
||||
gone; use the SDK's `Protocol`, `Request`, `Notification` and `Result`.
|
||||
- **Handler context.** Custom handlers receive the SDK 2.x context:
|
||||
`extra.signal` → `extra.mcpReq.signal`, `extra.requestId` →
|
||||
`extra.mcpReq.id`.
|
||||
- **`setRequestHandler` / `setNotificationHandler` take method names.**
|
||||
`app.setRequestHandler(SomeRequestSchema, handler)` becomes
|
||||
`app.setRequestHandler("some/method", handler)` (pass the params schema as the
|
||||
optional extra argument for validation).
|
||||
- **Errors.** Remote JSON-RPC errors are `ProtocolError` (numeric `code`);
|
||||
local conditions are `SdkError` with a string `code`: request timeout →
|
||||
`"REQUEST_TIMEOUT"`, connection closed → `"CONNECTION_CLOSED"`. Cancelling a
|
||||
request with an `AbortSignal` also rejects with `"REQUEST_TIMEOUT"` (the
|
||||
message is the abort reason). Messages no longer carry the `MCP 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.structuredContent` is any JSON value (was
|
||||
`type: "object"`).
|
||||
- Result `_meta` documents `io.modelcontextprotocol/serverInfo` and no longer
|
||||
lists `progressToken` / `related-task` (both still pass through).
|
||||
- `McpUiHostContext.toolInfo.tool.inputSchema` is a loose object.
|
||||
- A recursive `$defs.__schema0` JSON-value definition is added.
|
||||
|
||||
## Checklist
|
||||
|
||||
1. `npm uninstall @modelcontextprotocol/sdk` and install the packages for your
|
||||
role from the table above.
|
||||
2. Replace `sdk/...` imports with the split packages (`sdk/server/mcp.js` →
|
||||
`@modelcontextprotocol/server`, `sdk/server/streamableHttp.js` →
|
||||
`NodeStreamableHTTPServerTransport` from `@modelcontextprotocol/node`,
|
||||
`sdk/server/stdio.js` → `@modelcontextprotocol/server/stdio`, `sdk/types.js`
|
||||
→ `@modelcontextprotocol/client` or `server`).
|
||||
3. Wrap raw zod shapes with `z.object({...})`.
|
||||
4. Update custom handlers to the `extra.mcpReq.*` context and method-keyed
|
||||
`setRequestHandler` calls.
|
||||
5. Replace `McpError` / numeric-code checks with `ProtocolError` / `SdkError`.
|
||||
|
|
@ -56,8 +56,8 @@ flowchart LR
|
|||
- **Host** — The chat client (e.g., Claude Desktop) that connects to servers, embeds Views in iframes, and proxies communication between them.
|
||||
- **View** — The UI running inside a sandboxed iframe. It receives tool data from the Host and can call server tools or send messages back to the chat.
|
||||
|
||||
The View's `App` and the Host's `AppBridge` both subclass the base MCP SDK's
|
||||
public `Protocol` for the iframe channel. A separate outer `Client` connects
|
||||
The View's `App` and the Host's `AppBridge` both subclass the `Protocol` class
|
||||
exported by `@modelcontextprotocol/client` for the iframe channel. A separate outer `Client` connects
|
||||
the Host to the actual MCP Server. Keeping those two connections separate
|
||||
preserves the Apps-only iframe handshake and prevents iframe capabilities from
|
||||
leaking into the server connection.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Install the dependencies you'll need:
|
|||
|
||||
```bash
|
||||
npm init -y
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.5 @modelcontextprotocol/core@2.0.0-beta.5 @modelcontextprotocol/server@2.0.0-beta.5 @modelcontextprotocol/node@2.0.0-beta.5 @modelcontextprotocol/express@2.0.0-beta.5 zod@^4.2.0 express cors
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 @modelcontextprotocol/node@^2.0.0 @modelcontextprotocol/express@^2.0.0 zod@^4.2.0 express cors
|
||||
npm install -D typescript vite vite-plugin-singlefile @types/express @types/cors @types/node tsx concurrently cross-env
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ The [`basic-host`](https://github.com/modelcontextprotocol/ext-apps/tree/main/ex
|
|||
```
|
||||
|
||||
The root install runs the package build, including type-checking the
|
||||
documentation snippets against the exact base MCP SDK beta.4 packages. Do
|
||||
documentation snippets against the pinned base MCP SDK 2.x packages. Do
|
||||
not bypass a failed build before testing the host.
|
||||
|
||||
2. Start basic-host, pointing it to your MCP server:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ To test local modifications, use this configuration (replace `~/code/ext-apps` w
|
|||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- Node.js 20+
|
||||
- Chrome, Edge, or Safari (Web Speech API support)
|
||||
|
||||
### Installation
|
||||
|
|
|
|||
|
|
@ -77,15 +77,27 @@ Before writing any code, analyze the server's existing tools and determine which
|
|||
## Step 2: Add Dependencies
|
||||
|
||||
```bash
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.5 @modelcontextprotocol/core@2.0.0-beta.5 @modelcontextprotocol/server@2.0.0-beta.5 zod@^4.2.0
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 zod@^4.2.0
|
||||
npm install -D vite vite-plugin-singlefile
|
||||
```
|
||||
|
||||
Plus framework-specific dependencies if needed (e.g., `react`, `react-dom`, `@vitejs/plugin-react` for React).
|
||||
Plus framework-specific dependencies if needed (e.g., `react`, `react-dom`, `@vitejs/plugin-react` for React), and `@modelcontextprotocol/node` / `@modelcontextprotocol/express` if the server uses HTTP transports.
|
||||
|
||||
Use the exact base MCP SDK prerelease required by ext-apps. Existing servers
|
||||
that still import `@modelcontextprotocol/sdk` v1 must migrate those imports and
|
||||
handler schemas before adding the App integration.
|
||||
ext-apps 2.x requires the split base MCP SDK packages at `^2.0.0`
|
||||
(`@modelcontextprotocol/core` comes in transitively). Existing servers that
|
||||
still import `@modelcontextprotocol/sdk` v1 must migrate those imports and
|
||||
handler schemas before adding the App integration:
|
||||
|
||||
| SDK v1 (`@modelcontextprotocol/sdk`) | SDK v2 |
|
||||
|---|---|
|
||||
| `sdk/server/mcp.js` (`McpServer`) | `@modelcontextprotocol/server` |
|
||||
| `sdk/server/streamableHttp.js` (`StreamableHTTPServerTransport`) | `NodeStreamableHTTPServerTransport` from `@modelcontextprotocol/node` |
|
||||
| Express wiring by hand | `createMcpExpressApp` from `@modelcontextprotocol/express` |
|
||||
| `sdk/server/stdio.js` | `@modelcontextprotocol/server/stdio` |
|
||||
| `sdk/types.js` (types, schemas) | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
|
||||
| Raw zod shapes: `inputSchema: { q: z.string() }` | `inputSchema: z.object({ q: z.string() })` |
|
||||
| `extra.signal` in tool callbacks | `extra.mcpReq.signal` |
|
||||
| `setRequestHandler(SomeRequestSchema, handler)` | `setRequestHandler("some/method", handler)` |
|
||||
|
||||
## Step 3: Set Up the Build Pipeline
|
||||
|
||||
|
|
|
|||
|
|
@ -115,12 +115,14 @@ Create a new MCP server with tool and resource registration. This wraps the exis
|
|||
### Dependencies
|
||||
|
||||
```bash
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.5 @modelcontextprotocol/core@2.0.0-beta.5 @modelcontextprotocol/server@2.0.0-beta.5 zod@^4.2.0
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 zod@^4.2.0
|
||||
npm install -D tsx vite vite-plugin-singlefile
|
||||
```
|
||||
|
||||
Use `npm install` with the exact base MCP SDK prerelease required by ext-apps.
|
||||
Do not substitute unpublished local packages or guess a different prerelease.
|
||||
Use `npm install` so the package manager resolves versions; ext-apps 2.x needs
|
||||
the split base MCP SDK packages at `^2.0.0` (`@modelcontextprotocol/core` comes
|
||||
in transitively). Do not add the legacy `@modelcontextprotocol/sdk` v1 package
|
||||
or substitute unpublished local packages.
|
||||
|
||||
### Server Code
|
||||
|
||||
|
|
|
|||
|
|
@ -110,12 +110,14 @@ See `/tmp/mcp-ext-apps/docs/patterns.md` for detailed recipes:
|
|||
**Always** use `npm install` to add dependencies rather than manually writing version numbers:
|
||||
|
||||
```bash
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.5 @modelcontextprotocol/core@2.0.0-beta.5 @modelcontextprotocol/server@2.0.0-beta.5 @modelcontextprotocol/node@2.0.0-beta.5 @modelcontextprotocol/express@2.0.0-beta.5 zod@^4.2.0 express cors
|
||||
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 @modelcontextprotocol/node@^2.0.0 @modelcontextprotocol/express@^2.0.0 zod@^4.2.0 express cors
|
||||
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors
|
||||
```
|
||||
|
||||
Use the exact base MCP SDK prerelease required by ext-apps. Do not substitute
|
||||
unpublished local packages or guess a different prerelease.
|
||||
ext-apps 2.x requires the split base MCP SDK packages (`@modelcontextprotocol/client`,
|
||||
`server`, `node`, `express`) at `^2.0.0`; `@modelcontextprotocol/core` comes in
|
||||
transitively. Do not add the legacy `@modelcontextprotocol/sdk` v1 package or
|
||||
substitute unpublished local packages.
|
||||
|
||||
### TypeScript Server Execution
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const config = {
|
|||
"docs/authorization.md",
|
||||
"docs/csp-cors.md",
|
||||
"docs/migrate_from_openai_apps.md",
|
||||
"docs/migrate-to-2.md",
|
||||
],
|
||||
entryPoints: [
|
||||
"src/server/index.ts",
|
||||
|
|
@ -43,6 +44,7 @@ const config = {
|
|||
ResponseCacheStore: BASE_SDK_DOCS,
|
||||
SdkError: BASE_SDK_DOCS,
|
||||
"SdkErrorCode.MethodNotSupportedByProtocolVersion": BASE_SDK_DOCS,
|
||||
StandardJSONSchemaV1: BASE_SDK_DOCS,
|
||||
"SdkErrorCode.UnsupportedResultType": BASE_SDK_DOCS,
|
||||
"__type.enforceStrictCapabilities": BASE_SDK_DOCS,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue