From fa1274490873f869c9a084e1abb9cf3031d288c7 Mon Sep 17 00:00:00 2001
From: Aqil Aziz
Date: Wed, 17 Jun 2026 22:51:57 +0700
Subject: [PATCH 01/45] docs: fix map-server readme and code of conduct links
(#657)
---
CONTRIBUTING.md | 2 +-
examples/map-server/README.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6592106..e28dcd1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -502,7 +502,7 @@ Alternatively, use the [workflow dispatch](https://github.com/modelcontextprotoc
## Code of Conduct
-This project follows our [Code of Conduct](CODE_OF_CONDUCT.md). Please review it before contributing.
+This project follows our [Code of Conduct](https://github.com/modelcontextprotocol/.github/blob/main/CODE_OF_CONDUCT.md). Please review it before contributing.
## Reporting Issues
diff --git a/examples/map-server/README.md b/examples/map-server/README.md
index 4c4de5f..e1e044a 100644
--- a/examples/map-server/README.md
+++ b/examples/map-server/README.md
@@ -122,7 +122,7 @@ Vanilla TypeScript app that:
- [`server.ts`](server.ts) - MCP server with geocode and show-map tools
- [`mcp-app.html`](mcp-app.html) / [`src/mcp-app.ts`](src/mcp-app.ts) - CesiumJS globe UI
-- [`server-utils.ts`](server-utils.ts) - HTTP server utilities
+- [`main.ts`](main.ts) - HTTP and stdio server utilities
## Notes
From ea8775dcb5534cc8977c5137fee5572b0cd94f23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ensar=20G=C3=B6k?=
<116498667+ensargx@users.noreply.github.com>
Date: Tue, 7 Jul 2026 20:43:37 +0300
Subject: [PATCH 02/45] docs: API Docs link for ext-apps/server (#697)
Updated API documentation link for ext-apps/server.
The link `/server.html` does not exists.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 7348e15..d0677ef 100644
--- a/README.md
+++ b/README.md
@@ -139,7 +139,7 @@ UI metadata.
| `@modelcontextprotocol/ext-apps` | Build interactive Views (App class, PostMessageTransport) | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/app.html) |
| `@modelcontextprotocol/ext-apps/react` | React hooks for Views (useApp, useHostStyles, etc.) | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/_modelcontextprotocol_ext-apps_react.html) |
| `@modelcontextprotocol/ext-apps/app-bridge` | Embed and communicate with Views in your chat client | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/app-bridge.html) |
-| `@modelcontextprotocol/ext-apps/server` | Register tools and resources on your MCP server | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/server.html) |
+| `@modelcontextprotocol/ext-apps/server` | Register tools and resources on your MCP server | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/server-helpers.html) |
There's no _supported_ host implementation in this repo (beyond the
[examples/basic-host](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host)
From f0d9582eaa63faeec754c8b026ec4a9b3f626cfe Mon Sep 17 00:00:00 2001
From: Cameron Yick
Date: Tue, 7 Jul 2026 14:02:07 -0400
Subject: [PATCH 03/45] spec: add missing HostCapabilities fields (#653)
---
specification/draft/apps.mdx | 39 ++++++++++++++++++++++++++++--------
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/specification/draft/apps.mdx b/specification/draft/apps.mdx
index 1a14d3f..96c8286 100644
--- a/specification/draft/apps.mdx
+++ b/specification/draft/apps.mdx
@@ -659,6 +659,22 @@ Example:
They describe the features and capabilities that the Host supports.
```typescript
+/** Content block modalities that the host supports for a given capability. */
+interface SupportedContentBlockModalities {
+ /** Host supports text content blocks. */
+ text?: {};
+ /** Host supports image content blocks. */
+ image?: {};
+ /** Host supports audio content blocks. */
+ audio?: {};
+ /** Host supports resource content blocks. */
+ resource?: {};
+ /** Host supports resource link content blocks. */
+ resourceLink?: {};
+ /** Host supports structured content. */
+ structuredContent?: {};
+}
+
interface HostCapabilities {
/** Experimental features (structure TBD). */
experimental?: {};
@@ -678,14 +694,6 @@ interface HostCapabilities {
};
/** Host accepts log messages. */
logging?: {};
- /**
- * Host supports LLM sampling (sampling/createMessage) from the view.
- * Mirrors MCP ClientCapabilities.sampling so hosts can pass it through.
- */
- sampling?: {
- /** Host supports tool use via `tools` and `toolChoice` params (SEP-1577). */
- tools?: {};
- };
/** Sandbox configuration applied by the host. */
sandbox?: {
/** Permissions granted by the host (camera, microphone, geolocation, clipboard-write). */
@@ -707,6 +715,21 @@ interface HostCapabilities {
baseUriDomains?: string[];
};
};
+ /**
+ * Host accepts context updates (ui/update-model-context) to be included in
+ * the model's context for future turns.
+ */
+ updateModelContext?: SupportedContentBlockModalities;
+ /** Host supports receiving content messages (ui/message) from the view. */
+ message?: SupportedContentBlockModalities;
+ /**
+ * Host supports LLM sampling (sampling/createMessage) from the view.
+ * Mirrors MCP ClientCapabilities.sampling so hosts can pass it through.
+ */
+ sampling?: {
+ /** Host supports tool use via `tools` and `toolChoice` params (SEP-1577). */
+ tools?: {};
+ };
}
```
From cd969dbc312923a0a407ed76f8679666be45e801 Mon Sep 17 00:00:00 2001
From: Andrew Khadder <54488379+khandrew1@users.noreply.github.com>
Date: Tue, 7 Jul 2026 11:05:17 -0700
Subject: [PATCH 04/45] docs: add mcp-use inspector badge to supported clients
(#650)
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index d0677ef..506b255 100644
--- a/README.md
+++ b/README.md
@@ -89,6 +89,7 @@ it will guide you through the rest.
+
> [!NOTE]
From cf87f2a2c2581b2bc45ff4848aac9fa7e106a576 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Tue, 7 Jul 2026 21:29:16 +0300
Subject: [PATCH 05/45] ci: fix README prettier build failure (#698)
* Initial plan
* fix: apply Prettier formatting to README table row
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 506b255..2fd89ff 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,7 @@ UI metadata.
| `@modelcontextprotocol/ext-apps` | Build interactive Views (App class, PostMessageTransport) | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/app.html) |
| `@modelcontextprotocol/ext-apps/react` | React hooks for Views (useApp, useHostStyles, etc.) | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/_modelcontextprotocol_ext-apps_react.html) |
| `@modelcontextprotocol/ext-apps/app-bridge` | Embed and communicate with Views in your chat client | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/app-bridge.html) |
-| `@modelcontextprotocol/ext-apps/server` | Register tools and resources on your MCP server | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/server-helpers.html) |
+| `@modelcontextprotocol/ext-apps/server` | Register tools and resources on your MCP server | [API Docs →](https://apps.extensions.modelcontextprotocol.io/api/modules/server-helpers.html) |
There's no _supported_ host implementation in this repo (beyond the
[examples/basic-host](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host)
From b383847bf2c7f4f5fa37e3bd054205f71618e035 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 13:35:51 -0700
Subject: [PATCH 06/45] chore: prepare SDK v2 dependencies
---
examples/basic-server-preact/package.json | 2 +
examples/basic-server-react/package.json | 2 +
examples/basic-server-solid/package.json | 2 +
examples/basic-server-svelte/package.json | 2 +
examples/basic-server-vanillajs/package.json | 2 +
examples/basic-server-vue/package.json | 2 +
examples/budget-allocator-server/package.json | 2 +
examples/cohort-heatmap-server/package.json | 2 +
.../customer-segmentation-server/package.json | 2 +
examples/debug-server/package.json | 2 +
examples/integration-server/package.json | 2 +
examples/lazy-auth-server/package.json | 1 +
examples/map-server/package.json | 2 +
examples/pdf-server/package.json | 2 +
examples/quickstart/package.json | 2 +
examples/scenario-modeler-server/package.json | 2 +
examples/shadertoy-server/package.json | 2 +
examples/sheet-music-server/package.json | 2 +
examples/system-monitor-server/package.json | 2 +
examples/threejs-server/package.json | 2 +
examples/transcript-server/package.json | 2 +
examples/video-resource-server/package.json | 2 +
examples/wiki-explorer-server/package.json | 2 +
package-lock.json | 537 +++++-------------
package.json | 10 +-
25 files changed, 187 insertions(+), 405 deletions(-)
diff --git a/examples/basic-server-preact/package.json b/examples/basic-server-preact/package.json
index 5127202..1a63232 100644
--- a/examples/basic-server-preact/package.json
+++ b/examples/basic-server-preact/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/basic-server-react/package.json b/examples/basic-server-react/package.json
index e4d1233..821fc96 100644
--- a/examples/basic-server-react/package.json
+++ b/examples/basic-server-react/package.json
@@ -35,6 +35,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/basic-server-solid/package.json b/examples/basic-server-solid/package.json
index 8f75ac8..997bc60 100644
--- a/examples/basic-server-solid/package.json
+++ b/examples/basic-server-solid/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/basic-server-svelte/package.json b/examples/basic-server-svelte/package.json
index f877bf7..e83772f 100644
--- a/examples/basic-server-svelte/package.json
+++ b/examples/basic-server-svelte/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/basic-server-vanillajs/package.json b/examples/basic-server-vanillajs/package.json
index 5d47f2c..64e1758 100644
--- a/examples/basic-server-vanillajs/package.json
+++ b/examples/basic-server-vanillajs/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/basic-server-vue/package.json b/examples/basic-server-vue/package.json
index d27ddc9..e4cd0b4 100644
--- a/examples/basic-server-vue/package.json
+++ b/examples/basic-server-vue/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/budget-allocator-server/package.json b/examples/budget-allocator-server/package.json
index 19a1d25..8af1a6c 100644
--- a/examples/budget-allocator-server/package.json
+++ b/examples/budget-allocator-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
diff --git a/examples/cohort-heatmap-server/package.json b/examples/cohort-heatmap-server/package.json
index 8d1268b..99e9d9f 100644
--- a/examples/cohort-heatmap-server/package.json
+++ b/examples/cohort-heatmap-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/customer-segmentation-server/package.json b/examples/customer-segmentation-server/package.json
index 4511de9..59e3eb1 100644
--- a/examples/customer-segmentation-server/package.json
+++ b/examples/customer-segmentation-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
diff --git a/examples/debug-server/package.json b/examples/debug-server/package.json
index 3417a8f..02e9fbf 100644
--- a/examples/debug-server/package.json
+++ b/examples/debug-server/package.json
@@ -35,6 +35,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"zod": "^4.1.13"
},
diff --git a/examples/integration-server/package.json b/examples/integration-server/package.json
index f6715a4..3f9d8bb 100644
--- a/examples/integration-server/package.json
+++ b/examples/integration-server/package.json
@@ -16,6 +16,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/lazy-auth-server/package.json b/examples/lazy-auth-server/package.json
index f3ed6cd..086f20a 100644
--- a/examples/lazy-auth-server/package.json
+++ b/examples/lazy-auth-server/package.json
@@ -23,6 +23,7 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/map-server/package.json b/examples/map-server/package.json
index 5dc23fe..b0c629a 100644
--- a/examples/map-server/package.json
+++ b/examples/map-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/pdf-server/package.json b/examples/pdf-server/package.json
index 4d960f1..aeb52c7 100644
--- a/examples/pdf-server/package.json
+++ b/examples/pdf-server/package.json
@@ -27,6 +27,8 @@
"dependencies": {
"@cantoo/pdf-lib": "^2.6.5",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/quickstart/package.json b/examples/quickstart/package.json
index 99948cc..1003637 100644
--- a/examples/quickstart/package.json
+++ b/examples/quickstart/package.json
@@ -16,6 +16,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0"
diff --git a/examples/scenario-modeler-server/package.json b/examples/scenario-modeler-server/package.json
index aa1e668..a7e8a9a 100644
--- a/examples/scenario-modeler-server/package.json
+++ b/examples/scenario-modeler-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
diff --git a/examples/shadertoy-server/package.json b/examples/shadertoy-server/package.json
index ccf15a4..0c27501 100644
--- a/examples/shadertoy-server/package.json
+++ b/examples/shadertoy-server/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/sheet-music-server/package.json b/examples/sheet-music-server/package.json
index ca9fa90..6cf175a 100644
--- a/examples/sheet-music-server/package.json
+++ b/examples/sheet-music-server/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"abcjs": "^6.4.4",
"cors": "^2.8.5",
diff --git a/examples/system-monitor-server/package.json b/examples/system-monitor-server/package.json
index 12e8cea..760d07f 100644
--- a/examples/system-monitor-server/package.json
+++ b/examples/system-monitor-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
diff --git a/examples/threejs-server/package.json b/examples/threejs-server/package.json
index cfb5686..9dda288 100644
--- a/examples/threejs-server/package.json
+++ b/examples/threejs-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/transcript-server/package.json b/examples/transcript-server/package.json
index dcba3d7..ce5b737 100644
--- a/examples/transcript-server/package.json
+++ b/examples/transcript-server/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/video-resource-server/package.json b/examples/video-resource-server/package.json
index b0d04af..605b8de 100644
--- a/examples/video-resource-server/package.json
+++ b/examples/video-resource-server/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/wiki-explorer-server/package.json b/examples/wiki-explorer-server/package.json
index fe511ad..62f1de8 100644
--- a/examples/wiki-explorer-server/package.json
+++ b/examples/wiki-explorer-server/package.json
@@ -27,6 +27,8 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cheerio": "^1.0.0",
"cors": "^2.8.5",
diff --git a/package-lock.json b/package-lock.json
index 29e9058..5514bf1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,10 @@
},
"devDependencies": {
"@boneskull/typedoc-plugin-mermaid": "^0.2.0",
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"@playwright/test": "1.57.0",
"@types/bun": "^1.3.2",
"@types/node": "20.19.27",
@@ -44,16 +47,19 @@
"typedoc": "^0.28.14",
"typedoc-github-theme": "^0.4.0",
"typescript": "^5.9.3",
- "zod": "^4.1.13"
+ "zod": "^4.2.0"
},
"engines": {
"node": ">=20"
},
"peerDependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "zod": "^3.25.0 || ^4.0.0"
+ "zod": "^4.2.0"
},
"peerDependenciesMeta": {
"react": {
@@ -89,29 +95,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-host/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-host/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-preact": {
"name": "@modelcontextprotocol/server-basic-preact",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -133,29 +124,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-server-preact/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-preact/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-react": {
"name": "@modelcontextprotocol/server-basic-react",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -180,29 +156,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-server-react/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-react/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-solid": {
"name": "@modelcontextprotocol/server-basic-solid",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -224,29 +185,14 @@
"vite-plugin-solid": "^2.11.12"
}
},
- "examples/basic-server-solid/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-solid/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-svelte": {
"name": "@modelcontextprotocol/server-basic-svelte",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -268,29 +214,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-server-svelte/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-svelte/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-vanillajs": {
"name": "@modelcontextprotocol/server-basic-vanillajs",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -310,29 +241,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-server-vanillajs/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-vanillajs/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/basic-server-vue": {
"name": "@modelcontextprotocol/server-basic-vue",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -354,29 +270,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/basic-server-vue/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/basic-server-vue/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/budget-allocator-server": {
"name": "@modelcontextprotocol/server-budget-allocator",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
@@ -397,29 +298,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/budget-allocator-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/budget-allocator-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/cohort-heatmap-server": {
"name": "@modelcontextprotocol/server-cohort-heatmap",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -444,29 +330,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/cohort-heatmap-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/cohort-heatmap-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/customer-segmentation-server": {
"name": "@modelcontextprotocol/server-customer-segmentation",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
@@ -487,29 +358,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/customer-segmentation-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/customer-segmentation-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/debug-server": {
"name": "@modelcontextprotocol/server-debug",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"zod": "^4.1.13"
},
@@ -529,27 +385,12 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/debug-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/debug-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/integration-server": {
"version": "1.7.4",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -573,29 +414,13 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/integration-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/integration-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/lazy-auth-server": {
"name": "@modelcontextprotocol/server-lazy-auth",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -615,29 +440,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/lazy-auth-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/lazy-auth-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/map-server": {
"name": "@modelcontextprotocol/server-map",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -657,30 +467,15 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/map-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/map-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/pdf-server": {
"name": "@modelcontextprotocol/server-pdf",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
"@cantoo/pdf-lib": "^2.6.5",
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -701,23 +496,6 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/pdf-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/pdf-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/qr-server": {
"name": "@modelcontextprotocol/server-qr",
"version": "1.7.4",
@@ -731,7 +509,9 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0"
@@ -748,16 +528,6 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/quickstart/node_modules/@types/node": {
- "version": "22.19.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.5.tgz",
- "integrity": "sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.21.0"
- }
- },
"examples/say-server": {
"name": "@modelcontextprotocol/server-say",
"version": "1.7.4",
@@ -772,7 +542,9 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
@@ -798,29 +570,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/scenario-modeler-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/scenario-modeler-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/shadertoy-server": {
"name": "@modelcontextprotocol/server-shadertoy",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -840,29 +597,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/shadertoy-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/shadertoy-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/sheet-music-server": {
"name": "@modelcontextprotocol/server-sheet-music",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"abcjs": "^6.4.4",
"cors": "^2.8.5",
@@ -883,29 +625,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/sheet-music-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/sheet-music-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/system-monitor-server": {
"name": "@modelcontextprotocol/server-system-monitor",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
@@ -927,29 +654,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/system-monitor-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/system-monitor-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/threejs-server": {
"name": "@modelcontextprotocol/server-threejs",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -976,29 +688,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/threejs-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/threejs-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/transcript-server": {
"name": "@modelcontextprotocol/server-transcript",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -1019,29 +716,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/transcript-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/transcript-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/video-resource-server": {
"name": "@modelcontextprotocol/server-video-resource",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -1061,29 +743,14 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/video-resource-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/video-resource-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"examples/wiki-explorer-server": {
"name": "@modelcontextprotocol/server-wiki-explorer",
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
+ "@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"cheerio": "^1.0.0",
"cors": "^2.8.5",
@@ -1105,23 +772,6 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
- "examples/wiki-explorer-server/node_modules/@types/node": {
- "version": "22.10.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
- "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
- "examples/wiki-explorer-server/node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@babel/code-frame": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
@@ -2576,6 +2226,53 @@
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
"license": "MIT"
},
+ "node_modules/@modelcontextprotocol/client": {
+ "version": "2.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0-beta.4.tgz",
+ "integrity": "sha512-VNHA/UXDk7mCpVl+jOg5B4WMRRD2OEl+it360Lhi6HiCbrIB2f6pZ0cqSDKXQVUtZvqnhdQHzZAM9h8EKWhq/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
+ "cross-spawn": "^7.0.5",
+ "eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
+ "jose": "^6.1.3",
+ "pkce-challenge": "^5.0.0",
+ "zod": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@modelcontextprotocol/core": {
+ "version": "2.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0-beta.4.tgz",
+ "integrity": "sha512-nsMXd4wQBKzmph6r+WOhum+mXjDYljTAqwY/XUg3hLtvNOQ8+JVqBSJOVCMJvx9lXhTpTOPrGZ3BuNiaNPjSvg==",
+ "license": "MIT",
+ "dependencies": {
+ "zod": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@modelcontextprotocol/express": {
+ "version": "2.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/express/-/express-2.0.0-beta.4.tgz",
+ "integrity": "sha512-7hI8bEomz6rMn8sKYRVIZgQJsrWIjIS9WiPyIp3X2pMyLSCC7hB5km0kg+9SygWygTIRnPfte0tXevRB3mXEHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cors": "^2.8.5"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "@modelcontextprotocol/server": "^2.0.0-beta.4",
+ "express": "^4.18.0 || ^5.0.0"
+ }
+ },
"node_modules/@modelcontextprotocol/ext-apps": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/ext-apps/-/ext-apps-1.7.1.tgz",
@@ -2609,6 +2306,27 @@
"resolved": "examples/basic-host",
"link": true
},
+ "node_modules/@modelcontextprotocol/node": {
+ "version": "2.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/node/-/node-2.0.0-beta.4.tgz",
+ "integrity": "sha512-OqbrRVNYNfLxBB2BRkP5oIHKHa0IPHluMbaLgw7YCRKcj5be9ExzyWFJY3KVMb+1F2AVn+0SRoH0XKcNzh3HYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@hono/node-server": "^1.19.9"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "@modelcontextprotocol/server": "^2.0.0-beta.4",
+ "hono": "^4.11.4"
+ },
+ "peerDependenciesMeta": {
+ "hono": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@modelcontextprotocol/quickstart": {
"resolved": "examples/quickstart",
"link": true
@@ -2653,6 +2371,19 @@
}
}
},
+ "node_modules/@modelcontextprotocol/server": {
+ "version": "2.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0-beta.4.tgz",
+ "integrity": "sha512-pjMZcNEt1dOq0aJCcY3b7w1Ayh+qmQN2xlfTELcGV9yiAjEGIczBPBLWWW0k0zzo5T8kiv15jtKPsWeHGxLvLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
+ "zod": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/@modelcontextprotocol/server-basic-preact": {
"resolved": "examples/basic-server-preact",
"link": true
diff --git a/package.json b/package.json
index 8c6ead5..35bcdf0 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,10 @@
"author": "Olivier Chafik",
"devDependencies": {
"@boneskull/typedoc-plugin-mermaid": "^0.2.0",
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"@playwright/test": "1.57.0",
"@types/bun": "^1.3.2",
"@types/node": "20.19.27",
@@ -105,13 +108,16 @@
"typedoc": "^0.28.14",
"typedoc-github-theme": "^0.4.0",
"typescript": "^5.9.3",
- "zod": "^4.1.13"
+ "zod": "^4.2.0"
},
"peerDependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
+ "@modelcontextprotocol/core": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "zod": "^3.25.0 || ^4.0.0"
+ "zod": "^4.2.0"
},
"peerDependenciesMeta": {
"react": {
From 209cfc62413b7eea46c127ddd756ce58bd2da095 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 13:49:10 -0700
Subject: [PATCH 07/45] refactor: compose protocol-neutral event dispatch
---
src/app-bridge.test.ts | 2 +-
src/app-bridge.ts | 120 ++++++++++++++++---
src/app.ts | 139 +++++++++++++++++-----
src/events.test.ts | 82 +++++++++++++
src/events.ts | 261 ++++++-----------------------------------
typedoc.config.mjs | 2 +-
6 files changed, 335 insertions(+), 271 deletions(-)
create mode 100644 src/events.test.ts
diff --git a/src/app-bridge.test.ts b/src/app-bridge.test.ts
index a4fe1de..7adbb16 100644
--- a/src/app-bridge.test.ts
+++ b/src/app-bridge.test.ts
@@ -2713,7 +2713,7 @@ describe("isToolVisibilityAppOnly", () => {
expect(a).toEqual([]);
});
- it("App.onEventDispatch merges hostcontext before listeners fire", async () => {
+ it("App merges hostcontext before listeners fire", async () => {
let seen: unknown;
app.addEventListener("hostcontextchanged", () => {
seen = app.getHostContext();
diff --git a/src/app-bridge.ts b/src/app-bridge.ts
index 23383c4..18d7671 100644
--- a/src/app-bridge.ts
+++ b/src/app-bridge.ts
@@ -47,7 +47,10 @@ import {
ProtocolOptions,
RequestOptions,
} from "@modelcontextprotocol/sdk/shared/protocol.js";
-import { ProtocolWithEvents } from "./events";
+import { EventDispatcher } from "./events";
+import type { ZodLiteral, ZodObject } from "zod/v4";
+
+type MethodSchema = ZodObject<{ method: ZodLiteral }>;
import {
type AppNotification,
@@ -303,16 +306,36 @@ export type AppBridgeEventMap = {
* await bridge.connect(transport);
* ```
*/
-export class AppBridge extends ProtocolWithEvents<
- AppRequest,
- AppNotification,
- AppResult,
- AppBridgeEventMap
-> {
+export class AppBridge extends Protocol {
private _appCapabilities?: McpUiAppCapabilities;
private _hostContext: McpUiHostContext = {};
private _appInfo?: Implementation;
private _initializedReceived = false;
+ private readonly _registeredMethods = new Set();
+ private readonly _registeredEvents = new Set();
+ private readonly _events = new EventDispatcher();
+
+ // ProtocolWithEvents previously owned these registration guards. Keep them
+ // on AppBridge to preserve the existing double-registration behavior while
+ // event fan-out moves to protocol-independent composition. Arrow-function
+ // fields let Protocol's constructor run before the guards initialize.
+ override setRequestHandler: Protocol<
+ AppRequest,
+ AppNotification,
+ AppResult
+ >["setRequestHandler"] = (schema, handler) => {
+ this._assertMethodNotRegistered(schema, "setRequestHandler");
+ super.setRequestHandler(schema, handler);
+ };
+
+ override setNotificationHandler: Protocol<
+ AppRequest,
+ AppNotification,
+ AppResult
+ >["setNotificationHandler"] = (schema, handler) => {
+ this._assertMethodNotRegistered(schema, "setNotificationHandler");
+ super.setNotificationHandler(schema, handler);
+ };
/**
* Wrap every handler registered via `replaceRequestHandler` with a check
@@ -324,13 +347,14 @@ export class AppBridge extends ProtocolWithEvents<
*
* @see {@link https://github.com/anthropics/claude-ai-mcp/issues/149 claude-ai-mcp#149}
*/
- private _baseReplaceRequestHandler = this.replaceRequestHandler;
- protected override replaceRequestHandler: Protocol<
+ protected replaceRequestHandler: Protocol<
AppRequest,
AppNotification,
AppResult
>["setRequestHandler"] = (schema, handler) => {
- this._baseReplaceRequestHandler(schema, (request, extra) => {
+ const method = (schema as MethodSchema).shape.method.value;
+ this._registeredMethods.add(method);
+ super.setRequestHandler(schema, (request, extra) => {
if (!this._initializedReceived) {
console.warn(
`[ext-apps] AppBridge received '${request.method}' before ` +
@@ -343,7 +367,9 @@ export class AppBridge extends ProtocolWithEvents<
});
};
- protected readonly eventSchemas = {
+ private readonly eventSchemas: {
+ [K in keyof AppBridgeEventMap]: MethodSchema;
+ } = {
sizechange: McpUiSizeChangedNotificationSchema,
sandboxready: McpUiSandboxProxyReadyNotificationSchema,
initialized: McpUiInitializedNotificationSchema,
@@ -351,6 +377,74 @@ export class AppBridge extends ProtocolWithEvents<
loggingmessage: LoggingMessageNotificationSchema,
};
+ protected setEventHandler(
+ event: K,
+ handler: ((params: AppBridgeEventMap[K]) => void) | undefined,
+ ): void {
+ this._ensureEventSlot(event);
+ this._events.setHandler(event, handler);
+ }
+
+ protected getEventHandler(
+ event: K,
+ ): ((params: AppBridgeEventMap[K]) => void) | undefined {
+ return this._events.getHandler(event);
+ }
+
+ addEventListener(
+ event: K,
+ handler: (params: AppBridgeEventMap[K]) => void,
+ ): void {
+ this._ensureEventSlot(event);
+ this._events.addEventListener(event, handler);
+ }
+
+ removeEventListener(
+ event: K,
+ handler: (params: AppBridgeEventMap[K]) => void,
+ ): void {
+ this._events.removeEventListener(event, handler);
+ }
+
+ private _ensureEventSlot(
+ event: K,
+ ): void {
+ if (this._registeredEvents.has(event)) return;
+ const schema = this.eventSchemas[event];
+ if (!schema) throw new Error(`Unknown event: ${String(event)}`);
+ this.setNotificationHandler(schema, (notification) => {
+ const params = (notification as { params: AppBridgeEventMap[K] }).params;
+ if (event === "initialized") this._initializedReceived = true;
+ this._events.dispatch(event, params);
+ });
+ this._registeredEvents.add(event);
+ }
+
+ protected warnIfRequestHandlerReplaced(
+ name: string,
+ previous: unknown,
+ next: unknown,
+ ): void {
+ if (previous && next) {
+ console.warn(
+ `[MCP Apps] ${name} handler replaced. ` +
+ `Previous handler will no longer be called.`,
+ );
+ }
+ }
+
+ private _assertMethodNotRegistered(schema: unknown, via: string): void {
+ const method = (schema as MethodSchema).shape.method.value;
+ if (this._registeredMethods.has(method)) {
+ throw new Error(
+ `Handler for "${method}" already registered (via ${via}). ` +
+ `Use addEventListener() to attach multiple listeners, ` +
+ `or the on* setter for replace semantics.`,
+ );
+ }
+ this._registeredMethods.add(method);
+ }
+
/**
* Create a new AppBridge instance.
*
@@ -392,9 +486,7 @@ export class AppBridge extends ProtocolWithEvents<
) {
super(options);
- this.addEventListener("initialized", () => {
- this._initializedReceived = true;
- });
+ this._ensureEventSlot("initialized");
this._hostContext = options?.hostContext || {};
diff --git a/src/app.ts b/src/app.ts
index adfad5c..c586c31 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,6 +1,7 @@
import {
type RequestOptions,
mergeCapabilities,
+ Protocol,
ProtocolOptions,
} from "@modelcontextprotocol/sdk/shared/protocol.js";
@@ -32,8 +33,8 @@ import {
ToolListChangedNotification,
} from "@modelcontextprotocol/sdk/types.js";
import { AppNotification, AppRequest, AppResult } from "./types";
-import { ProtocolWithEvents } from "./events";
-export { ProtocolWithEvents };
+import { EventDispatcher } from "./events";
+export { EventDispatcher } from "./events";
import { PostMessageTransport } from "./message-transport";
import {
LATEST_PROTOCOL_VERSION,
@@ -74,7 +75,9 @@ import {
standardSchemaToJsonSchema,
validateStandardSchema,
} from "./standard-schema";
-import { z } from "zod/v4";
+import { z, type ZodLiteral, type ZodObject } from "zod/v4";
+
+type MethodSchema = ZodObject<{ method: ZodLiteral }>;
export type {
StandardSchemaV1,
@@ -271,9 +274,9 @@ export type RegisteredAppTool = {
/**
* Maps DOM-style event names to their notification `params` types.
*
- * Used by {@link App `App`} (which extends {@link ProtocolWithEvents `ProtocolWithEvents`})
- * to provide type-safe `addEventListener` / `removeEventListener` and
- * singular `on*` handler support.
+ * Used by {@link App `App`} and its composed {@link EventDispatcher} to
+ * provide type-safe `addEventListener` / `removeEventListener` and singular
+ * `on*` handler support.
*/
export type AppEventMap = {
toolinput: McpUiToolInputNotification["params"];
@@ -304,16 +307,14 @@ export type AppEventMap = {
* 3. **Interactive**: Send requests, receive notifications, call tools
* 4. **Teardown**: Host sends teardown request before unmounting
*
- * ## Inherited Methods
+ * ## Protocol and event methods
*
- * As a subclass of {@link ProtocolWithEvents `ProtocolWithEvents`}, `App` inherits:
+ * As a subclass of the MCP SDK's `Protocol`, `App` provides:
* - `setRequestHandler()` - Register handlers for requests from host
* - `setNotificationHandler()` - Register handlers for notifications from host
* - `addEventListener()` - Append a listener for a notification event (multi-listener)
* - `removeEventListener()` - Remove a previously added listener
*
- * @see {@link ProtocolWithEvents `ProtocolWithEvents`} for the DOM-model event system
- *
* ## Notification Setters (DOM-model `on*` handlers)
*
* For common notifications, the `App` class provides getter/setter properties
@@ -342,17 +343,37 @@ export type AppEventMap = {
* await app.connect();
* ```
*/
-export class App extends ProtocolWithEvents<
- AppRequest,
- AppNotification,
- AppResult,
- AppEventMap
-> {
+export class App extends Protocol {
private _hostCapabilities?: McpUiHostCapabilities;
private _hostInfo?: Implementation;
private _hostContext?: McpUiHostContext;
private _registeredTools: { [name: string]: RegisteredAppTool } = {};
private _initializedSent = false;
+ private readonly _registeredMethods = new Set();
+ private readonly _registeredEvents = new Set();
+ private readonly _events = new EventDispatcher();
+
+ // ProtocolWithEvents previously owned these registration guards. Keep them
+ // on App to preserve the existing double-registration behavior while event
+ // fan-out moves to protocol-independent composition. Arrow-function fields
+ // ensure Protocol's constructor uses its own methods before the guards init.
+ override setRequestHandler: Protocol<
+ AppRequest,
+ AppNotification,
+ AppResult
+ >["setRequestHandler"] = (schema, handler) => {
+ this._assertMethodNotRegistered(schema, "setRequestHandler");
+ super.setRequestHandler(schema, handler);
+ };
+
+ override setNotificationHandler: Protocol<
+ AppRequest,
+ AppNotification,
+ AppResult
+ >["setNotificationHandler"] = (schema, handler) => {
+ this._assertMethodNotRegistered(schema, "setNotificationHandler");
+ super.setNotificationHandler(schema, handler);
+ };
/**
* Warn if a host-bound method is called before {@link connect `connect`} has
@@ -378,7 +399,9 @@ export class App extends ProtocolWithEvents<
console.warn(`${msg}. This will throw in a future release.`);
}
- protected readonly eventSchemas = {
+ private readonly eventSchemas: {
+ [K in keyof AppEventMap]: MethodSchema;
+ } = {
toolinput: McpUiToolInputNotificationSchema,
toolinputpartial: McpUiToolInputPartialNotificationSchema,
toolresult: McpUiToolResultNotificationSchema,
@@ -427,31 +450,86 @@ export class App extends ProtocolWithEvents<
console.warn(msg);
}
- protected override setEventHandler(
+ protected setEventHandler(
event: K,
handler: ((params: AppEventMap[K]) => void) | undefined,
): void {
if (handler) this._assertHandlerTiming(event);
- super.setEventHandler(event, handler);
+ this._ensureEventSlot(event);
+ this._events.setHandler(event, handler);
}
- override addEventListener(
+ addEventListener(
event: K,
handler: (params: AppEventMap[K]) => void,
): void {
this._assertHandlerTiming(event);
- super.addEventListener(event, handler);
+ this._ensureEventSlot(event);
+ this._events.addEventListener(event, handler);
}
- protected override onEventDispatch(
+ removeEventListener(
event: K,
- params: AppEventMap[K],
+ handler: (params: AppEventMap[K]) => void,
): void {
- if (event === "hostcontextchanged") {
- this._hostContext = { ...this._hostContext, ...params };
+ this._events.removeEventListener(event, handler);
+ }
+
+ private _ensureEventSlot(event: K): void {
+ if (this._registeredEvents.has(event)) return;
+ const schema = this.eventSchemas[event];
+ if (!schema) throw new Error(`Unknown event: ${String(event)}`);
+ this.setNotificationHandler(schema, (notification) => {
+ const params = (notification as { params: AppEventMap[K] }).params;
+ if (event === "hostcontextchanged") {
+ this._hostContext = { ...this._hostContext, ...params };
+ }
+ this._events.dispatch(event, params);
+ });
+ this._registeredEvents.add(event);
+ }
+
+ protected getEventHandler(
+ event: K,
+ ): ((params: AppEventMap[K]) => void) | undefined {
+ return this._events.getHandler(event);
+ }
+
+ protected warnIfRequestHandlerReplaced(
+ name: string,
+ previous: unknown,
+ next: unknown,
+ ): void {
+ if (previous && next) {
+ console.warn(
+ `[MCP Apps] ${name} handler replaced. ` +
+ `Previous handler will no longer be called.`,
+ );
}
}
+ protected replaceRequestHandler: Protocol<
+ AppRequest,
+ AppNotification,
+ AppResult
+ >["setRequestHandler"] = (schema, handler) => {
+ const method = (schema as MethodSchema).shape.method.value;
+ this._registeredMethods.add(method);
+ super.setRequestHandler(schema, handler);
+ };
+
+ private _assertMethodNotRegistered(schema: unknown, via: string): void {
+ const method = (schema as MethodSchema).shape.method.value;
+ if (this._registeredMethods.has(method)) {
+ throw new Error(
+ `Handler for "${method}" already registered (via ${via}). ` +
+ `Use addEventListener() to attach multiple listeners, ` +
+ `or the on* setter for replace semantics.`,
+ );
+ }
+ this._registeredMethods.add(method);
+ }
+
/**
* Create a new MCP App instance.
*
@@ -484,9 +562,8 @@ export class App extends ProtocolWithEvents<
return {};
});
- // Eagerly register the hostcontextchanged event slot so that
- // onEventDispatch (which merges into _hostContext) fires even if the
- // user never assigns onhostcontextchanged or calls addEventListener.
+ // Eagerly register hostcontextchanged so the owner-side context merge runs
+ // even if the user never assigns a handler or adds a listener.
this.setEventHandler("hostcontextchanged", undefined);
}
@@ -924,9 +1001,9 @@ export class App extends ProtocolWithEvents<
* without replacing.
*
* Notification params are automatically merged into the internal host context
- * via {@link onEventDispatch `onEventDispatch`} before any handler or listener
- * fires. This means {@link getHostContext `getHostContext`} will return the
- * updated values even before your callback runs.
+ * before any handler or listener fires. This means
+ * {@link getHostContext `getHostContext`} will return the updated values even
+ * before your callback runs.
*
* Register handlers before calling {@link connect `connect`} to avoid missing notifications.
*
diff --git a/src/events.test.ts b/src/events.test.ts
new file mode 100644
index 0000000..7fd8708
--- /dev/null
+++ b/src/events.test.ts
@@ -0,0 +1,82 @@
+import { describe, expect, it, spyOn } from "bun:test";
+
+import { EventDispatcher } from "./events";
+
+type TestEventMap = {
+ change: { value: number };
+};
+
+describe("EventDispatcher", () => {
+ it("replaces the singular handler", () => {
+ const dispatcher = new EventDispatcher();
+ const calls: string[] = [];
+ const first = () => calls.push("first");
+ const second = () => calls.push("second");
+ const warn = spyOn(console, "warn").mockImplementation(() => {});
+
+ try {
+ dispatcher.setHandler("change", first);
+ dispatcher.setHandler("change", second);
+
+ expect(dispatcher.getHandler("change")).toBe(second);
+ dispatcher.dispatch("change", { value: 1 });
+ expect(calls).toEqual(["second"]);
+ } finally {
+ warn.mockRestore();
+ }
+ });
+
+ it("dispatches the singular handler before listeners in insertion order", () => {
+ const dispatcher = new EventDispatcher();
+ const calls: string[] = [];
+
+ dispatcher.setHandler("change", () => calls.push("handler"));
+ dispatcher.addEventListener("change", () => calls.push("listener-1"));
+ dispatcher.addEventListener("change", () => calls.push("listener-2"));
+
+ dispatcher.dispatch("change", { value: 1 });
+
+ expect(calls).toEqual(["handler", "listener-1", "listener-2"]);
+ });
+
+ it("uses a listener snapshot when a listener is removed during dispatch", () => {
+ const dispatcher = new EventDispatcher();
+ const calls: string[] = [];
+ const second = () => calls.push("second");
+ const first = () => {
+ calls.push("first");
+ dispatcher.removeEventListener("change", second);
+ };
+
+ dispatcher.addEventListener("change", first);
+ dispatcher.addEventListener("change", second);
+
+ dispatcher.dispatch("change", { value: 1 });
+ dispatcher.dispatch("change", { value: 2 });
+
+ expect(calls).toEqual(["first", "second", "first"]);
+ });
+
+ it("warns only when one singular handler replaces another", () => {
+ const dispatcher = new EventDispatcher();
+ const warn = spyOn(console, "warn").mockImplementation(() => {});
+ const first = () => {};
+ const second = () => {};
+
+ try {
+ dispatcher.setHandler("change", first);
+ dispatcher.setHandler("change", undefined);
+ dispatcher.setHandler("change", first);
+ expect(warn).not.toHaveBeenCalled();
+
+ dispatcher.setHandler("change", second);
+
+ expect(warn).toHaveBeenCalledTimes(1);
+ expect(String(warn.mock.calls[0]?.[0])).toContain(
+ "onchange handler replaced",
+ );
+ } finally {
+ warn.mockRestore();
+ }
+ });
+});
diff --git a/src/events.ts b/src/events.ts
index 4d17ca4..b891867 100644
--- a/src/events.ts
+++ b/src/events.ts
@@ -1,17 +1,6 @@
-import { Protocol } from "@modelcontextprotocol/sdk/shared/protocol.js";
-import {
- Request,
- Notification,
- Result,
-} from "@modelcontextprotocol/sdk/types.js";
-import { ZodLiteral, ZodObject } from "zod/v4";
-
-type MethodSchema = ZodObject<{ method: ZodLiteral }>;
-
/**
- * Per-event state: a singular `on*` handler (replace semantics) plus a
- * listener array (`addEventListener` semantics), mirroring the DOM model
- * where `el.onclick` and `el.addEventListener("click", …)` coexist.
+ * Per-event state: a singular `on*` handler (replace semantics) plus an
+ * ordered listener array (`addEventListener` semantics).
*/
interface EventSlot {
onHandler?: ((params: T) => void) | undefined;
@@ -19,118 +8,19 @@ interface EventSlot {
}
/**
- * Intermediate base class that adds DOM-style event support on top of the
- * MCP SDK's `Protocol`.
+ * Protocol-independent DOM-style event fan-out.
*
- * The base `Protocol` class stores one handler per method:
- * `setRequestHandler()` and `setNotificationHandler()` replace any existing
- * handler for the same method silently. This class introduces a two-channel
- * event model inspired by the DOM:
+ * Owners perform event-specific state updates before calling
+ * {@link dispatch}. Dispatch then invokes the singular handler followed by a
+ * snapshot of listeners in insertion order.
*
- * ### Singular `on*` handler (like `el.onclick`)
- *
- * Subclasses expose `get`/`set` pairs that delegate to
- * {@link setEventHandler `setEventHandler`} /
- * {@link getEventHandler `getEventHandler`}. Assigning replaces the previous
- * handler; assigning `undefined` clears it. `addEventListener` listeners are
- * unaffected.
- *
- * ### Multi-listener (`addEventListener` / `removeEventListener`)
- *
- * Append to a per-event listener array. Listeners fire in insertion order
- * after the singular `on*` handler.
- *
- * ### Dispatch order
- *
- * When a notification arrives for a mapped event:
- * 1. {@link onEventDispatch `onEventDispatch`} (subclass side-effects)
- * 2. The singular `on*` handler (if set)
- * 3. All `addEventListener` listeners in insertion order
- *
- * ### Double-set protection
- *
- * Direct calls to {@link setRequestHandler `setRequestHandler`} /
- * {@link setNotificationHandler `setNotificationHandler`} throw if a handler
- * for the same method has already been registered (through any path), so
- * accidental overwrites surface as errors instead of silent bugs.
- *
- * @typeParam EventMap - Maps event names to the listener's `params` type.
+ * @typeParam EventMap - Maps event names to their listener parameter types.
*/
-export abstract class ProtocolWithEvents<
- SendRequestT extends Request,
- SendNotificationT extends Notification,
- SendResultT extends Result,
- EventMap extends Record,
-> extends Protocol {
- private _registeredMethods = new Set();
- private _eventSlots = new Map();
+export class EventDispatcher> {
+ private readonly _eventSlots = new Map();
- /**
- * Event name → notification schema. Subclasses populate this so that
- * the event system can lazily register a dispatcher with the correct
- * schema on first use.
- */
- protected abstract readonly eventSchemas: {
- [K in keyof EventMap]: MethodSchema;
- };
-
- /**
- * Called once per incoming notification, before any handlers or listeners
- * fire. Subclasses may override to perform side effects such as merging
- * notification params into cached state.
- */
- protected onEventDispatch(
- _event: K,
- _params: EventMap[K],
- ): void {}
-
- // ── Event system (DOM model) ────────────────────────────────────────
-
- /**
- * Lazily create the event slot and register a single dispatcher with the
- * base `Protocol`. The dispatcher fans out to the `on*` handler and all
- * `addEventListener` listeners.
- */
- private _ensureEventSlot(
- event: K,
- ): EventSlot {
- let slot = this._eventSlots.get(event) as
- | EventSlot
- | undefined;
- if (!slot) {
- const schema = this.eventSchemas[event];
- if (!schema) {
- throw new Error(`Unknown event: ${String(event)}`);
- }
- slot = { listeners: [] };
- this._eventSlots.set(event, slot as EventSlot);
-
- // Claim this method so direct setNotificationHandler calls throw.
- const method = schema.shape.method.value;
- this._registeredMethods.add(method);
-
- const s = slot; // stable reference for the closure
- super.setNotificationHandler(schema, (n) => {
- const params = (n as { params: EventMap[K] }).params;
- this.onEventDispatch(event, params);
- // 1. Singular on* handler
- s.onHandler?.(params);
- // 2. addEventListener listeners — snapshot to tolerate removal during
- // dispatch (e.g., a listener that calls removeEventListener on itself)
- for (const l of [...s.listeners]) l(params);
- });
- }
- return slot;
- }
-
- /**
- * Set or clear the singular `on*` handler for an event.
- *
- * Replace semantics — like the DOM's `el.onclick = fn`. Assigning
- * `undefined` clears the handler without affecting `addEventListener`
- * listeners.
- */
- protected setEventHandler(
+ /** Set, replace, or clear the singular handler for an event. */
+ setHandler(
event: K,
handler: ((params: EventMap[K]) => void) | undefined,
): void {
@@ -144,31 +34,16 @@ export abstract class ProtocolWithEvents<
slot.onHandler = handler;
}
- /**
- * Get the singular `on*` handler for an event, or `undefined` if none is
- * set. `addEventListener` listeners are not reflected here.
- */
- protected getEventHandler(
+ /** Get the singular handler for an event, if one is set. */
+ getHandler(
event: K,
): ((params: EventMap[K]) => void) | undefined {
- return (this._eventSlots.get(event) as EventSlot | undefined)
- ?.onHandler;
+ return (this._eventSlots.get(event) as
+ | EventSlot
+ | undefined)?.onHandler;
}
- /**
- * Add a listener for a notification event.
- *
- * Unlike the singular `on*` handler, calling this multiple times appends
- * listeners rather than replacing them. All registered listeners fire in
- * insertion order after the `on*` handler when the notification arrives.
- *
- * Registration is lazy: the first call (for a given event, from either
- * this method or the `on*` setter) registers a dispatcher with the base
- * `Protocol`.
- *
- * @param event - Event name (a key of the `EventMap` type parameter).
- * @param handler - Listener invoked with the notification `params`.
- */
+ /** Add a listener. Listeners run in insertion order after the handler. */
addEventListener(
event: K,
handler: (params: EventMap[K]) => void,
@@ -176,11 +51,7 @@ export abstract class ProtocolWithEvents<
this._ensureEventSlot(event).listeners.push(handler);
}
- /**
- * Remove a previously registered event listener. The dispatcher stays
- * registered even if the listener array becomes empty; future
- * notifications simply have no listeners to call.
- */
+ /** Remove the first matching listener, if present. */
removeEventListener(
event: K,
handler: (params: EventMap[K]) => void,
@@ -193,87 +64,29 @@ export abstract class ProtocolWithEvents<
if (idx !== -1) slot.listeners.splice(idx, 1);
}
- // ── Handler registration with double-set protection ─────────────────
-
- // The two overrides below are arrow-function class fields rather than
- // prototype methods so that Protocol's constructor — which registers its
- // own ping/cancelled/progress handlers via `this.setRequestHandler`
- // before our fields initialize — hits the base implementation and skips
- // tracking. Converting these to proper methods would crash with
- // `_registeredMethods` undefined during super().
-
/**
- * Registers a request handler. Throws if a handler for the same method
- * has already been registered — use the `on*` setter (replace semantics)
- * or `addEventListener` (multi-listener) for notification events.
- *
- * @throws {Error} if a handler for this method is already registered.
+ * Dispatch an event to its singular handler and a listener snapshot.
+ * Listener mutations during dispatch take effect on the next dispatch.
*/
- override setRequestHandler: Protocol<
- SendRequestT,
- SendNotificationT,
- SendResultT
- >["setRequestHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setRequestHandler");
- super.setRequestHandler(schema, handler);
- };
-
- /**
- * Registers a notification handler. Throws if a handler for the same
- * method has already been registered — use the `on*` setter (replace
- * semantics) or `addEventListener` (multi-listener) for mapped events.
- *
- * @throws {Error} if a handler for this method is already registered.
- */
- override setNotificationHandler: Protocol<
- SendRequestT,
- SendNotificationT,
- SendResultT
- >["setNotificationHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setNotificationHandler");
- super.setNotificationHandler(schema, handler);
- };
-
- /**
- * Warn if a request handler `on*` setter is replacing a previously-set
- * handler. Call from each request setter before updating the backing field.
- */
- protected warnIfRequestHandlerReplaced(
- name: string,
- previous: unknown,
- next: unknown,
- ): void {
- if (previous && next) {
- console.warn(
- `[MCP Apps] ${name} handler replaced. ` +
- `Previous handler will no longer be called.`,
- );
- }
+ dispatch(event: K, params: EventMap[K]): void {
+ const slot = this._eventSlots.get(event) as
+ | EventSlot
+ | undefined;
+ if (!slot) return;
+ slot.onHandler?.(params);
+ for (const l of [...slot.listeners]) l(params);
}
- /**
- * Replace a request handler, bypassing double-set protection. Used by
- * `on*` request-handler setters that need replace semantics.
- */
- protected replaceRequestHandler: Protocol<
- SendRequestT,
- SendNotificationT,
- SendResultT
- >["setRequestHandler"] = (schema, handler) => {
- const method = (schema as MethodSchema).shape.method.value;
- this._registeredMethods.add(method);
- super.setRequestHandler(schema, handler);
- };
-
- private _assertMethodNotRegistered(schema: unknown, via: string): void {
- const method = (schema as MethodSchema).shape.method.value;
- if (this._registeredMethods.has(method)) {
- throw new Error(
- `Handler for "${method}" already registered (via ${via}). ` +
- `Use addEventListener() to attach multiple listeners, ` +
- `or the on* setter for replace semantics.`,
- );
+ private _ensureEventSlot(
+ event: K,
+ ): EventSlot {
+ let slot = this._eventSlots.get(event) as
+ | EventSlot
+ | undefined;
+ if (!slot) {
+ slot = { listeners: [] };
+ this._eventSlots.set(event, slot as EventSlot);
}
- this._registeredMethods.add(method);
+ return slot;
}
}
diff --git a/typedoc.config.mjs b/typedoc.config.mjs
index 4c5baa3..00babc4 100644
--- a/typedoc.config.mjs
+++ b/typedoc.config.mjs
@@ -28,7 +28,7 @@ const config = {
],
excludePrivate: true,
excludeInternal: false,
- intentionallyNotExported: ["MethodSchema", "RequestHandlerExtra"],
+ intentionallyNotExported: ["RequestHandlerExtra"],
blockTags: [...OptionDefaults.blockTags, "@description"],
jsDocCompatibility: {
exampleTag: false,
From 59e6ffc6d8822f5139efc4d09fae46350761ebd2 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 15:02:25 -0700
Subject: [PATCH 08/45] refactor: migrate App to SDK v2 client
---
src/app-bridge.test.ts | 44 +++---
src/app.test.ts | 300 +++++++++++++++++++++++++++++++++++++++++
src/app.ts | 261 ++++++++++++++++-------------------
3 files changed, 434 insertions(+), 171 deletions(-)
create mode 100644 src/app.test.ts
diff --git a/src/app-bridge.test.ts b/src/app-bridge.test.ts
index 7adbb16..8f432b4 100644
--- a/src/app-bridge.test.ts
+++ b/src/app-bridge.test.ts
@@ -7,10 +7,7 @@ import {
ListPromptsResultSchema,
ListResourcesResultSchema,
ListResourceTemplatesResultSchema,
- PromptListChangedNotificationSchema,
ReadResourceResultSchema,
- ResourceListChangedNotificationSchema,
- ToolListChangedNotificationSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod/v4";
@@ -2313,9 +2310,12 @@ describe("App <-> AppBridge integration", () => {
it("sendToolListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
- app.setNotificationHandler(ToolListChangedNotificationSchema, (n) => {
- receivedNotifications.push(n.params);
- });
+ app.setNotificationHandler(
+ "notifications/tools/list_changed",
+ (notification) => {
+ receivedNotifications.push(notification.params);
+ },
+ );
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
@@ -2328,9 +2328,12 @@ describe("App <-> AppBridge integration", () => {
it("sendResourceListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
- app.setNotificationHandler(ResourceListChangedNotificationSchema, (n) => {
- receivedNotifications.push(n.params);
- });
+ app.setNotificationHandler(
+ "notifications/resources/list_changed",
+ (notification) => {
+ receivedNotifications.push(notification.params);
+ },
+ );
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
@@ -2343,9 +2346,12 @@ describe("App <-> AppBridge integration", () => {
it("sendPromptListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
- app.setNotificationHandler(PromptListChangedNotificationSchema, (n) => {
- receivedNotifications.push(n.params);
- });
+ app.setNotificationHandler(
+ "notifications/prompts/list_changed",
+ (notification) => {
+ receivedNotifications.push(notification.params);
+ },
+ );
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
@@ -2771,20 +2777,6 @@ describe("isToolVisibilityAppOnly", () => {
);
}).toThrow(/already registered/);
});
-
- it("direct setNotificationHandler throws for event-mapped methods", () => {
- const app2 = new App(testAppInfo, {}, { autoResize: false });
- app2.addEventListener("toolinput", () => {});
- expect(() => {
- app2.setNotificationHandler(
- // @ts-expect-error — exercising throw path with raw schema
- {
- shape: { method: { value: "ui/notifications/tool-input" } },
- },
- () => {},
- );
- }).toThrow(/already registered/);
- });
});
});
diff --git a/src/app.test.ts b/src/app.test.ts
new file mode 100644
index 0000000..dcf2d52
--- /dev/null
+++ b/src/app.test.ts
@@ -0,0 +1,300 @@
+import { afterEach, describe, expect, it } from "bun:test";
+import {
+ InMemoryTransport,
+ Server,
+ type JSONRPCMessage,
+} from "@modelcontextprotocol/server";
+import { z } from "zod/v4";
+
+import { App } from "./app";
+import {
+ LATEST_PROTOCOL_VERSION,
+ McpUiInitializeRequestSchema,
+ McpUiInitializeResultSchema,
+ McpUiInitializedNotificationSchema,
+} from "./types";
+
+const INNER_MCP_PROTOCOL_VERSION = "2025-11-25";
+
+type ConnectedPair = {
+ app: App;
+ server: Server;
+ sentByApp: JSONRPCMessage[];
+ appsInitialized: Promise;
+};
+
+async function connectPair(
+ app = new App(
+ { name: "view-app", version: "1.0.0" },
+ { tools: { listChanged: true } },
+ { autoResize: false },
+ ),
+): Promise {
+ const server = new Server(
+ { name: "inner-mcp-server", version: "0.0.0" },
+ {
+ capabilities: { resources: {}, tools: {} },
+ supportedProtocolVersions: [INNER_MCP_PROTOCOL_VERSION],
+ },
+ );
+ const [appTransport, serverTransport] = InMemoryTransport.createLinkedPair();
+ const sentByApp: JSONRPCMessage[] = [];
+ const send = appTransport.send.bind(appTransport);
+ appTransport.send = async (message, options) => {
+ sentByApp.push(message);
+ await send(message, options);
+ };
+
+ let resolveAppsInitialized!: () => void;
+ const appsInitialized = new Promise((resolve) => {
+ resolveAppsInitialized = resolve;
+ });
+
+ server.setRequestHandler(
+ "ui/initialize",
+ {
+ params: McpUiInitializeRequestSchema.shape.params,
+ result: McpUiInitializeResultSchema,
+ },
+ (params) => {
+ expect(params.protocolVersion).toBe(LATEST_PROTOCOL_VERSION);
+ return {
+ protocolVersion: LATEST_PROTOCOL_VERSION,
+ hostCapabilities: { openLinks: {} },
+ hostInfo: { name: "apps-host", version: "2.0.0" },
+ hostContext: { theme: "dark" as const, locale: "en-US" },
+ };
+ },
+ );
+ server.setNotificationHandler(
+ "ui/notifications/initialized",
+ { params: McpUiInitializedNotificationSchema.shape.params },
+ () => resolveAppsInitialized(),
+ );
+ server.setRequestHandler("tools/call", (request) => ({
+ content: [{ type: "text", text: `called ${request.params.name}` }],
+ }));
+ server.setRequestHandler("resources/read", (request) => ({
+ contents: [{ uri: request.params.uri, text: "resource body" }],
+ }));
+ server.setRequestHandler("resources/list", () => ({
+ resources: [{ uri: "test://resource", name: "Test resource" }],
+ }));
+ server.setRequestHandler("sampling/createMessage", () => ({
+ model: "test-model",
+ role: "assistant",
+ content: { type: "text", text: "sampled" },
+ }));
+
+ await server.connect(serverTransport);
+ await app.connect(appTransport);
+ await appsInitialized;
+
+ return { app, server, sentByApp, appsInitialized };
+}
+
+const connected: Array> = [];
+
+afterEach(async () => {
+ await Promise.all(
+ connected
+ .splice(0)
+ .flatMap(({ app, server }) => [app.close(), server.close()]),
+ );
+});
+
+describe("App base MCP SDK v2 Client migration", () => {
+ it("completes the legacy MCP handshake before the authoritative Apps handshake", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+
+ const lifecycleMethods = pair.sentByApp
+ .filter(
+ (message): message is JSONRPCMessage & { method: string } =>
+ "method" in message,
+ )
+ .map((message) => message.method)
+ .filter((method) =>
+ [
+ "initialize",
+ "notifications/initialized",
+ "ui/initialize",
+ "ui/notifications/initialized",
+ ].includes(method),
+ );
+
+ expect(lifecycleMethods).toEqual([
+ "initialize",
+ "notifications/initialized",
+ "ui/initialize",
+ "ui/notifications/initialized",
+ ]);
+ expect(pair.app.getNegotiatedProtocolVersion()).toBe(
+ INNER_MCP_PROTOCOL_VERSION,
+ );
+ });
+
+ it("uses ui/initialize as the authority for Apps host state", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+
+ expect(pair.app.getServerVersion()).toEqual({
+ name: "inner-mcp-server",
+ version: "0.0.0",
+ });
+ expect(pair.app.getHostVersion()).toEqual({
+ name: "apps-host",
+ version: "2.0.0",
+ });
+ expect(pair.app.getHostCapabilities()).toEqual({ openLinks: {} });
+ expect(pair.app.getHostContext()).toEqual({
+ theme: "dark",
+ locale: "en-US",
+ });
+ });
+
+ it("preserves registered App tools with the base MCP SDK v2 Client handler context", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+ let receivedSignal: AbortSignal | undefined;
+
+ pair.app.registerTool(
+ "greet",
+ { description: "Greets a person" },
+ async (extra) => {
+ receivedSignal = extra.mcpReq.signal;
+ return { content: [{ type: "text", text: "hello" }] };
+ },
+ );
+
+ const listed = await pair.server.request({
+ method: "tools/list",
+ params: {},
+ });
+ const result = await pair.server.request({
+ method: "tools/call",
+ params: { name: "greet", arguments: {} },
+ });
+
+ expect(listed.tools.map((tool) => tool.name)).toEqual(["greet"]);
+ expect(result.content).toEqual([{ type: "text", text: "hello" }]);
+ expect(receivedSignal).toBeInstanceOf(AbortSignal);
+ });
+
+ it("uses base MCP SDK v2 method-keyed sends for standard MCP requests", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+
+ const toolResult = await pair.app.callServerTool({
+ name: "refresh",
+ arguments: {},
+ });
+ const resource = await pair.app.readServerResource({
+ uri: "test://resource",
+ });
+ const resources = await pair.app.listServerResources();
+ const sample = await pair.app.createSamplingMessage({
+ messages: [{ role: "user", content: { type: "text", text: "hello" } }],
+ maxTokens: 20,
+ });
+
+ expect(toolResult.content).toEqual([
+ { type: "text", text: "called refresh" },
+ ]);
+ expect(resource.contents[0]).toEqual({
+ uri: "test://resource",
+ text: "resource body",
+ });
+ expect(resources.resources.map(({ uri }) => uri)).toEqual([
+ "test://resource",
+ ]);
+ expect(sample.content).toEqual({ type: "text", text: "sampled" });
+ });
+
+ it("preserves reconnect behavior after close", async () => {
+ const first = await connectPair();
+ await first.app.close();
+ await first.server.close();
+
+ const second = await connectPair(first.app);
+ connected.push(second);
+
+ expect(second.app.getNegotiatedProtocolVersion()).toBe(
+ INNER_MCP_PROTOCOL_VERSION,
+ );
+ expect(second.app.getHostVersion()).toEqual({
+ name: "apps-host",
+ version: "2.0.0",
+ });
+ });
+
+ it("preserves auto-resize setup after Apps initialization", async () => {
+ const app = new App(
+ { name: "view-app", version: "1.0.0" },
+ {},
+ { autoResize: true },
+ );
+ let setupCalls = 0;
+ app.setupSizeChangedNotifications = () => {
+ setupCalls += 1;
+ return () => {};
+ };
+
+ const pair = await connectPair(app);
+ connected.push(pair);
+
+ expect(setupCalls).toBe(1);
+ });
+
+ it("preserves strict late-handler timing errors", async () => {
+ const app = new App(
+ { name: "view-app", version: "1.0.0" },
+ {},
+ { autoResize: false, strict: true },
+ );
+ const pair = await connectPair(app);
+ connected.push(pair);
+
+ expect(() => {
+ app.ontoolinput = () => {};
+ }).toThrow(/handler registered after connect/);
+ });
+
+ it("uses base MCP SDK replacement semantics for request handlers", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+ let handledBy = 0;
+
+ pair.app.setRequestHandler("ping", () => {
+ handledBy = 1;
+ return {};
+ });
+ pair.app.setRequestHandler("ping", () => {
+ handledBy = 2;
+ return {};
+ });
+
+ await pair.server.request({ method: "ping", params: {} });
+ expect(handledBy).toBe(2);
+ });
+
+ it("uses base MCP SDK replacement semantics for non-event notifications", async () => {
+ const pair = await connectPair();
+ connected.push(pair);
+ const calls: number[] = [];
+ const params = z.object({});
+
+ pair.app.setNotificationHandler("test/notification", { params }, () => {
+ calls.push(1);
+ });
+ pair.app.setNotificationHandler("test/notification", { params }, () => {
+ calls.push(2);
+ });
+ await pair.server.notification({
+ method: "test/notification",
+ params: {},
+ });
+
+ expect(calls).toEqual([2]);
+ });
+});
diff --git a/src/app.ts b/src/app.ts
index c586c31..3c8f5b7 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,38 +1,27 @@
import {
+ Client,
+ type ClientContext,
+ type ClientOptions,
type RequestOptions,
- mergeCapabilities,
- Protocol,
- ProtocolOptions,
-} from "@modelcontextprotocol/sdk/shared/protocol.js";
-
-import {
- CallToolRequest,
- CallToolRequestSchema,
- CallToolResult,
- CallToolResultSchema,
- CreateMessageRequest,
- CreateMessageResult,
- CreateMessageResultSchema,
- CreateMessageResultWithTools,
- CreateMessageResultWithToolsSchema,
- EmptyResultSchema,
- Implementation,
- ListResourcesRequest,
- ListResourcesResult,
- ListResourcesResultSchema,
- ListToolsRequest,
- ListToolsRequestSchema,
- ListToolsResult,
- LoggingMessageNotification,
- PingRequestSchema,
- ReadResourceRequest,
- ReadResourceResult,
- ReadResourceResultSchema,
- Tool,
- ToolAnnotations,
- ToolListChangedNotification,
-} from "@modelcontextprotocol/sdk/types.js";
-import { AppNotification, AppRequest, AppResult } from "./types";
+ type CallToolRequest,
+ type CallToolResult,
+ type CreateMessageRequest,
+ type CreateMessageResult,
+ type CreateMessageResultWithTools,
+ type Implementation,
+ type ListResourcesRequest,
+ type ListResourcesResult,
+ type ListToolsRequest,
+ type ListToolsResult,
+ type LoggingMessageNotification,
+ type ReadResourceRequest,
+ type ReadResourceResult,
+ type Tool,
+ type ToolAnnotations,
+ type ToolListChangedNotification,
+ type Transport,
+} from "@modelcontextprotocol/client";
+import { EmptyResultSchema } from "@modelcontextprotocol/core";
import { EventDispatcher } from "./events";
export { EventDispatcher } from "./events";
import { PostMessageTransport } from "./message-transport";
@@ -56,6 +45,7 @@ import {
McpUiResourceTeardownRequest,
McpUiResourceTeardownRequestSchema,
McpUiResourceTeardownResult,
+ McpUiResourceTeardownResultSchema,
McpUiRequestTeardownNotification,
McpUiSizeChangedNotification,
McpUiToolCancelledNotification,
@@ -69,15 +59,36 @@ import {
McpUiRequestDisplayModeRequest,
McpUiRequestDisplayModeResultSchema,
} from "./types";
-import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import {
StandardSchemaV1,
standardSchemaToJsonSchema,
validateStandardSchema,
} from "./standard-schema";
-import { z, type ZodLiteral, type ZodObject } from "zod/v4";
+import { z, type ZodLiteral, type ZodObject, type ZodType } from "zod/v4";
-type MethodSchema = ZodObject<{ method: ZodLiteral }>;
+type MethodSchema = ZodObject<{
+ method: ZodLiteral;
+ params: ZodType;
+}>;
+
+const INNER_MCP_PROTOCOL_VERSION = "2025-11-25";
+
+function mergeAppCapabilities(
+ base: McpUiAppCapabilities,
+ additional: McpUiAppCapabilities,
+): McpUiAppCapabilities {
+ const result = { ...base, ...additional };
+ if (additional.experimental !== undefined) {
+ result.experimental = {
+ ...base.experimental,
+ ...additional.experimental,
+ };
+ }
+ if (additional.tools !== undefined) {
+ result.tools = { ...base.tools, ...additional.tools };
+ }
+ return result;
+}
export type {
StandardSchemaV1,
@@ -167,7 +178,10 @@ export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
*
* @see `ProtocolOptions` from @modelcontextprotocol/sdk for inherited options
*/
-export type AppOptions = ProtocolOptions & {
+export type AppOptions = Omit<
+ ClientOptions,
+ "capabilities" | "supportedProtocolVersions" | "versionNegotiation"
+> & {
/**
* Automatically report size changes to the host using `ResizeObserver`.
*
@@ -207,9 +221,7 @@ export type AppOptions = ProtocolOptions & {
allowUnsafeEval?: boolean;
};
-type RequestHandlerExtra = Parameters<
- Parameters[1]
->[1];
+type RequestHandlerExtra = ClientContext;
/**
* Result of an app-registered tool callback. When `Out` is provided,
@@ -343,38 +355,15 @@ export type AppEventMap = {
* await app.connect();
* ```
*/
-export class App extends Protocol {
+export class App extends Client {
private _hostCapabilities?: McpUiHostCapabilities;
private _hostInfo?: Implementation;
private _hostContext?: McpUiHostContext;
private _registeredTools: { [name: string]: RegisteredAppTool } = {};
private _initializedSent = false;
- private readonly _registeredMethods = new Set();
private readonly _registeredEvents = new Set();
private readonly _events = new EventDispatcher();
- // ProtocolWithEvents previously owned these registration guards. Keep them
- // on App to preserve the existing double-registration behavior while event
- // fan-out moves to protocol-independent composition. Arrow-function fields
- // ensure Protocol's constructor uses its own methods before the guards init.
- override setRequestHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setRequestHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setRequestHandler");
- super.setRequestHandler(schema, handler);
- };
-
- override setNotificationHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setNotificationHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setNotificationHandler");
- super.setNotificationHandler(schema, handler);
- };
-
/**
* Warn if a host-bound method is called before {@link connect `connect`} has
* completed the `ui/initialize` → `ui/notifications/initialized` handshake.
@@ -479,13 +468,17 @@ export class App extends Protocol {
if (this._registeredEvents.has(event)) return;
const schema = this.eventSchemas[event];
if (!schema) throw new Error(`Unknown event: ${String(event)}`);
- this.setNotificationHandler(schema, (notification) => {
- const params = (notification as { params: AppEventMap[K] }).params;
- if (event === "hostcontextchanged") {
- this._hostContext = { ...this._hostContext, ...params };
- }
- this._events.dispatch(event, params);
- });
+ this.setNotificationHandler(
+ schema.shape.method.value,
+ { params: schema.shape.params },
+ (params) => {
+ const eventParams = params as AppEventMap[K];
+ if (event === "hostcontextchanged") {
+ this._hostContext = { ...this._hostContext, ...eventParams };
+ }
+ this._events.dispatch(event, eventParams);
+ },
+ );
this._registeredEvents.add(event);
}
@@ -508,33 +501,11 @@ export class App extends Protocol {
}
}
- protected replaceRequestHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setRequestHandler"] = (schema, handler) => {
- const method = (schema as MethodSchema).shape.method.value;
- this._registeredMethods.add(method);
- super.setRequestHandler(schema, handler);
- };
-
- private _assertMethodNotRegistered(schema: unknown, via: string): void {
- const method = (schema as MethodSchema).shape.method.value;
- if (this._registeredMethods.has(method)) {
- throw new Error(
- `Handler for "${method}" already registered (via ${via}). ` +
- `Use addEventListener() to attach multiple listeners, ` +
- `or the on* setter for replace semantics.`,
- );
- }
- this._registeredMethods.add(method);
- }
-
/**
* Create a new MCP App instance.
*
* @param _appInfo - App identification (name and version)
- * @param _capabilities - Features and capabilities this app provides
+ * @param _appCapabilities - Features and capabilities this app provides
* @param options - Configuration options including `autoResize` behavior
*
* @example
@@ -548,16 +519,29 @@ export class App extends Protocol {
*/
constructor(
private _appInfo: Implementation,
- private _capabilities: McpUiAppCapabilities = {},
+ private _appCapabilities: McpUiAppCapabilities = {},
private options: AppOptions = { autoResize: true },
) {
- super(options);
+ // TEMPORARY INNER-CHANNEL NEGOTIATION:
+ // App and AppBridge use the public v2 Client/Server roles, so the iframe
+ // channel first completes the SDK's standard legacy MCP initialization.
+ // ui/initialize remains authoritative for Apps capabilities, identity, and
+ // host context, and ui/notifications/initialized remains the View-ready gate.
+ // Keep the inner MCP era pinned to 2025-11-25. Revisit this sequence only
+ // after the MCP Apps negotiation specification is resolved:
+ // https://github.com/modelcontextprotocol/ext-apps/issues/708
+ super(_appInfo, {
+ ...options,
+ capabilities: {},
+ versionNegotiation: { mode: "legacy" },
+ supportedProtocolVersions: [INNER_MCP_PROTOCOL_VERSION],
+ });
if (!options.allowUnsafeEval) {
z.config({ jitless: true });
}
- this.setRequestHandler(PingRequestSchema, (request) => {
+ this.setRequestHandler("ping", (request) => {
console.log("Received ping:", request.params);
return {};
});
@@ -567,13 +551,16 @@ export class App extends Protocol {
this.setEventHandler("hostcontextchanged", undefined);
}
- private registerCapabilities(capabilities: McpUiAppCapabilities): void {
+ private registerAppCapabilities(capabilities: McpUiAppCapabilities): void {
if (this.transport) {
throw new Error(
"Cannot register capabilities after transport is established",
);
}
- this._capabilities = mergeCapabilities(this._capabilities, capabilities);
+ this._appCapabilities = mergeAppCapabilities(
+ this._appCapabilities,
+ capabilities,
+ );
}
registerTool<
@@ -596,7 +583,7 @@ export class App extends Protocol {
}
const app = this;
const notify = () => {
- if (app._initializedSent && app._capabilities.tools?.listChanged) {
+ if (app._initializedSent && app._appCapabilities.tools?.listChanged) {
void app.sendToolListChanged();
}
};
@@ -668,8 +655,8 @@ export class App extends Protocol {
// to declare { tools: {} } in the constructor just to use registerTool.
// Only do this pre-connect; post-connect the capability was already
// advertised (or wasn't) and can't change.
- if (!this._capabilities.tools && !this.transport) {
- this.registerCapabilities({ tools: { listChanged: true } });
+ if (!this._appCapabilities.tools && !this.transport) {
+ this.registerAppCapabilities({ tools: { listChanged: true } });
}
this.ensureToolHandlersInitialized();
@@ -1081,11 +1068,15 @@ export class App extends Protocol {
) {
this.warnIfRequestHandlerReplaced("onteardown", this._onteardown, callback);
this._onteardown = callback;
- this.replaceRequestHandler(
- McpUiResourceTeardownRequestSchema,
- (request, extra) => {
+ this.setRequestHandler(
+ "ui/resource-teardown",
+ {
+ params: McpUiResourceTeardownRequestSchema.shape.params,
+ result: McpUiResourceTeardownResultSchema,
+ },
+ (params, extra) => {
if (!this._onteardown) throw new Error("No onteardown handler set");
- return this._onteardown(request.params, extra);
+ return this._onteardown(params, extra);
},
);
}
@@ -1135,7 +1126,7 @@ export class App extends Protocol {
) {
this.warnIfRequestHandlerReplaced("oncalltool", this._oncalltool, callback);
this._oncalltool = callback;
- this.replaceRequestHandler(CallToolRequestSchema, (request, extra) => {
+ this.setRequestHandler("tools/call", (request, extra) => {
if (!this._oncalltool) throw new Error("No oncalltool handler set");
return this._oncalltool(request.params, extra);
});
@@ -1206,7 +1197,7 @@ export class App extends Protocol {
callback,
);
this._onlisttools = callback;
- this.replaceRequestHandler(ListToolsRequestSchema, (request, extra) => {
+ this.setRequestHandler("tools/list", (request, extra) => {
if (!this._onlisttools) throw new Error("No onlisttools handler set");
return this._onlisttools(request.params, extra);
});
@@ -1216,7 +1207,7 @@ export class App extends Protocol {
* Verify that the host supports the capability required for the given request method.
* @internal
*/
- assertCapabilityForMethod(method: AppRequest["method"]): void {
+ protected override assertCapabilityForMethod(method: string): void {
switch (method) {
case "sampling/createMessage":
if (!this._hostCapabilities?.sampling) {
@@ -1232,11 +1223,11 @@ export class App extends Protocol {
* Verify that the app declared the capability required for the given request method.
* @internal
*/
- assertRequestHandlerCapability(method: AppRequest["method"]): void {
+ protected override assertRequestHandlerCapability(method: string): void {
switch (method) {
case "tools/call":
case "tools/list":
- if (!this._capabilities.tools) {
+ if (!this._appCapabilities.tools) {
throw new Error(
`Client does not support tool capability (required for ${method})`,
);
@@ -1254,26 +1245,10 @@ export class App extends Protocol {
* Verify that the app supports the capability required for the given notification method.
* @internal
*/
- assertNotificationCapability(_method: AppNotification["method"]): void {
+ protected override assertNotificationCapability(_method: string): void {
// TODO
}
- /**
- * Verify that task creation is supported for the given request method.
- * @internal
- */
- protected assertTaskCapability(_method: string): void {
- throw new Error("Tasks are not supported in MCP Apps");
- }
-
- /**
- * Verify that task handler is supported for the given method.
- * @internal
- */
- protected assertTaskHandlerCapability(_method: string): void {
- throw new Error("Task handlers are not supported in MCP Apps");
- }
-
/**
* Call a tool on the originating MCP server (proxied through the host).
*
@@ -1322,7 +1297,6 @@ export class App extends Protocol {
}
return await this.request(
{ method: "tools/call", params },
- CallToolResultSchema,
{
// Hosts may interpose long-running or user-interactive steps before the
// tool result arrives. Opting in here lets a host heartbeat keep the
@@ -1379,11 +1353,7 @@ export class App extends Protocol {
options?: RequestOptions,
): Promise {
this._assertInitialized("readServerResource");
- return await this.request(
- { method: "resources/read", params },
- ReadResourceResultSchema,
- options,
- );
+ return await this.request({ method: "resources/read", params }, options);
}
/**
@@ -1427,11 +1397,7 @@ export class App extends Protocol {
options?: RequestOptions,
): Promise {
this._assertInitialized("listServerResources");
- return await this.request(
- { method: "resources/list", params },
- ListResourcesResultSchema,
- options,
- );
+ return await this.request({ method: "resources/list", params }, options);
}
/**
@@ -1508,12 +1474,8 @@ export class App extends Protocol {
options?: RequestOptions,
): Promise {
this._assertInitialized("createSamplingMessage");
- const resultSchema = params.tools
- ? CreateMessageResultWithToolsSchema
- : CreateMessageResultSchema;
return await this.request(
{ method: "sampling/createMessage", params },
- resultSchema,
options,
);
}
@@ -2030,14 +1992,23 @@ export class App extends Protocol {
);
}
this._initializedSent = false;
- await super.connect(transport);
+ // TEMPORARY INNER-CHANNEL NEGOTIATION:
+ // App and AppBridge use the public v2 Client/Server roles, so the iframe
+ // channel first completes the SDK's standard legacy MCP initialization.
+ // ui/initialize remains authoritative for Apps capabilities, identity, and
+ // host context, and ui/notifications/initialized remains the View-ready gate.
+ // Keep the inner MCP era pinned to 2025-11-25. Revisit this sequence only
+ // after the MCP Apps negotiation specification is resolved:
+ // https://github.com/modelcontextprotocol/ext-apps/issues/708
try {
+ await super.connect(transport);
+
const result = await this.request(
{
method: "ui/initialize",
params: {
- appCapabilities: this._capabilities,
+ appCapabilities: this._appCapabilities,
appInfo: this._appInfo,
protocolVersion: LATEST_PROTOCOL_VERSION,
},
From d19a1fb83ade586d6e2eb46535e7d84a7f7468a8 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 15:34:33 -0700
Subject: [PATCH 09/45] refactor: migrate AppBridge to SDK v2 server
---
src/app-bridge.test.ts | 336 ++++++++++++++++++++++----
src/app-bridge.ts | 527 ++++++++++++++++++++---------------------
2 files changed, 546 insertions(+), 317 deletions(-)
diff --git a/src/app-bridge.test.ts b/src/app-bridge.test.ts
index 8f432b4..81e072f 100644
--- a/src/app-bridge.test.ts
+++ b/src/app-bridge.test.ts
@@ -1,14 +1,6 @@
import { describe, it, expect, beforeEach, afterEach, spyOn } from "bun:test";
-import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
-import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import type { ServerCapabilities } from "@modelcontextprotocol/sdk/types.js";
-import {
- EmptyResultSchema,
- ListPromptsResultSchema,
- ListResourcesResultSchema,
- ListResourceTemplatesResultSchema,
- ReadResourceResultSchema,
-} from "@modelcontextprotocol/sdk/types.js";
+import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
+import { Server, type ServerCapabilities } from "@modelcontextprotocol/server";
import { z } from "zod/v4";
import { App } from "./app";
@@ -19,6 +11,7 @@ import {
getToolUiResourceUri,
isToolVisibilityModelOnly,
isToolVisibilityAppOnly,
+ McpUiOpenLinkResultSchema,
type McpUiHostCapabilities,
} from "./app-bridge";
@@ -31,11 +24,18 @@ const flush = () => new Promise((resolve) => setTimeout(resolve, 0));
*/
function createMockClient(
serverCapabilities: ServerCapabilities = {},
-): Pick {
+): Pick<
+ Client,
+ | "getServerCapabilities"
+ | "request"
+ | "notification"
+ | "setNotificationHandler"
+> {
return {
getServerCapabilities: () => serverCapabilities,
request: async () => ({}) as never,
notification: async () => {},
+ setNotificationHandler: () => {},
};
}
@@ -82,6 +82,58 @@ describe("App <-> AppBridge integration", () => {
expect(initializedFired).toBe(true);
});
+ it("keeps standard initialization separate from the Apps-ready gate", async () => {
+ const methods: string[] = [];
+ let releaseAppsInitialized!: () => void;
+ let reachedAppsInitialized!: () => void;
+ const appsInitializedGate = new Promise((resolve) => {
+ releaseAppsInitialized = resolve;
+ });
+ const reachedGate = new Promise((resolve) => {
+ reachedAppsInitialized = resolve;
+ });
+ const originalSend = appTransport.send.bind(appTransport);
+ appTransport.send = async (message, options) => {
+ if ("method" in message) methods.push(message.method);
+ if (
+ "method" in message &&
+ message.method === "ui/notifications/initialized"
+ ) {
+ reachedAppsInitialized();
+ await appsInitializedGate;
+ }
+ return originalSend(message, options);
+ };
+
+ let singularCalls = 0;
+ let listenerCalls = 0;
+ bridge.oninitialized = () => singularCalls++;
+ bridge.addEventListener("initialized", () => listenerCalls++);
+
+ await bridge.connect(bridgeTransport);
+ const connecting = app.connect(appTransport);
+ await reachedGate;
+
+ expect(methods).toEqual([
+ "initialize",
+ "notifications/initialized",
+ "ui/initialize",
+ "ui/notifications/initialized",
+ ]);
+ expect(app.getNegotiatedProtocolVersion()).toBe("2025-11-25");
+ expect(bridge.getNegotiatedProtocolVersion()).toBe("2025-11-25");
+ expect(bridge.getClientVersion()).toEqual(testAppInfo);
+ expect(bridge.getAppVersion()).toEqual(testAppInfo);
+ expect(singularCalls).toBe(0);
+ expect(listenerCalls).toBe(0);
+
+ releaseAppsInitialized();
+ await connecting;
+
+ expect(singularCalls).toBe(1);
+ expect(listenerCalls).toBe(1);
+ });
+
it("App receives host info and capabilities after connect", async () => {
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
@@ -91,6 +143,8 @@ describe("App <-> AppBridge integration", () => {
const hostCaps = app.getHostCapabilities();
expect(hostCaps).toEqual(testHostCapabilities);
+ expect(bridge.getHostCapabilities()).toEqual(testHostCapabilities);
+ expect(bridge.getCapabilities()).toEqual({});
});
it("Bridge receives app info and capabilities after initialization", async () => {
@@ -611,6 +665,30 @@ describe("App <-> AppBridge integration", () => {
expect(result.isError).toBe(true);
});
+
+ it("rejects invalid params for a custom ui request", async () => {
+ bridge.onopenlink = async () => ({});
+ await app.connect(appTransport);
+
+ await expect(
+ app.request(
+ {
+ method: "ui/open-link",
+ params: { url: 42 },
+ },
+ McpUiOpenLinkResultSchema,
+ ),
+ ).rejects.toThrow();
+ });
+
+ it("rejects invalid results from a custom ui handler", async () => {
+ bridge.onopenlink = async () => ({ isError: "yes" }) as never;
+ await app.connect(appTransport);
+
+ await expect(
+ app.openLink({ url: "https://example.com" }),
+ ).rejects.toThrow();
+ });
});
describe("deprecated method aliases", () => {
@@ -680,10 +758,7 @@ describe("App <-> AppBridge integration", () => {
await app.connect(appTransport);
// Bridge can send ping via the protocol's request method
- const result = await bridge.request(
- { method: "ping", params: {} },
- EmptyResultSchema,
- );
+ const result = await bridge.request({ method: "ping", params: {} });
expect(result).toEqual({});
});
@@ -798,7 +873,7 @@ describe("App <-> AppBridge integration", () => {
});
await bridge.callTool({ name: "noargs", arguments: {} });
expect(receivedExtra).toBeDefined();
- expect(receivedExtra.signal).toBeInstanceOf(AbortSignal);
+ expect(receivedExtra.mcpReq.signal).toBeInstanceOf(AbortSignal);
});
it("isError result skips output schema validation", async () => {
@@ -2180,10 +2255,10 @@ describe("App <-> AppBridge integration", () => {
await app.connect(appTransport);
// App sends resources/list request via the protocol's request method
- const result = await app.request(
- { method: "resources/list", params: requestParams },
- ListResourcesResultSchema,
- );
+ const result = await app.request({
+ method: "resources/list",
+ params: requestParams,
+ });
expect(receivedRequests).toHaveLength(1);
expect(receivedRequests[0]).toMatchObject(requestParams);
@@ -2224,10 +2299,10 @@ describe("App <-> AppBridge integration", () => {
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
- const result = await app.request(
- { method: "resources/read", params: requestParams },
- ReadResourceResultSchema,
- );
+ const result = await app.request({
+ method: "resources/read",
+ params: requestParams,
+ });
expect(receivedRequests).toHaveLength(1);
expect(receivedRequests[0]).toMatchObject(requestParams);
@@ -2275,10 +2350,10 @@ describe("App <-> AppBridge integration", () => {
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
- const result = await app.request(
- { method: "resources/templates/list", params: requestParams },
- ListResourceTemplatesResultSchema,
- );
+ const result = await app.request({
+ method: "resources/templates/list",
+ params: requestParams,
+ });
expect(receivedRequests).toHaveLength(1);
expect(receivedRequests[0]).toMatchObject(requestParams);
@@ -2298,10 +2373,10 @@ describe("App <-> AppBridge integration", () => {
await bridge.connect(bridgeTransport);
await app.connect(appTransport);
- const result = await app.request(
- { method: "prompts/list", params: requestParams },
- ListPromptsResultSchema,
- );
+ const result = await app.request({
+ method: "prompts/list",
+ params: requestParams,
+ });
expect(receivedRequests).toHaveLength(1);
expect(receivedRequests[0]).toMatchObject(requestParams);
@@ -2310,6 +2385,7 @@ describe("App <-> AppBridge integration", () => {
it("sendToolListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
+ bridge.oncalltool = async () => ({ content: [] });
app.setNotificationHandler(
"notifications/tools/list_changed",
(notification) => {
@@ -2328,6 +2404,7 @@ describe("App <-> AppBridge integration", () => {
it("sendResourceListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
+ bridge.onlistresources = async () => ({ resources: [] });
app.setNotificationHandler(
"notifications/resources/list_changed",
(notification) => {
@@ -2346,6 +2423,7 @@ describe("App <-> AppBridge integration", () => {
it("sendPromptListChanged sends notification to app", async () => {
const receivedNotifications: unknown[] = [];
+ bridge.onlistprompts = async () => ({ prompts: [] });
app.setNotificationHandler(
"notifications/prompts/list_changed",
(notification) => {
@@ -2364,6 +2442,184 @@ describe("App <-> AppBridge integration", () => {
});
});
+describe("AppBridge outer v2 Client proxy", () => {
+ let outerClient: Client;
+ let outerServer: Server;
+ let outerClientTransport: InMemoryTransport;
+ let outerServerTransport: InMemoryTransport;
+ let outerInitializeCount: number;
+
+ beforeEach(async () => {
+ [outerClientTransport, outerServerTransport] =
+ InMemoryTransport.createLinkedPair();
+ outerInitializeCount = 0;
+ const originalSend = outerClientTransport.send.bind(outerClientTransport);
+ outerClientTransport.send = async (message, options) => {
+ if ("method" in message && message.method === "initialize") {
+ outerInitializeCount++;
+ }
+ return originalSend(message, options);
+ };
+
+ outerServer = new Server(
+ { name: "ActualServer", version: "1.0.0" },
+ {
+ capabilities: {
+ tools: { listChanged: true },
+ resources: { listChanged: true },
+ prompts: { listChanged: true },
+ },
+ supportedProtocolVersions: ["2025-11-25"],
+ },
+ );
+ outerServer.setRequestHandler("tools/call", async (request) => ({
+ content: [
+ {
+ type: "text",
+ text: `outer:${request.params.name}`,
+ },
+ ],
+ }));
+
+ outerClient = new Client(
+ { name: "HostOuterClient", version: "1.0.0" },
+ {
+ capabilities: {},
+ versionNegotiation: { mode: "legacy" },
+ supportedProtocolVersions: ["2025-11-25"],
+ },
+ );
+ await outerServer.connect(outerServerTransport);
+ await outerClient.connect(outerClientTransport);
+ });
+
+ afterEach(async () => {
+ await outerClient.close().catch(() => {});
+ await outerServer.close().catch(() => {});
+ });
+
+ it("proxies through the outer Client without reconnecting it", async () => {
+ const bridge = new AppBridge(
+ outerClient,
+ testHostInfo,
+ testHostCapabilities,
+ );
+ const app = new App(testAppInfo, {}, { autoResize: false });
+ let [appTransport, bridgeTransport] = InMemoryTransport.createLinkedPair();
+
+ await bridge.connect(bridgeTransport);
+ await app.connect(appTransport);
+ expect(
+ await app.callServerTool({ name: "first", arguments: {} }),
+ ).toMatchObject({
+ content: [{ type: "text", text: "outer:first" }],
+ });
+ expect(outerInitializeCount).toBe(1);
+
+ await app.close();
+ await bridge.close();
+ [appTransport, bridgeTransport] = InMemoryTransport.createLinkedPair();
+ await bridge.connect(bridgeTransport);
+ await app.connect(appTransport);
+
+ expect(
+ await app.callServerTool({ name: "second", arguments: {} }),
+ ).toMatchObject({
+ content: [{ type: "text", text: "outer:second" }],
+ });
+ expect(outerInitializeCount).toBe(1);
+ expect(outerClient.getServerVersion()).toMatchObject({
+ name: "ActualServer",
+ version: "1.0.0",
+ });
+
+ await app.close();
+ await bridge.close();
+ });
+
+ it("propagates View cancellation to the actual outer Server", async () => {
+ let started!: () => void;
+ let aborted!: () => void;
+ const startedPromise = new Promise((resolve) => {
+ started = resolve;
+ });
+ const abortedPromise = new Promise((resolve) => {
+ aborted = resolve;
+ });
+ outerServer.setRequestHandler("tools/call", async (_request, context) => {
+ started();
+ await new Promise((resolve) => {
+ context.mcpReq.signal.addEventListener(
+ "abort",
+ () => {
+ aborted();
+ resolve();
+ },
+ { once: true },
+ );
+ });
+ return { content: [] };
+ });
+
+ const bridge = new AppBridge(
+ outerClient,
+ testHostInfo,
+ testHostCapabilities,
+ );
+ const app = new App(testAppInfo, {}, { autoResize: false });
+ const [appTransport, bridgeTransport] =
+ InMemoryTransport.createLinkedPair();
+ await bridge.connect(bridgeTransport);
+ await app.connect(appTransport);
+
+ const controller = new AbortController();
+ const result = app.callServerTool(
+ { name: "cancel-me", arguments: {} },
+ { signal: controller.signal },
+ );
+ await startedPromise;
+ controller.abort("test cancellation");
+ await abortedPromise;
+ await expect(result).rejects.toThrow();
+
+ await app.close();
+ await bridge.close();
+ });
+
+ it("forwards outer list-changed notifications to the App", async () => {
+ const bridge = new AppBridge(
+ outerClient,
+ testHostInfo,
+ testHostCapabilities,
+ );
+ const app = new App(testAppInfo, {}, { autoResize: false });
+ const [appTransport, bridgeTransport] =
+ InMemoryTransport.createLinkedPair();
+ const received: string[] = [];
+ app.setNotificationHandler("notifications/tools/list_changed", () => {
+ received.push("tools");
+ });
+ app.setNotificationHandler("notifications/resources/list_changed", () => {
+ received.push("resources");
+ });
+ app.setNotificationHandler("notifications/prompts/list_changed", () => {
+ received.push("prompts");
+ });
+
+ await bridge.connect(bridgeTransport);
+ await app.connect(appTransport);
+ await outerServer.sendToolListChanged();
+ await outerServer.sendResourceListChanged();
+ await outerServer.sendPromptListChanged();
+ await flush();
+
+ expect(received).toEqual(["tools", "resources", "prompts"]);
+
+ await app.close();
+ await bridge.close();
+ });
+});
+
describe("getToolUiResourceUri", () => {
describe("new nested format (_meta.ui.resourceUri)", () => {
it("extracts resourceUri from _meta.ui.resourceUri", () => {
@@ -2758,24 +3014,16 @@ describe("isToolVisibilityAppOnly", () => {
expect(app.onteardown).toBe(handler);
});
- it("direct setRequestHandler throws when called twice", () => {
+ it("direct setRequestHandler uses base SDK replacement semantics", () => {
const bridge2 = new AppBridge(
createMockClient() as Client,
testHostInfo,
testHostCapabilities,
);
- bridge2.setRequestHandler(
- // @ts-expect-error — exercising throw path with raw schema
- { shape: { method: { value: "test/method" } } },
- () => ({}),
- );
+ bridge2.setRequestHandler("ping", () => ({}));
expect(() => {
- bridge2.setRequestHandler(
- // @ts-expect-error — exercising throw path with raw schema
- { shape: { method: { value: "test/method" } } },
- () => ({}),
- );
- }).toThrow(/already registered/);
+ bridge2.setRequestHandler("ping", () => ({}));
+ }).not.toThrow();
});
});
});
diff --git a/src/app-bridge.ts b/src/app-bridge.ts
index 18d7671..c65510d 100644
--- a/src/app-bridge.ts
+++ b/src/app-bridge.ts
@@ -1,61 +1,51 @@
-import { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
+import { type Client } from "@modelcontextprotocol/client";
import {
- CallToolRequest,
- CallToolRequestSchema,
- CallToolResult,
- CallToolResultSchema,
- CreateMessageRequest,
- CreateMessageRequestSchema,
- CreateMessageResult,
- CreateMessageResultWithTools,
- EmptyResult,
- Implementation,
- ListPromptsRequest,
- ListPromptsRequestSchema,
- ListPromptsResult,
- ListPromptsResultSchema,
- ListResourcesRequest,
- ListResourcesRequestSchema,
- ListResourcesResult,
- ListResourcesResultSchema,
- ListResourceTemplatesRequest,
- ListResourceTemplatesRequestSchema,
- ListResourceTemplatesResult,
- ListResourceTemplatesResultSchema,
- ListToolsRequest,
- ListToolsRequestSchema,
- ListToolsResultSchema,
- LoggingMessageNotification,
+ Server,
+ type CallToolRequest,
+ type CallToolResult,
+ type CreateMessageRequest,
+ type CreateMessageResult,
+ type CreateMessageResultWithTools,
+ type EmptyResult,
+ type Implementation,
+ type JSONRPCRequest,
+ type ListPromptsRequest,
+ type ListPromptsResult,
+ type ListResourcesRequest,
+ type ListResourcesResult,
+ type ListResourceTemplatesRequest,
+ type ListResourceTemplatesResult,
+ type ListToolsRequest,
+ type LoggingMessageNotification,
+ type PingRequest,
+ type PromptListChangedNotification,
+ type ReadResourceRequest,
+ type ReadResourceResult,
+ type RequestOptions,
+ type ResourceListChangedNotification,
+ type Result,
+ type ServerCapabilities,
+ type ServerContext,
+ type ServerOptions,
+ type Tool,
+ type ToolListChangedNotification,
+ type Transport,
+} from "@modelcontextprotocol/server";
+import {
+ EmptyResultSchema,
LoggingMessageNotificationSchema,
- PingRequest,
- PingRequestSchema,
- PromptListChangedNotification,
- PromptListChangedNotificationSchema,
- ReadResourceRequest,
- ReadResourceRequestSchema,
- ReadResourceResult,
- ReadResourceResultSchema,
- ResourceListChangedNotification,
- ResourceListChangedNotificationSchema,
- Tool,
- ToolListChangedNotification,
- ToolListChangedNotificationSchema,
-} from "@modelcontextprotocol/sdk/types.js";
-import {
- Protocol,
- ProtocolOptions,
- RequestOptions,
-} from "@modelcontextprotocol/sdk/shared/protocol.js";
+} from "@modelcontextprotocol/core";
import { EventDispatcher } from "./events";
-import type { ZodLiteral, ZodObject } from "zod/v4";
+import type { ZodLiteral, ZodObject, ZodType } from "zod/v4";
-type MethodSchema = ZodObject<{ method: ZodLiteral }>;
+type MethodSchema = ZodObject<{
+ method: ZodLiteral;
+ params: ZodType;
+}>;
+
+const INNER_MCP_PROTOCOL_VERSION = "2025-11-25";
import {
- type AppNotification,
- type AppRequest,
- type AppResult,
type McpUiSandboxResourceReadyNotification,
type McpUiSizeChangedNotification,
type McpUiToolCancelledNotification,
@@ -74,15 +64,19 @@ import {
McpUiInitializeRequest,
McpUiInitializeRequestSchema,
McpUiInitializeResult,
+ McpUiInitializeResultSchema,
McpUiMessageRequest,
McpUiMessageRequestSchema,
McpUiMessageResult,
+ McpUiMessageResultSchema,
McpUiOpenLinkRequest,
McpUiOpenLinkRequestSchema,
McpUiOpenLinkResult,
+ McpUiOpenLinkResultSchema,
McpUiDownloadFileRequest,
McpUiDownloadFileRequestSchema,
McpUiDownloadFileResult,
+ McpUiDownloadFileResultSchema,
McpUiResourceTeardownRequest,
McpUiResourceTeardownResultSchema,
McpUiRequestTeardownNotification,
@@ -93,6 +87,7 @@ import {
McpUiRequestDisplayModeRequest,
McpUiRequestDisplayModeRequestSchema,
McpUiRequestDisplayModeResult,
+ McpUiRequestDisplayModeResultSchema,
McpUiResourcePermissions,
McpUiToolMeta,
} from "./types";
@@ -101,6 +96,20 @@ export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE } from "./app";
import { RESOURCE_URI_META_KEY } from "./app";
export { PostMessageTransport } from "./message-transport";
+function proxiedInnerCapabilities(
+ capabilities: ServerCapabilities,
+): ServerCapabilities {
+ return {
+ ...(capabilities.tools && { tools: capabilities.tools }),
+ ...(capabilities.resources && {
+ resources: {
+ listChanged: capabilities.resources.listChanged,
+ },
+ }),
+ ...(capabilities.prompts && { prompts: capabilities.prompts }),
+ };
+}
+
/**
* Extract UI resource URI from tool metadata.
*
@@ -206,10 +215,13 @@ export function buildAllowAttribute(
*
* @property hostContext - Optional initial host context to provide to the view
*
- * @see `ProtocolOptions` from @modelcontextprotocol/sdk for available options
+ * @see `ServerOptions` from @modelcontextprotocol/server for available options
* @see {@link McpUiHostContext `McpUiHostContext`} for the hostContext structure
*/
-export type HostOptions = ProtocolOptions & {
+export type HostOptions = Omit<
+ ServerOptions,
+ "capabilities" | "supportedProtocolVersions"
+> & {
hostContext?: McpUiHostContext;
};
@@ -224,15 +236,12 @@ export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION];
/**
* Extra metadata passed to request handlers.
*
- * This type represents the additional context provided by the `Protocol` class
- * when handling requests, including abort signals and session information.
- * It is extracted from the MCP SDK's request handler signature.
+ * This type represents the additional context provided by the base MCP SDK
+ * `Server` when handling requests.
*
* @internal
*/
-type RequestHandlerExtra = Parameters<
- Parameters[1]
->[1];
+type RequestHandlerExtra = ServerContext;
/**
* Maps DOM-style event names to their notification `params` types.
@@ -306,66 +315,53 @@ export type AppBridgeEventMap = {
* await bridge.connect(transport);
* ```
*/
-export class AppBridge extends Protocol {
+export class AppBridge extends Server {
private _appCapabilities?: McpUiAppCapabilities;
private _hostContext: McpUiHostContext = {};
private _appInfo?: Implementation;
private _initializedReceived = false;
- private readonly _registeredMethods = new Set();
private readonly _registeredEvents = new Set();
private readonly _events = new EventDispatcher();
- // ProtocolWithEvents previously owned these registration guards. Keep them
- // on AppBridge to preserve the existing double-registration behavior while
- // event fan-out moves to protocol-independent composition. Arrow-function
- // fields let Protocol's constructor run before the guards initialize.
- override setRequestHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setRequestHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setRequestHandler");
- super.setRequestHandler(schema, handler);
- };
-
- override setNotificationHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setNotificationHandler"] = (schema, handler) => {
- this._assertMethodNotRegistered(schema, "setNotificationHandler");
- super.setNotificationHandler(schema, handler);
- };
-
/**
- * Wrap every handler registered via `replaceRequestHandler` with a check
- * that the View has sent `ui/notifications/initialized`. Warns (never
- * throws) so lenient hosts keep working while still surfacing the
- * misordering that leaves strict hosts with a permanently hidden iframe.
- * `ui/initialize` and `ping` use `setRequestHandler` directly and are
- * intentionally exempt.
+ * The base MCP SDK calls this hook for every standard and custom request
+ * handler registration. AppBridge uses it to preserve the existing warning
+ * when a View calls host methods before `ui/notifications/initialized`,
+ * without adding overload-forwarding adapters around `setRequestHandler`.
+ * Chaining through `super._wrapHandler()` retains the base `Server`'s own
+ * role-specific behavior, including tool-result validation. The two
+ * initialization methods and `ping` are exempt because they are valid before
+ * the Apps-ready gate. This wraps registered callbacks, not JSON-RPC dispatch.
*
* @see {@link https://github.com/anthropics/claude-ai-mcp/issues/149 claude-ai-mcp#149}
*/
- protected replaceRequestHandler: Protocol<
- AppRequest,
- AppNotification,
- AppResult
- >["setRequestHandler"] = (schema, handler) => {
- const method = (schema as MethodSchema).shape.method.value;
- this._registeredMethods.add(method);
- super.setRequestHandler(schema, (request, extra) => {
+ protected override _wrapHandler(
+ method: string,
+ handler: (
+ request: JSONRPCRequest,
+ context: ServerContext,
+ ) => Promise,
+ ): (request: JSONRPCRequest, context: ServerContext) => Promise {
+ const wrapped = super._wrapHandler(method, handler);
+ if (
+ method === "initialize" ||
+ method === "ui/initialize" ||
+ method === "ping"
+ ) {
+ return wrapped;
+ }
+ return async (request, context) => {
if (!this._initializedReceived) {
console.warn(
- `[ext-apps] AppBridge received '${request.method}' before ` +
+ `[ext-apps] AppBridge received '${method}' before ` +
`ui/notifications/initialized. The View is calling host ` +
`methods before completing the handshake; it should await ` +
`app.connect() first.`,
);
}
- return handler(request, extra);
- });
- };
+ return wrapped(request, context);
+ };
+ }
private readonly eventSchemas: {
[K in keyof AppBridgeEventMap]: MethodSchema;
@@ -406,17 +402,27 @@ export class AppBridge extends Protocol
this._events.removeEventListener(event, handler);
}
- private _ensureEventSlot(
- event: K,
- ): void {
+ private _ensureEventSlot(event: K): void {
if (this._registeredEvents.has(event)) return;
const schema = this.eventSchemas[event];
if (!schema) throw new Error(`Unknown event: ${String(event)}`);
- this.setNotificationHandler(schema, (notification) => {
- const params = (notification as { params: AppBridgeEventMap[K] }).params;
+
+ const dispatch = (params: AppBridgeEventMap[K]) => {
if (event === "initialized") this._initializedReceived = true;
this._events.dispatch(event, params);
- });
+ };
+
+ if (event === "loggingmessage") {
+ this.setNotificationHandler("notifications/message", (notification) => {
+ dispatch(notification.params as AppBridgeEventMap[K]);
+ });
+ } else {
+ this.setNotificationHandler(
+ schema.shape.method.value,
+ { params: schema.shape.params },
+ (params) => dispatch(params as AppBridgeEventMap[K]),
+ );
+ }
this._registeredEvents.add(event);
}
@@ -433,16 +439,12 @@ export class AppBridge extends Protocol
}
}
- private _assertMethodNotRegistered(schema: unknown, via: string): void {
- const method = (schema as MethodSchema).shape.method.value;
- if (this._registeredMethods.has(method)) {
- throw new Error(
- `Handler for "${method}" already registered (via ${via}). ` +
- `Use addEventListener() to attach multiple listeners, ` +
- `or the on* setter for replace semantics.`,
- );
- }
- this._registeredMethods.add(method);
+ private ensureInnerCapabilities(capabilities: ServerCapabilities): void {
+ const current = super.getCapabilities();
+ const missing = Object.keys(capabilities).some(
+ (key) => current[key as keyof ServerCapabilities] === undefined,
+ );
+ if (missing) this.registerCapabilities(capabilities);
}
/**
@@ -453,8 +455,8 @@ export class AppBridge extends Protocol
* between the View and the server. When `null`, you must register handlers
* manually using the {@link oncalltool `oncalltool`}, {@link onlistresources `onlistresources`}, etc. setters.
* @param _hostInfo - Host application identification (name and version)
- * @param _capabilities - Features and capabilities the host supports
- * @param options - Configuration options (inherited from Protocol)
+ * @param _hostCapabilities - Features and capabilities the host supports
+ * @param options - Configuration options (inherited from Server)
*
* @example With MCP client (automatic forwarding)
* ```ts source="./app-bridge.examples.ts#AppBridge_constructor_withMcpClient"
@@ -481,29 +483,61 @@ export class AppBridge extends Protocol
constructor(
private _client: Client | null,
private _hostInfo: Implementation,
- private _capabilities: McpUiHostCapabilities,
+ private _hostCapabilities: McpUiHostCapabilities,
options?: HostOptions,
) {
- super(options);
+ // TEMPORARY INNER-CHANNEL NEGOTIATION:
+ // App and AppBridge use the public v2 Client/Server roles, so the iframe
+ // channel first completes the SDK's standard legacy MCP initialization.
+ // ui/initialize remains authoritative for Apps capabilities, identity, and
+ // host context, and ui/notifications/initialized remains the View-ready gate.
+ // Keep the inner MCP era pinned to 2025-11-25. Revisit this sequence only
+ // after the MCP Apps negotiation specification is resolved:
+ // https://github.com/modelcontextprotocol/ext-apps/issues/708
+ super(_hostInfo, {
+ ...options,
+ capabilities: {},
+ supportedProtocolVersions: [INNER_MCP_PROTOCOL_VERSION],
+ });
+
+ // The base Server's standard initialized callback is MCP-ready state. The
+ // public AppBridge callback remains exclusively the Apps View-ready gate.
+ super.setNotificationHandler("notifications/initialized", () => {});
+ Object.defineProperty(this, "oninitialized", {
+ configurable: true,
+ enumerable: true,
+ get: () => this.getEventHandler("initialized"),
+ set: (callback: AppBridge["oninitialized"]) =>
+ this.setEventHandler("initialized", callback),
+ });
this._ensureEventSlot("initialized");
this._hostContext = options?.hostContext || {};
- this.setRequestHandler(McpUiInitializeRequestSchema, (request) =>
- this._oninitialize(request),
+ this.setRequestHandler(
+ "ui/initialize",
+ {
+ params: McpUiInitializeRequestSchema.shape.params,
+ result: McpUiInitializeResultSchema,
+ },
+ (params) => this._onAppsInitialize(params),
);
- this.setRequestHandler(PingRequestSchema, (request, extra) => {
+ this.setRequestHandler("ping", (request, extra) => {
this.onping?.(request.params, extra);
return {};
});
// Default handler for requestDisplayMode - returns current mode from host context.
// Hosts can override this by setting bridge.onrequestdisplaymode = ...
- this.replaceRequestHandler(
- McpUiRequestDisplayModeRequestSchema,
- (request) => {
+ this.setRequestHandler(
+ "ui/request-display-mode",
+ {
+ params: McpUiRequestDisplayModeRequestSchema.shape.params,
+ result: McpUiRequestDisplayModeResultSchema,
+ },
+ () => {
const currentMode = this._hostContext.displayMode ?? "inline";
return { mode: currentMode };
},
@@ -680,18 +714,9 @@ export class AppBridge extends Protocol
* @see {@link sendToolInput `sendToolInput`} for sending tool arguments to the View
* @deprecated Use {@link addEventListener `addEventListener("initialized", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}.
*/
- get oninitialized():
- | ((params: McpUiInitializedNotification["params"]) => void)
- | undefined {
- return this.getEventHandler("initialized");
- }
- set oninitialized(
- callback:
- | ((params: McpUiInitializedNotification["params"]) => void)
- | undefined,
- ) {
- this.setEventHandler("initialized", callback);
- }
+ override oninitialized?: (
+ params?: McpUiInitializedNotification["params"],
+ ) => void;
/**
* Register a handler for message requests from the view.
@@ -744,11 +769,15 @@ export class AppBridge extends Protocol
) {
this.warnIfRequestHandlerReplaced("onmessage", this._onmessage, callback);
this._onmessage = callback;
- this.replaceRequestHandler(
- McpUiMessageRequestSchema,
- async (request, extra) => {
+ this.setRequestHandler(
+ "ui/message",
+ {
+ params: McpUiMessageRequestSchema.shape.params,
+ result: McpUiMessageResultSchema,
+ },
+ async (params, extra) => {
if (!this._onmessage) throw new Error("No onmessage handler set");
- return this._onmessage(request.params, extra);
+ return this._onmessage(params, extra);
},
);
}
@@ -813,11 +842,15 @@ export class AppBridge extends Protocol
) {
this.warnIfRequestHandlerReplaced("onopenlink", this._onopenlink, callback);
this._onopenlink = callback;
- this.replaceRequestHandler(
- McpUiOpenLinkRequestSchema,
- async (request, extra) => {
+ this.setRequestHandler(
+ "ui/open-link",
+ {
+ params: McpUiOpenLinkRequestSchema.shape.params,
+ result: McpUiOpenLinkResultSchema,
+ },
+ async (params, extra) => {
if (!this._onopenlink) throw new Error("No onopenlink handler set");
- return this._onopenlink(request.params, extra);
+ return this._onopenlink(params, extra);
},
);
}
@@ -885,12 +918,16 @@ export class AppBridge extends Protocol
callback,
);
this._ondownloadfile = callback;
- this.replaceRequestHandler(
- McpUiDownloadFileRequestSchema,
- async (request, extra) => {
+ this.setRequestHandler(
+ "ui/download-file",
+ {
+ params: McpUiDownloadFileRequestSchema.shape.params,
+ result: McpUiDownloadFileResultSchema,
+ },
+ async (params, extra) => {
if (!this._ondownloadfile)
throw new Error("No ondownloadfile handler set");
- return this._ondownloadfile(request.params, extra);
+ return this._ondownloadfile(params, extra);
},
);
}
@@ -985,12 +1022,16 @@ export class AppBridge extends Protocol
callback,
);
this._onrequestdisplaymode = callback;
- this.replaceRequestHandler(
- McpUiRequestDisplayModeRequestSchema,
- async (request, extra) => {
+ this.setRequestHandler(
+ "ui/request-display-mode",
+ {
+ params: McpUiRequestDisplayModeRequestSchema.shape.params,
+ result: McpUiRequestDisplayModeResultSchema,
+ },
+ async (params, extra) => {
if (!this._onrequestdisplaymode)
throw new Error("No onrequestdisplaymode handler set");
- return this._onrequestdisplaymode(request.params, extra);
+ return this._onrequestdisplaymode(params, extra);
},
);
}
@@ -1082,12 +1123,16 @@ export class AppBridge extends Protocol
callback,
);
this._onupdatemodelcontext = callback;
- this.replaceRequestHandler(
- McpUiUpdateModelContextRequestSchema,
- async (request, extra) => {
+ this.setRequestHandler(
+ "ui/update-model-context",
+ {
+ params: McpUiUpdateModelContextRequestSchema.shape.params,
+ result: EmptyResultSchema,
+ },
+ async (params, extra) => {
if (!this._onupdatemodelcontext)
throw new Error("No onupdatemodelcontext handler set");
- return this._onupdatemodelcontext(request.params, extra);
+ return this._onupdatemodelcontext(params, extra);
},
);
}
@@ -1135,13 +1180,11 @@ export class AppBridge extends Protocol
) {
this.warnIfRequestHandlerReplaced("oncalltool", this._oncalltool, callback);
this._oncalltool = callback;
- this.replaceRequestHandler(
- CallToolRequestSchema,
- async (request, extra) => {
- if (!this._oncalltool) throw new Error("No oncalltool handler set");
- return this._oncalltool(request.params, extra);
- },
- );
+ this.ensureInnerCapabilities({ tools: {} });
+ this.setRequestHandler("tools/call", async (request, extra) => {
+ if (!this._oncalltool) throw new Error("No oncalltool handler set");
+ return this._oncalltool(request.params, extra);
+ });
}
/**
@@ -1179,12 +1222,9 @@ export class AppBridge extends Protocol
extra: RequestHandlerExtra,
) => Promise,
) {
- this.setRequestHandler(
- CreateMessageRequestSchema,
- async (request, extra) => {
- return callback(request.params, extra);
- },
- );
+ this.setRequestHandler("sampling/createMessage", async (request, extra) => {
+ return callback(request.params, extra);
+ });
}
/**
@@ -1260,14 +1300,12 @@ export class AppBridge extends Protocol
callback,
);
this._onlistresources = callback;
- this.replaceRequestHandler(
- ListResourcesRequestSchema,
- async (request, extra) => {
- if (!this._onlistresources)
- throw new Error("No onlistresources handler set");
- return this._onlistresources(request.params, extra);
- },
- );
+ this.ensureInnerCapabilities({ resources: {} });
+ this.setRequestHandler("resources/list", async (request, extra) => {
+ if (!this._onlistresources)
+ throw new Error("No onlistresources handler set");
+ return this._onlistresources(request.params, extra);
+ });
}
/**
@@ -1317,8 +1355,9 @@ export class AppBridge extends Protocol
callback,
);
this._onlistresourcetemplates = callback;
- this.replaceRequestHandler(
- ListResourceTemplatesRequestSchema,
+ this.ensureInnerCapabilities({ resources: {} });
+ this.setRequestHandler(
+ "resources/templates/list",
async (request, extra) => {
if (!this._onlistresourcetemplates)
throw new Error("No onlistresourcetemplates handler set");
@@ -1374,14 +1413,12 @@ export class AppBridge extends Protocol
callback,
);
this._onreadresource = callback;
- this.replaceRequestHandler(
- ReadResourceRequestSchema,
- async (request, extra) => {
- if (!this._onreadresource)
- throw new Error("No onreadresource handler set");
- return this._onreadresource(request.params, extra);
- },
- );
+ this.ensureInnerCapabilities({ resources: {} });
+ this.setRequestHandler("resources/read", async (request, extra) => {
+ if (!this._onreadresource)
+ throw new Error("No onreadresource handler set");
+ return this._onreadresource(request.params, extra);
+ });
}
/**
@@ -1459,14 +1496,11 @@ export class AppBridge extends Protocol
callback,
);
this._onlistprompts = callback;
- this.replaceRequestHandler(
- ListPromptsRequestSchema,
- async (request, extra) => {
- if (!this._onlistprompts)
- throw new Error("No onlistprompts handler set");
- return this._onlistprompts(request.params, extra);
- },
- );
+ this.ensureInnerCapabilities({ prompts: {} });
+ this.setRequestHandler("prompts/list", async (request, extra) => {
+ if (!this._onlistprompts) throw new Error("No onlistprompts handler set");
+ return this._onlistprompts(request.params, extra);
+ });
}
/**
@@ -1495,46 +1529,6 @@ export class AppBridge extends Protocol
});
}
- /**
- * Verify that the guest supports the capability required for the given request method.
- * @internal
- */
- assertCapabilityForMethod(method: AppRequest["method"]): void {
- // TODO
- }
-
- /**
- * Verify that a request handler is registered and supported for the given method.
- * @internal
- */
- assertRequestHandlerCapability(method: AppRequest["method"]): void {
- // TODO
- }
-
- /**
- * Verify that the host supports the capability required for the given notification method.
- * @internal
- */
- assertNotificationCapability(method: AppNotification["method"]): void {
- // TODO
- }
-
- /**
- * Verify that task creation is supported for the given request method.
- * @internal
- */
- protected assertTaskCapability(_method: string): void {
- throw new Error("Tasks are not supported in MCP Apps");
- }
-
- /**
- * Verify that task handler is supported for the given method.
- * @internal
- */
- protected assertTaskHandlerCapability(_method: string): void {
- throw new Error("Task handlers are not supported in MCP Apps");
- }
-
/**
* Get the host capabilities passed to the constructor.
*
@@ -1542,18 +1536,18 @@ export class AppBridge extends Protocol
*
* @see {@link McpUiHostCapabilities `McpUiHostCapabilities`} for the capabilities structure
*/
- getCapabilities(): McpUiHostCapabilities {
- return this._capabilities;
+ getHostCapabilities(): McpUiHostCapabilities {
+ return this._hostCapabilities;
}
/**
* Handle the ui/initialize request from the guest.
* @internal
*/
- private async _oninitialize(
- request: McpUiInitializeRequest,
+ private async _onAppsInitialize(
+ params: McpUiInitializeRequest["params"],
): Promise {
- const requestedVersion = request.params.protocolVersion;
+ const requestedVersion = params.protocolVersion;
if (this._appInfo !== undefined) {
console.warn(
@@ -1564,8 +1558,8 @@ export class AppBridge extends Protocol
);
}
- this._appCapabilities = request.params.appCapabilities;
- this._appInfo = request.params.appInfo;
+ this._appCapabilities = params.appCapabilities;
+ this._appInfo = params.appInfo;
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(
requestedVersion,
@@ -1575,7 +1569,7 @@ export class AppBridge extends Protocol
return {
protocolVersion,
- hostCapabilities: this.getCapabilities(),
+ hostCapabilities: this.getHostCapabilities(),
hostInfo: this._hostInfo,
hostContext: this._hostContext,
};
@@ -1857,11 +1851,7 @@ export class AppBridge extends Protocol
* @returns Promise resolving to the tool call result
*/
callTool(params: CallToolRequest["params"], options?: RequestOptions) {
- return this.request(
- { method: "tools/call", params },
- CallToolResultSchema,
- options,
- );
+ return this.request({ method: "tools/call", params }, options);
}
/**
@@ -1874,11 +1864,7 @@ export class AppBridge extends Protocol
* @returns Promise resolving to the list of tools
*/
listTools(params: ListToolsRequest["params"], options?: RequestOptions) {
- return this.request(
- { method: "tools/list", params },
- ListToolsResultSchema,
- options,
- );
+ return this.request({ method: "tools/list", params }, options);
}
/**
@@ -1949,18 +1935,18 @@ export class AppBridge extends Protocol
if (!serverCapabilities) {
throw new Error("Client server capabilities not available");
}
+ this.registerCapabilities(proxiedInnerCapabilities(serverCapabilities));
if (serverCapabilities.tools) {
this.oncalltool = async (params, extra) => {
return this._client!.request(
{ method: "tools/call", params },
- CallToolResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
if (serverCapabilities.tools.listChanged) {
this._client.setNotificationHandler(
- ToolListChangedNotificationSchema,
+ "notifications/tools/list_changed",
(n) => this.sendToolListChanged(n.params),
);
}
@@ -1969,27 +1955,24 @@ export class AppBridge extends Protocol
this.onlistresources = async (params, extra) => {
return this._client!.request(
{ method: "resources/list", params },
- ListResourcesResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
this.onlistresourcetemplates = async (params, extra) => {
return this._client!.request(
{ method: "resources/templates/list", params },
- ListResourceTemplatesResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
this.onreadresource = async (params, extra) => {
return this._client!.request(
{ method: "resources/read", params },
- ReadResourceResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
if (serverCapabilities.resources.listChanged) {
this._client.setNotificationHandler(
- ResourceListChangedNotificationSchema,
+ "notifications/resources/list_changed",
(n) => this.sendResourceListChanged(n.params),
);
}
@@ -1998,22 +1981,20 @@ export class AppBridge extends Protocol
this.onlistprompts = async (params, extra) => {
return this._client!.request(
{ method: "prompts/list", params },
- ListPromptsResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
if (serverCapabilities.prompts.listChanged) {
this._client.setNotificationHandler(
- PromptListChangedNotificationSchema,
+ "notifications/prompts/list_changed",
(n) => this.sendPromptListChanged(n.params),
);
}
}
}
- // MCP-UI specific handlers are registered by the host component
- // after the proxy is created. The standard MCP initialization
- // (via oninitialized callback set in constructor) handles the ready signal.
+ // The standard MCP handshake only establishes the temporary inner Server
+ // role. ui/notifications/initialized remains the public View-ready signal.
return super.connect(transport);
}
From a76e3a76913b9482a5d00342184004ccaab44885 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 15:46:56 -0700
Subject: [PATCH 10/45] refactor: migrate shared SDK surfaces to v2
---
scripts/generate-schemas.ts | 6 +-
src/generated/schema.json | 182 +++++++++++++++++++++++-------------
src/generated/schema.ts | 2 +-
src/message-transport.ts | 8 +-
src/react/useApp.tsx | 3 +-
src/server/index.ts | 54 +++--------
src/spec.types.ts | 22 ++---
src/types.ts | 130 --------------------------
8 files changed, 149 insertions(+), 258 deletions(-)
diff --git a/scripts/generate-schemas.ts b/scripts/generate-schemas.ts
index 109f352..85225f5 100644
--- a/scripts/generate-schemas.ts
+++ b/scripts/generate-schemas.ts
@@ -12,7 +12,7 @@
*
* ts-to-zod generates `import { z } from "zod"`. We rewrite this to
* `import { z } from "zod/v4"` because the generated schemas compose with
- * schemas imported from `@modelcontextprotocol/sdk/types.js`, which the SDK
+ * schemas imported from `@modelcontextprotocol/core`, which the SDK
* constructs via `zod/v4`. Mixing schemas from the v3 and v4 APIs at runtime
* fails with errors like `keyValidator._parse is not a function` (v3 internals
* calling into v4 objects, or vice versa). The `zod/v4` subpath is exported by
@@ -22,7 +22,7 @@
*
* **Problem**: ts-to-zod cannot resolve types imported from external packages.
* When it encounters types like `ContentBlock`, `CallToolResult`, `Implementation`,
- * `RequestId`, and `Tool` from `@modelcontextprotocol/sdk`, it generates `z.any()`
+ * `RequestId`, and `Tool` from `@modelcontextprotocol/core`, it generates `z.any()`
* as a placeholder.
*
* **Solution**: Import the schemas from MCP SDK and remove the z.any() placeholders.
@@ -193,7 +193,7 @@ function postProcess(content: string): string {
`import { z } from "zod/v4";
import {
${mcpImports},
-} from "@modelcontextprotocol/sdk/types.js";`,
+} from "@modelcontextprotocol/core";`,
);
// 2. Remove z.any() placeholders for external types (now imported from MCP SDK)
diff --git a/src/generated/schema.json b/src/generated/schema.json
index 80b4ac6..5f2124a 100644
--- a/src/generated/schema.json
+++ b/src/generated/schema.json
@@ -596,7 +596,9 @@
"propertyNames": {
"type": "string"
},
- "additionalProperties": {}
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
},
"required": {
"type": "array",
@@ -611,25 +613,10 @@
"outputSchema": {
"type": "object",
"properties": {
- "type": {
- "type": "string",
- "const": "object"
- },
- "properties": {
- "type": "object",
- "propertyNames": {
- "type": "string"
- },
- "additionalProperties": {}
- },
- "required": {
- "type": "array",
- "items": {
- "type": "string"
- }
+ "$schema": {
+ "type": "string"
}
},
- "required": ["type"],
"additionalProperties": {}
},
"annotations": {
@@ -1286,7 +1273,40 @@
}
},
"required": ["method", "params"],
- "additionalProperties": false
+ "additionalProperties": false,
+ "$defs": {
+ "__schema0": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "null"
+ },
+ {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
+ },
+ {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/__schema0"
+ }
+ }
+ ]
+ }
+ }
},
"McpUiHostContext": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1359,7 +1379,9 @@
"propertyNames": {
"type": "string"
},
- "additionalProperties": {}
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
},
"required": {
"type": "array",
@@ -1374,25 +1396,10 @@
"outputSchema": {
"type": "object",
"properties": {
- "type": {
- "type": "string",
- "const": "object"
- },
- "properties": {
- "type": "object",
- "propertyNames": {
- "type": "string"
- },
- "additionalProperties": {}
- },
- "required": {
- "type": "array",
- "items": {
- "type": "string"
- }
+ "$schema": {
+ "type": "string"
}
},
- "required": ["type"],
"additionalProperties": {}
},
"annotations": {
@@ -2044,7 +2051,40 @@
"additionalProperties": false
}
},
- "additionalProperties": {}
+ "additionalProperties": {},
+ "$defs": {
+ "__schema0": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "null"
+ },
+ {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
+ },
+ {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/__schema0"
+ }
+ }
+ ]
+ }
+ }
},
"McpUiHostCss": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -2942,7 +2982,9 @@
"propertyNames": {
"type": "string"
},
- "additionalProperties": {}
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
},
"required": {
"type": "array",
@@ -2957,25 +2999,10 @@
"outputSchema": {
"type": "object",
"properties": {
- "type": {
- "type": "string",
- "const": "object"
- },
- "properties": {
- "type": "object",
- "propertyNames": {
- "type": "string"
- },
- "additionalProperties": {}
- },
- "required": {
- "type": "array",
- "items": {
- "type": "string"
- }
+ "$schema": {
+ "type": "string"
}
},
- "required": ["type"],
"additionalProperties": {}
},
"annotations": {
@@ -3637,7 +3664,40 @@
"hostCapabilities",
"hostContext"
],
- "additionalProperties": {}
+ "additionalProperties": {},
+ "$defs": {
+ "__schema0": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "null"
+ },
+ {
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "$ref": "#/$defs/__schema0"
+ }
+ },
+ {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/__schema0"
+ }
+ }
+ ]
+ }
+ }
},
"McpUiInitializedNotification": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -5669,13 +5729,7 @@
]
}
},
- "structuredContent": {
- "type": "object",
- "propertyNames": {
- "type": "string"
- },
- "additionalProperties": {}
- },
+ "structuredContent": {},
"isError": {
"type": "boolean"
}
diff --git a/src/generated/schema.ts b/src/generated/schema.ts
index 4368737..341c7b4 100644
--- a/src/generated/schema.ts
+++ b/src/generated/schema.ts
@@ -10,7 +10,7 @@ import {
RequestIdSchema,
ResourceLinkSchema,
ToolSchema,
-} from "@modelcontextprotocol/sdk/types.js";
+} from "@modelcontextprotocol/core";
/**
* @description Color theme preference for the host environment.
diff --git a/src/message-transport.ts b/src/message-transport.ts
index 9d19543..9483540 100644
--- a/src/message-transport.ts
+++ b/src/message-transport.ts
@@ -1,12 +1,10 @@
-import {
+import { JSONRPCMessageSchema } from "@modelcontextprotocol/core";
+import type {
JSONRPCMessage,
- JSONRPCMessageSchema,
MessageExtraInfo,
-} from "@modelcontextprotocol/sdk/types.js";
-import {
Transport,
TransportSendOptions,
-} from "@modelcontextprotocol/sdk/shared/transport.js";
+} from "@modelcontextprotocol/client";
import { TOOL_INPUT_PARTIAL_METHOD } from "./spec.types";
/**
diff --git a/src/react/useApp.tsx b/src/react/useApp.tsx
index 6189246..0e64a74 100644
--- a/src/react/useApp.tsx
+++ b/src/react/useApp.tsx
@@ -1,6 +1,5 @@
import { useEffect, useState } from "react";
-import { Implementation } from "@modelcontextprotocol/sdk/types.js";
-import { Client } from "@modelcontextprotocol/sdk/client";
+import type { Implementation } from "@modelcontextprotocol/client";
import {
App,
AppOptions,
diff --git a/src/server/index.ts b/src/server/index.ts
index c90514a..b8b3ad0 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -40,24 +40,17 @@ import {
McpUiClientCapabilities,
} from "../app.js";
import type {
- BaseToolCallback,
+ ClientCapabilities,
McpServer,
+ ReadResourceResult,
RegisteredTool,
ResourceMetadata,
+ StandardSchemaWithJSON,
+ ToolAnnotations,
ToolCallback,
ReadResourceCallback as _ReadResourceCallback,
RegisteredResource,
-} from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- AnySchema,
- ZodRawShapeCompat,
-} from "@modelcontextprotocol/sdk/server/zod-compat.js";
-import type { StandardSchemaWithJSON } from "../standard-schema";
-import type {
- ClientCapabilities,
- ReadResourceResult,
- ToolAnnotations,
-} from "@modelcontextprotocol/sdk/types.js";
+} from "@modelcontextprotocol/server";
// Re-exports for convenience
export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE };
@@ -70,8 +63,8 @@ export type { ResourceMetadata, ToolCallback };
export interface ToolConfig {
title?: string;
description?: string;
- inputSchema?: ZodRawShapeCompat | StandardSchemaWithJSON;
- outputSchema?: ZodRawShapeCompat | StandardSchemaWithJSON;
+ inputSchema?: StandardSchemaWithJSON;
+ outputSchema?: StandardSchemaWithJSON;
annotations?: ToolAnnotations;
_meta?: Record;
}
@@ -215,9 +208,8 @@ export interface McpUiAppResourceConfig extends ResourceMetadata {
* @see {@link registerAppResource `registerAppResource`} to register the HTML resource referenced by the tool
*/
export function registerAppTool<
- OutputArgs extends ZodRawShapeCompat | StandardSchemaWithJSON,
- InputArgs extends undefined | ZodRawShapeCompat | StandardSchemaWithJSON =
- undefined,
+ OutputArgs extends StandardSchemaWithJSON,
+ InputArgs extends StandardSchemaWithJSON | undefined = undefined,
>(
server: Pick,
name: string,
@@ -225,15 +217,7 @@ export function registerAppTool<
inputSchema?: InputArgs;
outputSchema?: OutputArgs;
},
- // The widened constraint signals the v2 API shape, but NOTE: McpServer in
- // sdk@1.x still calls zod internals at runtime, so non-zod schemas will fail
- // here until we depend on sdk v2. Zod (which all current callers use) is
- // unaffected. The cast below bridges the 1.x type signature.
- cb: ToolCallback<
- InputArgs extends undefined | ZodRawShapeCompat | AnySchema
- ? InputArgs
- : AnySchema
- >,
+ cb: ToolCallback,
): RegisteredTool {
// Normalize metadata for backward compatibility:
// - If _meta.ui.resourceUri is set, also set the legacy flat key
@@ -251,14 +235,7 @@ export function registerAppTool<
normalizedMeta = { ...meta, ui: { ...uiMeta, resourceUri: legacyUri } };
}
- // Cast bridges the widened StandardSchemaWithJSON constraint to the
- // sdk@1.x zod-typed signature. Drops once we depend on sdk v2.
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- return server.registerTool(
- name,
- { ...config, _meta: normalizedMeta } as any,
- cb as any,
- );
+ return server.registerTool(name, { ...config, _meta: normalizedMeta }, cb);
}
export type McpUiReadResourceResult = ReadResourceResult & {
@@ -418,10 +395,6 @@ export const EXTENSION_ID = "io.modelcontextprotocol/ui";
* This helper retrieves the capability object from the `extensions` field
* where MCP Apps advertises its support.
*
- * Note: The `clientCapabilities` parameter extends the SDK's `ClientCapabilities`
- * type with an `extensions` field (pending SEP-1724). Once `extensions` is added
- * to the SDK, this can use `ClientCapabilities` directly.
- *
* @param clientCapabilities - The client capabilities from the initialize response
* @returns The MCP Apps capability settings, or `undefined` if not supported
*
@@ -456,10 +429,7 @@ export const EXTENSION_ID = "io.modelcontextprotocol/ui";
* ```
*/
export function getUiCapability(
- clientCapabilities:
- | (ClientCapabilities & { extensions?: Record })
- | null
- | undefined,
+ clientCapabilities: ClientCapabilities | null | undefined,
): McpUiClientCapabilities | undefined {
if (!clientCapabilities) {
return undefined;
diff --git a/src/spec.types.ts b/src/spec.types.ts
index 7a8b337..8b03de9 100644
--- a/src/spec.types.ts
+++ b/src/spec.types.ts
@@ -18,7 +18,7 @@ import type {
RequestId,
ResourceLink,
Tool,
-} from "@modelcontextprotocol/sdk/types.js";
+} from "@modelcontextprotocol/client";
/**
* Current protocol version supported by this SDK.
@@ -163,8 +163,8 @@ export interface McpUiOpenLinkResult {
/** @description True if the host failed to open the URL (e.g., due to security policy). */
isError?: boolean;
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
- * Note: The generated schema uses passthrough() to allow additional properties.
+ * Additional result properties are preserved for protocol extensibility.
+ * The generated schema uses passthrough() to allow them.
*/
[key: string]: unknown;
}
@@ -195,8 +195,8 @@ export interface McpUiDownloadFileResult {
/** @description True if the download failed (e.g., user cancelled or host denied). */
isError?: boolean;
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
- * Note: The generated schema uses passthrough() to allow additional properties.
+ * Additional result properties are preserved for protocol extensibility.
+ * The generated schema uses passthrough() to allow them.
*/
[key: string]: unknown;
}
@@ -223,8 +223,8 @@ export interface McpUiMessageResult {
/** @description True if the host rejected or failed to deliver the message. */
isError?: boolean;
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
- * Note: The generated schema uses passthrough() to allow additional properties.
+ * Additional result properties are preserved for protocol extensibility.
+ * The generated schema uses passthrough() to allow them.
*/
[key: string]: unknown;
}
@@ -454,7 +454,7 @@ export interface McpUiResourceTeardownRequest {
*/
export interface McpUiResourceTeardownResult {
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
+ * Additional result properties are preserved for protocol extensibility.
*/
[key: string]: unknown;
}
@@ -577,8 +577,8 @@ export interface McpUiInitializeResult {
/** @description Rich context about the host environment. */
hostContext: McpUiHostContext;
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
- * Note: The generated schema uses passthrough() to allow additional properties.
+ * Additional result properties are preserved for protocol extensibility.
+ * The generated schema uses passthrough() to allow them.
*/
[key: string]: unknown;
}
@@ -752,7 +752,7 @@ export interface McpUiRequestDisplayModeResult {
/** @description The display mode that was actually set. May differ from requested if not supported. */
mode: McpUiDisplayMode;
/**
- * Index signature required for MCP SDK `Protocol` class compatibility.
+ * Additional result properties are preserved for protocol extensibility.
* Note: The generated schema uses passthrough() to allow additional properties.
*/
[key: string]: unknown;
diff --git a/src/types.ts b/src/types.ts
index 7fc6b71..655812b 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -69,33 +69,6 @@ export {
type McpUiClientCapabilities,
} from "./spec.types.js";
-// Import types needed for protocol type unions (not re-exported, just used internally)
-import type {
- McpUiInitializeRequest,
- McpUiOpenLinkRequest,
- McpUiDownloadFileRequest,
- McpUiMessageRequest,
- McpUiUpdateModelContextRequest,
- McpUiResourceTeardownRequest,
- McpUiRequestDisplayModeRequest,
- McpUiHostContextChangedNotification,
- McpUiToolInputNotification,
- McpUiToolInputPartialNotification,
- McpUiToolResultNotification,
- McpUiToolCancelledNotification,
- McpUiSandboxResourceReadyNotification,
- McpUiInitializedNotification,
- McpUiSizeChangedNotification,
- McpUiSandboxProxyReadyNotification,
- McpUiRequestTeardownNotification,
- McpUiInitializeResult,
- McpUiOpenLinkResult,
- McpUiDownloadFileResult,
- McpUiMessageResult,
- McpUiResourceTeardownResult,
- McpUiRequestDisplayModeResult,
-} from "./spec.types.js";
-
// Re-export all schemas from generated/schema.ts (already PascalCase)
export {
McpUiThemeSchema,
@@ -135,106 +108,3 @@ export {
McpUiToolVisibilitySchema,
McpUiToolMetaSchema,
} from "./generated/schema.js";
-
-// Re-export SDK types used in protocol type unions
-import {
- CallToolRequest,
- CallToolResult,
- CreateMessageRequest,
- CreateMessageResult,
- CreateMessageResultWithTools,
- EmptyResult,
- ListPromptsRequest,
- ListPromptsResult,
- ListResourcesRequest,
- ListResourcesResult,
- ListResourceTemplatesRequest,
- ListResourceTemplatesResult,
- ListToolsRequest,
- ListToolsResult,
- LoggingMessageNotification,
- PingRequest,
- PromptListChangedNotification,
- ReadResourceRequest,
- ReadResourceResult,
- ResourceListChangedNotification,
- ToolListChangedNotification,
-} from "@modelcontextprotocol/sdk/types.js";
-
-/**
- * All request types in the MCP Apps protocol.
- *
- * Includes:
- * - MCP UI requests (initialize, open-link, message, resource-teardown, request-display-mode)
- * - MCP server requests forwarded from the app (tools/call, tools/list, resources/list,
- * resources/templates/list, resources/read, prompts/list)
- * - MCP client requests forwarded to the host (sampling/createMessage)
- * - Protocol requests (ping)
- */
-export type AppRequest =
- | McpUiInitializeRequest
- | McpUiOpenLinkRequest
- | McpUiDownloadFileRequest
- | McpUiMessageRequest
- | McpUiUpdateModelContextRequest
- | McpUiResourceTeardownRequest
- | McpUiRequestDisplayModeRequest
- | CallToolRequest
- | ListToolsRequest
- | ListResourcesRequest
- | ListResourceTemplatesRequest
- | ReadResourceRequest
- | ListPromptsRequest
- | CreateMessageRequest
- | PingRequest;
-
-/**
- * All notification types in the MCP Apps protocol.
- *
- * Host to app:
- * - Tool lifecycle (input, input-partial, result, cancelled)
- * - Host context changes
- * - MCP list changes (tools, resources, prompts)
- * - Sandbox resource ready
- *
- * App to host:
- * - Initialized, size-changed, sandbox-proxy-ready, request-teardown
- * - Logging messages
- */
-export type AppNotification =
- // Sent to app
- | McpUiHostContextChangedNotification
- | McpUiToolInputNotification
- | McpUiToolInputPartialNotification
- | McpUiToolResultNotification
- | McpUiToolCancelledNotification
- | McpUiSandboxResourceReadyNotification
- | ToolListChangedNotification
- | ResourceListChangedNotification
- | PromptListChangedNotification
- // Received from app
- | McpUiInitializedNotification
- | McpUiSizeChangedNotification
- | McpUiSandboxProxyReadyNotification
- | McpUiRequestTeardownNotification
- | LoggingMessageNotification;
-
-/**
- * All result types in the MCP Apps protocol.
- */
-export type AppResult =
- | McpUiInitializeResult
- | McpUiOpenLinkResult
- | McpUiDownloadFileResult
- | McpUiMessageResult
- | McpUiResourceTeardownResult
- | McpUiRequestDisplayModeResult
- | CallToolResult
- | ListToolsResult
- | ListResourcesResult
- | ListResourceTemplatesResult
- | ReadResourceResult
- | ListPromptsResult
- | CreateMessageResult
- | CreateMessageResultWithTools
- | EmptyResult;
From f94cb38b0b6453476cb45e3edccf606505be7708 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 17:07:30 -0700
Subject: [PATCH 11/45] refactor: finish MCP SDK v2 migration
---
AGENTS.md | 8 +-
README.md | 10 +-
build.bun.ts | 12 +-
docs/authorization.md | 2 +-
docs/migrate_from_openai_apps.md | 8 +-
docs/overview.md | 8 +-
docs/patterns.md | 11 +-
docs/patterns.tsx | 17 +--
docs/quickstart.md | 19 +--
docs/testing-mcp-apps.md | 4 +
examples/basic-host/package.json | 2 +-
examples/basic-host/src/implementation.ts | 12 +-
examples/basic-host/src/index.tsx | 2 +-
examples/basic-server-preact/main.ts | 10 +-
examples/basic-server-preact/package.json | 3 +-
examples/basic-server-preact/server.ts | 10 +-
examples/basic-server-preact/src/mcp-app.tsx | 2 +-
examples/basic-server-react/main.ts | 10 +-
examples/basic-server-react/package.json | 3 +-
examples/basic-server-react/server.ts | 10 +-
examples/basic-server-react/src/mcp-app.tsx | 2 +-
examples/basic-server-solid/main.ts | 10 +-
examples/basic-server-solid/package.json | 3 +-
examples/basic-server-solid/server.ts | 10 +-
examples/basic-server-solid/src/mcp-app.tsx | 2 +-
examples/basic-server-svelte/main.ts | 10 +-
examples/basic-server-svelte/package.json | 3 +-
examples/basic-server-svelte/server.ts | 10 +-
examples/basic-server-svelte/src/App.svelte | 2 +-
examples/basic-server-vanillajs/main.ts | 10 +-
examples/basic-server-vanillajs/package.json | 3 +-
examples/basic-server-vanillajs/server.ts | 9 +-
.../basic-server-vanillajs/src/mcp-app.ts | 2 +-
examples/basic-server-vue/main.ts | 10 +-
examples/basic-server-vue/package.json | 3 +-
examples/basic-server-vue/server.ts | 10 +-
examples/basic-server-vue/src/App.vue | 2 +-
examples/budget-allocator-server/main.ts | 10 +-
examples/budget-allocator-server/package.json | 2 +-
examples/budget-allocator-server/server.ts | 12 +-
examples/cohort-heatmap-server/main.ts | 10 +-
examples/cohort-heatmap-server/package.json | 2 +-
examples/cohort-heatmap-server/server.ts | 10 +-
examples/customer-segmentation-server/main.ts | 10 +-
.../customer-segmentation-server/package.json | 2 +-
.../customer-segmentation-server/server.ts | 14 +--
examples/debug-server/main.ts | 10 +-
examples/debug-server/package.json | 2 +-
examples/debug-server/server.ts | 10 +-
examples/integration-server/main.ts | 10 +-
examples/integration-server/package.json | 3 +-
examples/integration-server/server.ts | 14 +--
examples/integration-server/src/mcp-app.tsx | 2 +-
examples/lazy-auth-server/package.json | 5 +-
examples/lazy-auth-server/server.ts | 29 ++---
examples/map-server/main.ts | 10 +-
examples/map-server/package.json | 3 +-
examples/map-server/server.ts | 18 +--
examples/map-server/src/mcp-app.ts | 2 +-
examples/pdf-server/main.ts | 10 +-
examples/pdf-server/package.json | 3 +-
examples/pdf-server/server.test.ts | 3 +-
examples/pdf-server/server.ts | 57 +++++----
examples/pdf-server/src/mcp-app.ts | 6 +-
examples/qr-server/package.json | 3 +-
examples/quickstart/main.ts | 10 +-
examples/quickstart/package.json | 5 +-
examples/quickstart/server.ts | 5 +-
examples/say-server/package.json | 3 +-
examples/scenario-modeler-server/main.ts | 10 +-
examples/scenario-modeler-server/package.json | 2 +-
examples/scenario-modeler-server/server.ts | 14 +--
examples/shadertoy-server/main.ts | 10 +-
examples/shadertoy-server/package.json | 2 +-
examples/shadertoy-server/server.ts | 10 +-
examples/sheet-music-server/main.ts | 10 +-
examples/sheet-music-server/package.json | 2 +-
examples/sheet-music-server/server.ts | 10 +-
examples/system-monitor-server/main.ts | 10 +-
examples/system-monitor-server/package.json | 2 +-
examples/system-monitor-server/server.ts | 18 +--
examples/threejs-server/main.ts | 10 +-
examples/threejs-server/package.json | 3 +-
examples/threejs-server/server.ts | 12 +-
.../threejs-server/src/mcp-app-wrapper.tsx | 2 +-
examples/transcript-server/main.ts | 10 +-
examples/transcript-server/package.json | 2 +-
examples/transcript-server/server.ts | 13 +-
examples/video-resource-server/main.ts | 10 +-
examples/video-resource-server/package.json | 3 +-
examples/video-resource-server/server.ts | 12 +-
examples/video-resource-server/src/mcp-app.ts | 2 +-
examples/wiki-explorer-server/main.ts | 10 +-
examples/wiki-explorer-server/package.json | 3 +-
examples/wiki-explorer-server/server.ts | 10 +-
examples/wiki-explorer-server/src/mcp-app.ts | 2 +-
package-lock.json | 95 +++++++++------
package.json | 2 -
.../skills/add-app-to-server/SKILL.md | 111 +++++++++++-------
.../mcp-apps/skills/convert-web-app/SKILL.md | 57 +++++----
.../mcp-apps/skills/create-mcp-app/SKILL.md | 5 +-
scripts/typedoc-plugin-base-sdk-links.mjs | 16 +++
src/app-bridge.examples.ts | 36 +++---
src/app-bridge.ts | 62 +++++-----
src/app.examples.ts | 9 +-
src/app.ts | 19 ++-
src/events.ts | 5 +-
src/message-transport.test.ts | 2 +-
src/server/index.examples.ts | 11 +-
src/server/index.test.ts | 2 +-
src/server/index.ts | 4 +-
typedoc.config.mjs | 25 ++++
112 files changed, 684 insertions(+), 540 deletions(-)
create mode 100644 scripts/typedoc-plugin-base-sdk-links.mjs
diff --git a/AGENTS.md b/AGENTS.md
index 6bfc8cd..f850aa3 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -60,8 +60,8 @@ rm -fR package-lock.json node_modules && \
### Key Source Files
-- `src/app.ts` - `App` class extends MCP Protocol, handles guest initialization, tool calls, messaging
-- `src/app-bridge.ts` - `AppBridge` class for hosts, proxies MCP requests, sends tool input/results to guests
+- `src/app.ts` - `App` subclasses the base MCP SDK `Client`, handles View initialization, tool calls, and messaging
+- `src/app-bridge.ts` - `AppBridge` subclasses the base MCP SDK `Server` for the inner 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
@@ -70,12 +70,12 @@ rm -fR package-lock.json node_modules && \
### Protocol Flow
```
-View (App) <--PostMessageTransport--> Host (AppBridge) <--MCP Client--> MCP Server
+View (App/Client) <--PostMessageTransport--> Host (AppBridge/Server) <--separate MCP Client--> MCP Server
```
1. Host creates iframe with view HTML
2. View creates `App` instance and calls `connect()` with `PostMessageTransport`
-3. View sends `ui/initialize` request, receives host capabilities and context
+3. View and Host complete the temporary inner base MCP handshake, then the View sends `ui/initialize` and receives authoritative Apps capabilities and context
4. Host sends `sendToolInput()` with tool arguments after initialization
5. View can call server tools via `app.callServerTool()` or send messages via `app.sendMessage()`
6. Host sends `sendToolResult()` when tool execution completes
diff --git a/README.md b/README.md
index 2fd89ff..b3f68e7 100644
--- a/README.md
+++ b/README.md
@@ -122,9 +122,17 @@ resources:
## Getting Started
```bash
-npm install -S @modelcontextprotocol/ext-apps
+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
```
+This release uses the split base MCP SDK v2 packages. Install all three at the
+exact published beta.4 version so the Apps SDK and your MCP client/server share
+one compatible protocol implementation.
+
**New here?** Start with the
[Quickstart Guide](https://apps.extensions.modelcontextprotocol.io/api/documents/Quickstart.html)
to build your first MCP App.
diff --git a/build.bun.ts b/build.bun.ts
index a129d5d..837279f 100644
--- a/build.bun.ts
+++ b/build.bun.ts
@@ -31,9 +31,15 @@ function buildJs(
});
}
-// zod is a peerDependency — keep it external so consumers share a single
-// zod instance (instanceof ZodError / schema.extend() break with duplicate copies).
-const PEER_EXTERNALS = ["@modelcontextprotocol/sdk", "zod"];
+// Peer dependencies stay external in the standard entry points so consumers
+// share one base MCP SDK and Zod instance. The *-with-deps entry points keep
+// bundling these dependencies for standalone browser use.
+const PEER_EXTERNALS = [
+ "@modelcontextprotocol/client",
+ "@modelcontextprotocol/core",
+ "@modelcontextprotocol/server",
+ "zod",
+];
await Promise.all([
buildJs("src/app.ts", {
diff --git a/docs/authorization.md b/docs/authorization.md
index 59fc26c..df7adc6 100644
--- a/docs/authorization.md
+++ b/docs/authorization.md
@@ -150,7 +150,7 @@ registerAppTool(
"get_account_balance",
{
description: "Get account balance",
- inputSchema: { accountId: z.string() },
+ inputSchema: z.object({ accountId: z.string() }),
},
async ({ accountId }) => {
if (!authInfo) {
diff --git a/docs/migrate_from_openai_apps.md b/docs/migrate_from_openai_apps.md
index d91281b..22d5d9f 100644
--- a/docs/migrate_from_openai_apps.md
+++ b/docs/migrate_from_openai_apps.md
@@ -66,7 +66,7 @@ The server-side changes involve updating metadata structure and using helper fun
#### Before (OpenAI)
```typescript
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
function createServer() {
@@ -78,7 +78,7 @@ function createServer() {
{
title: "Shopping Cart",
description: "Display the user's shopping cart",
- inputSchema: { userId: z.string() },
+ inputSchema: z.object({ userId: z.string() }),
annotations: { readOnlyHint: true },
_meta: {
"openai/outputTemplate": "ui://view/cart.html",
@@ -126,7 +126,7 @@ function createServer() {
#### After (MCP Apps)
```typescript
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { McpServer } from "@modelcontextprotocol/server";
import {
registerAppTool,
registerAppResource,
@@ -144,7 +144,7 @@ function createServer() {
{
title: "Shopping Cart",
description: "Display the user's shopping cart",
- inputSchema: { userId: z.string() },
+ inputSchema: z.object({ userId: z.string() }),
annotations: { readOnlyHint: true },
_meta: { ui: { resourceUri: "ui://view/cart.html" } },
},
diff --git a/docs/overview.md b/docs/overview.md
index 28f5b23..317ab43 100644
--- a/docs/overview.md
+++ b/docs/overview.md
@@ -56,7 +56,11 @@ 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 acts as an MCP client, the Host acts as a proxy, and the Server is a standard MCP server.
+The View's `App` subclasses the base MCP SDK `Client`. The Host's `AppBridge`
+subclasses the base MCP SDK `Server` for the inner iframe channel, while a
+separate outer `Client` connects the Host to the actual MCP Server. Keeping
+those two connections separate prevents iframe negotiation and capabilities
+from leaking into the server connection.
## Lifecycle
@@ -93,7 +97,7 @@ sequenceDiagram
```
1. **Discovery** — The Host learns about tools and their UI resources when connecting to the server.
-2. **Initialization** — When a UI tool is called, the Host renders the iframe. The View sends `ui/initialize` and receives host context (theme, capabilities, container dimensions). This handshake ensures the View is ready before receiving data.
+2. **Initialization** — When a UI tool is called, the Host renders the iframe. The SDK first completes its temporary inner base MCP handshake, then the View sends `ui/initialize` and receives host context (theme, capabilities, container dimensions). `ui/initialize` remains authoritative for Apps capabilities and identity, and `ui/notifications/initialized` remains the public View-ready signal.
3. **Data delivery** — The Host sends tool arguments and, once available, tool results to the View. Results include both `content` (text for the model's context) and optionally `structuredContent` (data optimized for UI rendering). This separation lets servers provide rich data to the UI without bloating the model's context.
4. **Interactive phase** — The user interacts with the View. The View can call tools, send messages, or update context.
5. **Teardown** — Before unmounting, the Host notifies the View so it can save state or release resources.
diff --git a/docs/patterns.md b/docs/patterns.md
index 87a6d82..884de26 100644
--- a/docs/patterns.md
+++ b/docs/patterns.md
@@ -19,7 +19,7 @@ registerAppTool(
"update-quantity",
{
description: "Update item quantity in cart",
- inputSchema: { itemId: z.string(), quantity: z.number() },
+ inputSchema: z.object({ itemId: z.string(), quantity: z.number() }),
_meta: {
ui: {
resourceUri: "ui://shop/cart.html",
@@ -127,14 +127,14 @@ registerAppTool(
{
title: "Read Data Bytes",
description: "Load binary data in chunks",
- inputSchema: {
+ inputSchema: z.object({
id: z.string().describe("Resource identifier"),
offset: z.number().min(0).default(0).describe("Byte offset"),
byteCount: z
.number()
.default(MAX_CHUNK_BYTES)
.describe("Bytes to read"),
- },
+ }),
outputSchema: DataChunkSchema,
// Hidden from model - only callable by the App
_meta: { ui: { visibility: ["app"] } },
@@ -281,10 +281,7 @@ server.registerResource(
```ts source="./patterns.tsx#binaryBlobResourceClient"
-const result = await app.request(
- { method: "resources/read", params: { uri: `video://${videoId}` } },
- ReadResourceResultSchema,
-);
+const result = await app.readServerResource({ uri: `video://${videoId}` });
const content = result.contents[0];
if (!content || !("blob" in content)) {
diff --git a/docs/patterns.tsx b/docs/patterns.tsx
index 6b87692..bb9eaa4 100644
--- a/docs/patterns.tsx
+++ b/docs/patterns.tsx
@@ -17,16 +17,12 @@ import { randomUUID } from "node:crypto";
import type {
CallToolResult,
ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
-import { ReadResourceResultSchema } from "@modelcontextprotocol/sdk/types.js";
+} from "@modelcontextprotocol/server";
import type { McpUiHostContext } from "../src/types.js";
import { useEffect, useState } from "react";
import { useApp } from "../src/react/index.js";
import { registerAppTool } from "../src/server/index.js";
-import {
- McpServer,
- ResourceTemplate,
-} from "@modelcontextprotocol/sdk/server/mcp.js";
+import { McpServer, ResourceTemplate } from "@modelcontextprotocol/server";
import { z } from "zod";
/**
@@ -117,14 +113,14 @@ function chunkedDataServer(server: McpServer) {
{
title: "Read Data Bytes",
description: "Load binary data in chunks",
- inputSchema: {
+ inputSchema: z.object({
id: z.string().describe("Resource identifier"),
offset: z.number().min(0).default(0).describe("Byte offset"),
byteCount: z
.number()
.default(MAX_CHUNK_BYTES)
.describe("Bytes to read"),
- },
+ }),
outputSchema: DataChunkSchema,
// Hidden from model - only callable by the App
_meta: { ui: { visibility: ["app"] } },
@@ -252,10 +248,7 @@ function binaryBlobResourceServer(
*/
async function binaryBlobResourceClient(app: App, videoId: string) {
//#region binaryBlobResourceClient
- const result = await app.request(
- { method: "resources/read", params: { uri: `video://${videoId}` } },
- ReadResourceResultSchema,
- );
+ const result = await app.readServerResource({ uri: `video://${videoId}` });
const content = result.contents[0];
if (!content || !("blob" in content)) {
diff --git a/docs/quickstart.md b/docs/quickstart.md
index 3e00796..eb6b096 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -21,7 +21,7 @@ This tutorial assumes you've built an MCP server before and are comfortable with
We'll use the [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) to build the server.
-You'll also need Node.js 18+.
+You'll also need Node.js 20+.
## 1. Set up the project
@@ -37,7 +37,7 @@ Install the dependencies you'll need:
```bash
npm init -y
-npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk express cors
+npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.4 @modelcontextprotocol/core@2.0.0-beta.4 @modelcontextprotocol/server@2.0.0-beta.4 @modelcontextprotocol/node@2.0.0-beta.4 @modelcontextprotocol/express@2.0.0-beta.4 zod@^4.2.0 express cors
npm install -D typescript vite vite-plugin-singlefile @types/express @types/cors @types/node tsx concurrently cross-env
```
@@ -178,9 +178,10 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { McpServer } from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
+import { z } from "zod";
const DIST_DIR = path.join(import.meta.dirname, "dist");
@@ -205,7 +206,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async () => {
@@ -240,10 +241,10 @@ export function createServer(): McpServer {
```ts source="../examples/quickstart/main.ts"
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -263,7 +264,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/docs/testing-mcp-apps.md b/docs/testing-mcp-apps.md
index df1396c..e5d82b5 100644
--- a/docs/testing-mcp-apps.md
+++ b/docs/testing-mcp-apps.md
@@ -28,6 +28,10 @@ The [`basic-host`](https://github.com/modelcontextprotocol/ext-apps/tree/main/ex
cd examples/basic-host
```
+ The root install runs the package build, including type-checking the
+ documentation snippets against the exact base MCP SDK beta.4 packages. Do
+ not bypass a failed build before testing the host.
+
2. Start basic-host, pointing it to your MCP server:
```bash
diff --git a/examples/basic-host/package.json b/examples/basic-host/package.json
index 1b45dcf..583d2ff 100644
--- a/examples/basic-host/package.json
+++ b/examples/basic-host/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"zod": "^4.1.13"
diff --git a/examples/basic-host/src/implementation.ts b/examples/basic-host/src/implementation.ts
index 31e3698..5f680ff 100644
--- a/examples/basic-host/src/implementation.ts
+++ b/examples/basic-host/src/implementation.ts
@@ -1,8 +1,12 @@
import { RESOURCE_MIME_TYPE, getToolUiResourceUri, type McpUiSandboxProxyReadyNotification, AppBridge, PostMessageTransport, type McpUiResourceCsp, type McpUiResourcePermissions, buildAllowAttribute, type McpUiUpdateModelContextRequest, type McpUiMessageRequest } from "@modelcontextprotocol/ext-apps/app-bridge";
-import { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
-import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
-import type { CallToolResult, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
+import {
+ Client,
+ SSEClientTransport,
+ StreamableHTTPClientTransport,
+ type CallToolResult,
+ type Resource,
+ type Tool,
+} from "@modelcontextprotocol/client";
import { getTheme, onThemeChange } from "./theme";
import { HOST_STYLE_VARIABLES } from "./host-styles";
diff --git a/examples/basic-host/src/index.tsx b/examples/basic-host/src/index.tsx
index 3d488a7..00c0d52 100644
--- a/examples/basic-host/src/index.tsx
+++ b/examples/basic-host/src/index.tsx
@@ -1,5 +1,5 @@
import { getToolUiResourceUri, McpUiToolMetaSchema } from "@modelcontextprotocol/ext-apps/app-bridge";
-import type { Tool } from "@modelcontextprotocol/sdk/types.js";
+import type { Tool } from "@modelcontextprotocol/client";
import { Component, type ErrorInfo, type ReactNode, StrictMode, Suspense, use, useEffect, useMemo, useRef, useState } from "react";
import { createRoot } from "react-dom/client";
import { callTool, connectToServer, hasAppHtml, initializeApp, loadSandboxProxy, log, newAppBridge, type ServerInfo, type ToolCallInfo, type ModelContext, type AppMessage } from "./implementation";
diff --git a/examples/basic-server-preact/main.ts b/examples/basic-server-preact/main.ts
index 7642632..ffdff52 100644
--- a/examples/basic-server-preact/main.ts
+++ b/examples/basic-server-preact/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-preact/package.json b/examples/basic-server-preact/package.json
index 1a63232..0187827 100644
--- a/examples/basic-server-preact/package.json
+++ b/examples/basic-server-preact/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"preact": "^10.0.0",
diff --git a/examples/basic-server-preact/server.ts b/examples/basic-server-preact/server.ts
index bf14ea5..dfec94a 100644
--- a/examples/basic-server-preact/server.ts
+++ b/examples/basic-server-preact/server.ts
@@ -1,8 +1,12 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
@@ -28,7 +32,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async (): Promise => {
diff --git a/examples/basic-server-preact/src/mcp-app.tsx b/examples/basic-server-preact/src/mcp-app.tsx
index a8bdc68..351a8ec 100644
--- a/examples/basic-server-preact/src/mcp-app.tsx
+++ b/examples/basic-server-preact/src/mcp-app.tsx
@@ -8,7 +8,7 @@ import {
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { useCallback, useEffect, useState } from "preact/hooks";
import { render } from "preact";
import styles from "./mcp-app.module.css";
diff --git a/examples/basic-server-react/main.ts b/examples/basic-server-react/main.ts
index ec187b6..21c5e18 100644
--- a/examples/basic-server-react/main.ts
+++ b/examples/basic-server-react/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-react/package.json b/examples/basic-server-react/package.json
index 821fc96..dae7665 100644
--- a/examples/basic-server-react/package.json
+++ b/examples/basic-server-react/package.json
@@ -34,10 +34,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
diff --git a/examples/basic-server-react/server.ts b/examples/basic-server-react/server.ts
index 23f6dda..d77c908 100644
--- a/examples/basic-server-react/server.ts
+++ b/examples/basic-server-react/server.ts
@@ -1,8 +1,12 @@
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
@@ -29,7 +33,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async (): Promise => {
diff --git a/examples/basic-server-react/src/mcp-app.tsx b/examples/basic-server-react/src/mcp-app.tsx
index 6bb5540..2b5fbef 100644
--- a/examples/basic-server-react/src/mcp-app.tsx
+++ b/examples/basic-server-react/src/mcp-app.tsx
@@ -3,7 +3,7 @@
*/
import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps";
import { useApp } from "@modelcontextprotocol/ext-apps/react";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { StrictMode, useCallback, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import styles from "./mcp-app.module.css";
diff --git a/examples/basic-server-solid/main.ts b/examples/basic-server-solid/main.ts
index c8d9de2..095ef8d 100644
--- a/examples/basic-server-solid/main.ts
+++ b/examples/basic-server-solid/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-solid/package.json b/examples/basic-server-solid/package.json
index 997bc60..5d91407 100644
--- a/examples/basic-server-solid/package.json
+++ b/examples/basic-server-solid/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"solid-js": "1.9.10",
diff --git a/examples/basic-server-solid/server.ts b/examples/basic-server-solid/server.ts
index 2ed2d93..addb522 100644
--- a/examples/basic-server-solid/server.ts
+++ b/examples/basic-server-solid/server.ts
@@ -1,8 +1,12 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
@@ -28,7 +32,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async (): Promise => {
diff --git a/examples/basic-server-solid/src/mcp-app.tsx b/examples/basic-server-solid/src/mcp-app.tsx
index 66d47f3..2d78b7b 100644
--- a/examples/basic-server-solid/src/mcp-app.tsx
+++ b/examples/basic-server-solid/src/mcp-app.tsx
@@ -8,7 +8,7 @@ import {
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { createEffect, createSignal, onMount, Show } from "solid-js";
import { render } from "solid-js/web";
import styles from "./mcp-app.module.css";
diff --git a/examples/basic-server-svelte/main.ts b/examples/basic-server-svelte/main.ts
index 6c50a25..734ec0c 100644
--- a/examples/basic-server-svelte/main.ts
+++ b/examples/basic-server-svelte/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-svelte/package.json b/examples/basic-server-svelte/package.json
index e83772f..18bf7ab 100644
--- a/examples/basic-server-svelte/package.json
+++ b/examples/basic-server-svelte/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"svelte": "^5.0.0",
diff --git a/examples/basic-server-svelte/server.ts b/examples/basic-server-svelte/server.ts
index da603ca..9414285 100644
--- a/examples/basic-server-svelte/server.ts
+++ b/examples/basic-server-svelte/server.ts
@@ -1,8 +1,12 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
@@ -28,7 +32,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async (): Promise => {
diff --git a/examples/basic-server-svelte/src/App.svelte b/examples/basic-server-svelte/src/App.svelte
index fde128d..cabcc31 100644
--- a/examples/basic-server-svelte/src/App.svelte
+++ b/examples/basic-server-svelte/src/App.svelte
@@ -7,7 +7,7 @@ import {
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
function extractTime(result: CallToolResult): string {
const { text } = result.content?.find((c) => c.type === "text")!;
diff --git a/examples/basic-server-vanillajs/main.ts b/examples/basic-server-vanillajs/main.ts
index 286fa34..4de7331 100644
--- a/examples/basic-server-vanillajs/main.ts
+++ b/examples/basic-server-vanillajs/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-vanillajs/package.json b/examples/basic-server-vanillajs/package.json
index 64e1758..6bb75af 100644
--- a/examples/basic-server-vanillajs/package.json
+++ b/examples/basic-server-vanillajs/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
diff --git a/examples/basic-server-vanillajs/server.ts b/examples/basic-server-vanillajs/server.ts
index 5b2daf7..693d861 100644
--- a/examples/basic-server-vanillajs/server.ts
+++ b/examples/basic-server-vanillajs/server.ts
@@ -1,6 +1,9 @@
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -29,7 +32,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
outputSchema: z.object({
time: z.string(),
}),
diff --git a/examples/basic-server-vanillajs/src/mcp-app.ts b/examples/basic-server-vanillajs/src/mcp-app.ts
index c3168c2..6b5084a 100644
--- a/examples/basic-server-vanillajs/src/mcp-app.ts
+++ b/examples/basic-server-vanillajs/src/mcp-app.ts
@@ -8,7 +8,7 @@ import {
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import "./global.css";
import "./mcp-app.css";
diff --git a/examples/basic-server-vue/main.ts b/examples/basic-server-vue/main.ts
index 669a071..d774269 100644
--- a/examples/basic-server-vue/main.ts
+++ b/examples/basic-server-vue/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/basic-server-vue/package.json b/examples/basic-server-vue/package.json
index e4cd0b4..3b34aa6 100644
--- a/examples/basic-server-vue/package.json
+++ b/examples/basic-server-vue/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"vue": "^3.5.0",
diff --git a/examples/basic-server-vue/server.ts b/examples/basic-server-vue/server.ts
index 5aa72de..9adb911 100644
--- a/examples/basic-server-vue/server.ts
+++ b/examples/basic-server-vue/server.ts
@@ -1,8 +1,12 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
@@ -28,7 +32,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async (): Promise => {
diff --git a/examples/basic-server-vue/src/App.vue b/examples/basic-server-vue/src/App.vue
index 196ad64..a45c262 100644
--- a/examples/basic-server-vue/src/App.vue
+++ b/examples/basic-server-vue/src/App.vue
@@ -7,7 +7,7 @@ import {
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
function extractTime(result: CallToolResult): string {
const { text } = result.content?.find((c) => c.type === "text")!;
diff --git a/examples/budget-allocator-server/main.ts b/examples/budget-allocator-server/main.ts
index cc488f0..02c03cb 100644
--- a/examples/budget-allocator-server/main.ts
+++ b/examples/budget-allocator-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/budget-allocator-server/package.json b/examples/budget-allocator-server/package.json
index 8af1a6c..5d4fe8e 100644
--- a/examples/budget-allocator-server/package.json
+++ b/examples/budget-allocator-server/package.json
@@ -29,7 +29,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/budget-allocator-server/server.ts b/examples/budget-allocator-server/server.ts
index 04fba11..01f5dbf 100755
--- a/examples/budget-allocator-server/server.ts
+++ b/examples/budget-allocator-server/server.ts
@@ -4,11 +4,11 @@
* Provides budget configuration, 24 months of historical allocation data,
* and industry benchmarks by company stage.
*/
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -270,7 +270,7 @@ export function createServer(): McpServer {
title: "Get Budget Data",
description:
"Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage. The widget is interactive and exposes tools for reading/modifying allocations, adjusting budgets, and comparing against industry benchmarks.",
- inputSchema: {},
+ inputSchema: z.object({}),
outputSchema: BudgetDataResponseSchema,
_meta: { ui: { resourceUri } },
},
diff --git a/examples/cohort-heatmap-server/main.ts b/examples/cohort-heatmap-server/main.ts
index d59903b..8b33603 100644
--- a/examples/cohort-heatmap-server/main.ts
+++ b/examples/cohort-heatmap-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/cohort-heatmap-server/package.json b/examples/cohort-heatmap-server/package.json
index 99e9d9f..c54040a 100644
--- a/examples/cohort-heatmap-server/package.json
+++ b/examples/cohort-heatmap-server/package.json
@@ -29,7 +29,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
diff --git a/examples/cohort-heatmap-server/server.ts b/examples/cohort-heatmap-server/server.ts
index 6d07144..129e2dc 100644
--- a/examples/cohort-heatmap-server/server.ts
+++ b/examples/cohort-heatmap-server/server.ts
@@ -1,5 +1,7 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -178,8 +180,8 @@ export function createServer(): McpServer {
title: "Get Cohort Retention Data",
description:
"Returns cohort retention heatmap data showing customer retention over time by signup month",
- inputSchema: GetCohortDataInputSchema.shape,
- outputSchema: CohortDataSchema.shape,
+ inputSchema: GetCohortDataInputSchema,
+ outputSchema: CohortDataSchema,
_meta: { ui: { resourceUri } },
},
async ({ metric, periodType, cohortCount, maxPeriods }) => {
diff --git a/examples/customer-segmentation-server/main.ts b/examples/customer-segmentation-server/main.ts
index 130076c..c788757 100644
--- a/examples/customer-segmentation-server/main.ts
+++ b/examples/customer-segmentation-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/customer-segmentation-server/package.json b/examples/customer-segmentation-server/package.json
index 59e3eb1..ef14b32 100644
--- a/examples/customer-segmentation-server/package.json
+++ b/examples/customer-segmentation-server/package.json
@@ -29,7 +29,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/customer-segmentation-server/server.ts b/examples/customer-segmentation-server/server.ts
index 244415d..7cc1c1f 100644
--- a/examples/customer-segmentation-server/server.ts
+++ b/examples/customer-segmentation-server/server.ts
@@ -1,8 +1,8 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -100,8 +100,8 @@ export function createServer(): McpServer {
title: "Get Customer Data",
description:
"Returns customer data with segment information for visualization. Optionally filter by segment.",
- inputSchema: GetCustomerDataInputSchema.shape,
- outputSchema: GetCustomerDataOutputSchema.shape,
+ inputSchema: GetCustomerDataInputSchema,
+ outputSchema: GetCustomerDataOutputSchema,
_meta: { ui: { resourceUri } },
},
async ({ segment }): Promise => {
diff --git a/examples/debug-server/main.ts b/examples/debug-server/main.ts
index 3c89a97..9fb0825 100644
--- a/examples/debug-server/main.ts
+++ b/examples/debug-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/debug-server/package.json b/examples/debug-server/package.json
index 02e9fbf..0e3f508 100644
--- a/examples/debug-server/package.json
+++ b/examples/debug-server/package.json
@@ -37,7 +37,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"zod": "^4.1.13"
},
"devDependencies": {
diff --git a/examples/debug-server/server.ts b/examples/debug-server/server.ts
index fd3452a..068f94d 100644
--- a/examples/debug-server/server.ts
+++ b/examples/debug-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import { appendFileSync } from "node:fs";
import path from "node:path";
diff --git a/examples/integration-server/main.ts b/examples/integration-server/main.ts
index c45787e..9a42842 100644
--- a/examples/integration-server/main.ts
+++ b/examples/integration-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/integration-server/package.json b/examples/integration-server/package.json
index 3f9d8bb..56fc8ed 100644
--- a/examples/integration-server/package.json
+++ b/examples/integration-server/package.json
@@ -15,10 +15,11 @@
"serve": "bun --watch main.ts"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
diff --git a/examples/integration-server/server.ts b/examples/integration-server/server.ts
index e44689d..346f4f7 100644
--- a/examples/integration-server/server.ts
+++ b/examples/integration-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -33,7 +33,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time.",
- inputSchema: {},
+ inputSchema: z.object({}),
outputSchema: z.object({
time: z.string(),
}),
@@ -72,7 +72,7 @@ export function createServer(): McpServer {
);
// Sample downloadable resource — used to demo ResourceLink in ui/download-file
- server.resource(
+ server.registerResource(
SAMPLE_DOWNLOAD_URI,
SAMPLE_DOWNLOAD_URI,
{
diff --git a/examples/integration-server/src/mcp-app.tsx b/examples/integration-server/src/mcp-app.tsx
index 7f0b18c..281a356 100644
--- a/examples/integration-server/src/mcp-app.tsx
+++ b/examples/integration-server/src/mcp-app.tsx
@@ -3,7 +3,7 @@
*/
import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps";
import { useApp } from "@modelcontextprotocol/ext-apps/react";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { StrictMode, useCallback, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import styles from "./mcp-app.module.css";
diff --git a/examples/lazy-auth-server/package.json b/examples/lazy-auth-server/package.json
index 086f20a..6aef3e1 100644
--- a/examples/lazy-auth-server/package.json
+++ b/examples/lazy-auth-server/package.json
@@ -24,10 +24,11 @@
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
- "jose": "^6.0.0"
+ "jose": "^6.0.0",
+ "zod": "^4.1.13"
},
"devDependencies": {
"@types/cors": "^2.8.19",
diff --git a/examples/lazy-auth-server/server.ts b/examples/lazy-auth-server/server.ts
index fe7b1ac..01535eb 100644
--- a/examples/lazy-auth-server/server.ts
+++ b/examples/lazy-auth-server/server.ts
@@ -21,13 +21,13 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
-import { UrlElicitationRequiredError } from "@modelcontextprotocol/sdk/types.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import {
+ McpServer,
+ UrlElicitationRequiredError,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import cors from "cors";
import express, { type Express, type Request, type Response } from "express";
import { SignJWT, jwtVerify } from "jose";
@@ -35,6 +35,7 @@ import crypto from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js). Derived
// from import.meta.url rather than import.meta.filename/dirname, which are
@@ -605,7 +606,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Show Auth Button",
description:
"Public tool: shows a button that triggers the protected get_secret tool.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri: buttonUri } },
},
async (): Promise => ({
@@ -638,7 +639,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Get Secret",
description:
"Protected tool: returns secret data. Requires authentication.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri: secretUri } },
},
async (): Promise => {
@@ -682,7 +683,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Revoke Auth Token",
description:
"Protected tool: revokes the caller's entire auth session (access + refresh token).",
- inputSchema: {},
+ inputSchema: z.object({}),
},
async (): Promise => {
if (!authInfo) {
@@ -720,7 +721,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Elicit URL (session-callback)",
description:
"URL elicitation via elicitInput. Blocks until the client accepts; sends ElicitCompleteNotification before returning.",
- inputSchema: {},
+ inputSchema: z.object({}),
},
async (_args, extra): Promise => {
const eid = crypto.randomUUID();
@@ -735,7 +736,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
message: "Please open this URL to continue.",
elicitationId: eid,
},
- { relatedRequestId: extra.requestId, timeout: 300_000 },
+ { relatedRequestId: extra.mcpReq.id, timeout: 300_000 },
);
// Send completion notification before returning — lands on the same SSE
// stream as this tool response. For Streamable HTTP this is the ONLY
@@ -767,7 +768,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Elicit by -32042 Error",
description:
"Throws UrlElicitationRequiredError (-32042). Client must open the URL, then retry. On retry, if the last-issued elicitationId was completed, sends ElicitCompleteNotification and succeeds.",
- inputSchema: {},
+ inputSchema: z.object({}),
},
async (): Promise => {
// Retry path: check if the user completed the elicitation we last issued.
@@ -1031,7 +1032,7 @@ export function createApp(): Express {
}
const server = createServer(authInfo, req);
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on("close", () => {
diff --git a/examples/map-server/main.ts b/examples/map-server/main.ts
index f91f57b..8038394 100644
--- a/examples/map-server/main.ts
+++ b/examples/map-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/map-server/package.json b/examples/map-server/package.json
index b0c629a..a3639ce 100644
--- a/examples/map-server/package.json
+++ b/examples/map-server/package.json
@@ -26,10 +26,11 @@
"serve": "bun --watch main.ts"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
diff --git a/examples/map-server/server.ts b/examples/map-server/server.ts
index 10125a6..5767d46 100644
--- a/examples/map-server/server.ts
+++ b/examples/map-server/server.ts
@@ -5,11 +5,11 @@
* - geocode: Search for places using OpenStreetMap Nominatim
* - show-map: Display an interactive 3D globe at a given location
*/
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -148,7 +148,7 @@ export function createServer(): McpServer {
title: "Show Map",
description:
"Display an interactive world map zoomed to a specific bounding box. Use the GeoCode tool to find the bounding box of a location. The widget is interactive and exposes tools for navigation (fly to locations) and querying the current view.",
- inputSchema: {
+ inputSchema: z.object({
west: z
.number()
.optional()
@@ -173,7 +173,7 @@ export function createServer(): McpServer {
.string()
.optional()
.describe("Optional label to display on the map"),
- },
+ }),
_meta: { ui: { resourceUri } },
},
async ({ west, south, east, north, label }): Promise => ({
@@ -196,13 +196,13 @@ export function createServer(): McpServer {
title: "Geocode",
description:
"Search for places using OpenStreetMap. Returns coordinates and bounding boxes for up to 5 matches.",
- inputSchema: {
+ inputSchema: z.object({
query: z
.string()
.describe(
"Place name or address to search for (e.g., 'Paris', 'Golden Gate Bridge', '1600 Pennsylvania Ave')",
),
- },
+ }),
},
async ({ query }): Promise => {
try {
diff --git a/examples/map-server/src/mcp-app.ts b/examples/map-server/src/mcp-app.ts
index 39d7c2a..d3090c7 100644
--- a/examples/map-server/src/mcp-app.ts
+++ b/examples/map-server/src/mcp-app.ts
@@ -6,7 +6,7 @@
* a navigate-to tool for the host to control navigation.
*/
import { App } from "@modelcontextprotocol/ext-apps";
-import type { ContentBlock } from "@modelcontextprotocol/sdk/spec.types.js";
+import type { ContentBlock } from "@modelcontextprotocol/client";
import { z } from "zod";
// TypeScript declaration for Cesium loaded from CDN
diff --git a/examples/pdf-server/main.ts b/examples/pdf-server/main.ts
index 1ff848a..bb7b57f 100644
--- a/examples/pdf-server/main.ts
+++ b/examples/pdf-server/main.ts
@@ -6,10 +6,10 @@
import fs from "node:fs";
import path from "node:path";
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import {
@@ -39,7 +39,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/pdf-server/package.json b/examples/pdf-server/package.json
index aeb52c7..a7eb4bb 100644
--- a/examples/pdf-server/package.json
+++ b/examples/pdf-server/package.json
@@ -26,10 +26,11 @@
},
"dependencies": {
"@cantoo/pdf-lib": "^2.6.5",
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"pdfjs-dist": "^5.0.0",
diff --git a/examples/pdf-server/server.test.ts b/examples/pdf-server/server.test.ts
index 33a03f1..0b2a5eb 100644
--- a/examples/pdf-server/server.test.ts
+++ b/examples/pdf-server/server.test.ts
@@ -2,8 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, spyOn } from "bun:test";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
-import { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
+import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
import { PDFDocument } from "@cantoo/pdf-lib";
import { makeRandomJpeg } from "../../tests/helpers/range-counting-server";
diff --git a/examples/pdf-server/server.ts b/examples/pdf-server/server.ts
index 93dedfd..e67cd47 100644
--- a/examples/pdf-server/server.ts
+++ b/examples/pdf-server/server.ts
@@ -13,18 +13,19 @@
import { randomUUID } from "crypto";
import fs from "node:fs";
import path from "node:path";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
import {
registerAppResource,
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
import {
- RootsListChangedNotificationSchema,
+ McpServer,
type CallToolResult,
+ type ElicitResult,
+ type PrimitiveSchemaDefinition,
type ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+ type Server,
+} from "@modelcontextprotocol/server";
// Stub DOMMatrix/ImageData/Path2D before pdfjs-dist loads — its legacy
// build instantiates DOMMatrix at module scope and the @napi-rs/canvas
// polyfill is unreliable under npx. See ./pdfjs-polyfill.ts for details.
@@ -62,10 +63,6 @@ class FetchStandardFontDataFactory {
return new Uint8Array(await res.arrayBuffer());
}
}
-import type {
- PrimitiveSchemaDefinition,
- ElicitResult,
-} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// =============================================================================
@@ -1282,7 +1279,7 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
refreshRoots(server.server);
};
server.server.setNotificationHandler(
- RootsListChangedNotificationSchema,
+ "notifications/roots/list_changed",
async () => {
await refreshRoots(server.server);
},
@@ -1292,10 +1289,12 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
const { readPdfRange } = sharedPdfCache;
// Tool: list_pdfs - List available PDFs
- server.tool(
+ server.registerTool(
"list_pdfs",
- "List available PDFs that can be displayed",
- {},
+ {
+ description: "List available PDFs that can be displayed",
+ inputSchema: z.object({}),
+ },
async (): Promise => {
const seen = new Set();
const localFiles: string[] = [];
@@ -1377,7 +1376,7 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
title: "Read PDF Bytes",
description:
"Read a range of bytes from a PDF (max 512KB per request). The model should NOT call this tool directly.",
- inputSchema: {
+ inputSchema: z.object({
url: z.string().describe("PDF URL or local file path"),
offset: z.number().min(0).default(0).describe("Byte offset"),
byteCount: z
@@ -1386,7 +1385,7 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
.max(MAX_CHUNK_BYTES)
.default(MAX_CHUNK_BYTES)
.describe("Bytes to read"),
- },
+ }),
outputSchema: z.object({
url: z.string(),
bytes: z.string().describe("Base64 encoded bytes"),
@@ -1473,7 +1472,7 @@ Returns a viewUUID in structuredContent. Pass it to \`interact\`:
Accepts local files (use list_pdfs), client MCP root directories, or any HTTPS URL.
Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before display.`,
- inputSchema: {
+ inputSchema: z.object({
url: z
.string()
.default(DEFAULT_PDF)
@@ -1489,7 +1488,7 @@ Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before
"If true and the PDF has form fields, prompt the user to fill them before displaying",
),
}),
- },
+ }),
outputSchema: z.object({
viewUUID: z
.string()
@@ -2426,7 +2425,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
**FORMS** — fill_form: fill fields with \`fields\` array of {name, value}.
**SAVE** — save_as: write the annotated PDF (annotations + form values) to a file. Pass \`path\` (absolute path or file://) for a new location, or omit \`path\` to overwrite the original. Set \`overwrite: true\` to replace an existing file (always required when omitting \`path\`).`,
- inputSchema: {
+ inputSchema: z.object({
viewUUID: z
.string()
.describe(
@@ -2523,7 +2522,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
.describe(
"Array of commands to execute sequentially. More efficient than separate calls. Tip: end with get_pages+getScreenshots to verify changes.",
),
- },
+ }),
},
async (
{
@@ -2600,7 +2599,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
const result = await processInteractCommand(
uuid,
commandList[i],
- extra.signal,
+ extra.mcpReq.signal,
);
if (result.isError) {
const errText = result.content
@@ -2657,7 +2656,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
title: "Submit Page Data",
description:
"Submit rendered page data for a get_pages request (used by viewer). The model should NOT call this tool directly.",
- inputSchema: {
+ inputSchema: z.object({
requestId: z
.string()
.describe("The request ID from the get_pages command"),
@@ -2670,7 +2669,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
}),
)
.describe("Page data entries"),
- },
+ }),
_meta: { ui: { visibility: ["app"] } },
},
async ({ requestId, pages }): Promise => {
@@ -2700,7 +2699,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
title: "Submit Save Data",
description:
"Submit annotated PDF bytes for a save_as request (used by viewer). The model should NOT call this tool directly.",
- inputSchema: {
+ inputSchema: z.object({
requestId: z
.string()
.describe("The request ID from the save_as command"),
@@ -2709,7 +2708,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
.string()
.optional()
.describe("Error message if the viewer failed to build bytes"),
- },
+ }),
_meta: { ui: { visibility: ["app"] } },
},
async ({ requestId, data, error }): Promise => {
@@ -2739,7 +2738,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
title: "Submit Viewer State",
description:
"Submit a viewer-state snapshot for a get_viewer_state request (used by viewer). The model should NOT call this tool directly.",
- inputSchema: {
+ inputSchema: z.object({
requestId: z
.string()
.describe("The request ID from the get_viewer_state command"),
@@ -2751,7 +2750,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
.string()
.optional()
.describe("Error message if the viewer failed to read state"),
- },
+ }),
_meta: { ui: { visibility: ["app"] } },
},
async ({ requestId, state, error }): Promise => {
@@ -2781,9 +2780,9 @@ Example — add a signature image and a stamp, then screenshot to verify:
title: "Poll PDF Commands",
description:
"Poll for pending commands for a PDF viewer. The model should NOT call this tool directly.",
- inputSchema: {
+ inputSchema: z.object({
viewUUID: z.string().describe("The viewUUID of the PDF viewer"),
- },
+ }),
_meta: { ui: { visibility: ["app"] } },
},
async ({ viewUUID: uuid }): Promise => {
@@ -2828,10 +2827,10 @@ Example — add a signature image and a stamp, then screenshot to verify:
title: "Save PDF",
description:
"Save annotated PDF bytes back to a local file. The model should NOT call this tool directly — use interact with action: save_as instead.",
- inputSchema: {
+ inputSchema: z.object({
url: z.string().describe("Original PDF URL or local file path"),
data: z.string().describe("Base64-encoded PDF bytes"),
- },
+ }),
outputSchema: z.object({
filePath: z.string(),
mtimeMs: z.number(),
diff --git a/examples/pdf-server/src/mcp-app.ts b/examples/pdf-server/src/mcp-app.ts
index a953e24..45e0c74 100644
--- a/examples/pdf-server/src/mcp-app.ts
+++ b/examples/pdf-server/src/mcp-app.ts
@@ -12,8 +12,10 @@ import {
applyDocumentTheme,
applyHostStyleVariables,
} from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
-import type { ContentBlock } from "@modelcontextprotocol/sdk/spec.types.js";
+import type {
+ CallToolResult,
+ ContentBlock,
+} from "@modelcontextprotocol/client";
import { z } from "zod";
import * as pdfjsLib from "pdfjs-dist";
import { AnnotationLayer, AnnotationMode, TextLayer } from "pdfjs-dist";
diff --git a/examples/qr-server/package.json b/examples/qr-server/package.json
index a5cbf5b..cb4e010 100644
--- a/examples/qr-server/package.json
+++ b/examples/qr-server/package.json
@@ -8,7 +8,6 @@
"build": "echo 'No build step needed for Python server'"
},
"dependencies": {
- "@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0"
+ "@modelcontextprotocol/ext-apps": "^1.7.0"
}
}
diff --git a/examples/quickstart/main.ts b/examples/quickstart/main.ts
index 06895a4..7f370a8 100644
--- a/examples/quickstart/main.ts
+++ b/examples/quickstart/main.ts
@@ -1,7 +1,7 @@
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -21,7 +21,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/quickstart/package.json b/examples/quickstart/package.json
index 1003637..f741c6e 100644
--- a/examples/quickstart/package.json
+++ b/examples/quickstart/package.json
@@ -18,9 +18,10 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
- "express": "^5.1.0"
+ "express": "^5.1.0",
+ "zod": "^4.1.13"
},
"devDependencies": {
"@types/cors": "^2.8.19",
diff --git a/examples/quickstart/server.ts b/examples/quickstart/server.ts
index eb3c3b1..611d0f0 100644
--- a/examples/quickstart/server.ts
+++ b/examples/quickstart/server.ts
@@ -3,9 +3,10 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { McpServer } from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
+import { z } from "zod";
const DIST_DIR = path.join(import.meta.dirname, "dist");
@@ -30,7 +31,7 @@ export function createServer(): McpServer {
{
title: "Get Time",
description: "Returns the current server time.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } }, // Links this tool to its UI resource
},
async () => {
diff --git a/examples/say-server/package.json b/examples/say-server/package.json
index a0076e6..2ebc099 100644
--- a/examples/say-server/package.json
+++ b/examples/say-server/package.json
@@ -15,7 +15,6 @@
"build": "echo 'No build step needed for Python server'"
},
"dependencies": {
- "@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0"
+ "@modelcontextprotocol/ext-apps": "^1.7.0"
}
}
diff --git a/examples/scenario-modeler-server/main.ts b/examples/scenario-modeler-server/main.ts
index dbd3ab6..cc20e63 100644
--- a/examples/scenario-modeler-server/main.ts
+++ b/examples/scenario-modeler-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/scenario-modeler-server/package.json b/examples/scenario-modeler-server/package.json
index a7e8a9a..63a5d48 100644
--- a/examples/scenario-modeler-server/package.json
+++ b/examples/scenario-modeler-server/package.json
@@ -29,7 +29,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/scenario-modeler-server/server.ts b/examples/scenario-modeler-server/server.ts
index b59851c..c5fa05d 100644
--- a/examples/scenario-modeler-server/server.ts
+++ b/examples/scenario-modeler-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -305,8 +305,8 @@ export function createServer(): McpServer {
title: "Get Scenario Data",
description:
"Returns SaaS scenario templates and optionally computes custom projections for given inputs",
- inputSchema: GetScenarioDataInputSchema.shape,
- outputSchema: GetScenarioDataOutputSchema.shape,
+ inputSchema: GetScenarioDataInputSchema,
+ outputSchema: GetScenarioDataOutputSchema,
_meta: { ui: { resourceUri } },
},
async (args: {
diff --git a/examples/shadertoy-server/main.ts b/examples/shadertoy-server/main.ts
index ac8f6ad..7e388f0 100644
--- a/examples/shadertoy-server/main.ts
+++ b/examples/shadertoy-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/shadertoy-server/package.json b/examples/shadertoy-server/package.json
index 0c27501..318f017 100644
--- a/examples/shadertoy-server/package.json
+++ b/examples/shadertoy-server/package.json
@@ -27,7 +27,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
diff --git a/examples/shadertoy-server/server.ts b/examples/shadertoy-server/server.ts
index 5238c40..50c27bc 100644
--- a/examples/shadertoy-server/server.ts
+++ b/examples/shadertoy-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
diff --git a/examples/sheet-music-server/main.ts b/examples/sheet-music-server/main.ts
index 8b143a7..d7bf3a0 100644
--- a/examples/sheet-music-server/main.ts
+++ b/examples/sheet-music-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/sheet-music-server/package.json b/examples/sheet-music-server/package.json
index 6cf175a..10d7c71 100644
--- a/examples/sheet-music-server/package.json
+++ b/examples/sheet-music-server/package.json
@@ -27,7 +27,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"abcjs": "^6.4.4",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/sheet-music-server/server.ts b/examples/sheet-music-server/server.ts
index cfd319b..be7214a 100644
--- a/examples/sheet-music-server/server.ts
+++ b/examples/sheet-music-server/server.ts
@@ -1,8 +1,8 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
diff --git a/examples/system-monitor-server/main.ts b/examples/system-monitor-server/main.ts
index 365a560..c55c799 100644
--- a/examples/system-monitor-server/main.ts
+++ b/examples/system-monitor-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/system-monitor-server/package.json b/examples/system-monitor-server/package.json
index 760d07f..5bc4a95 100644
--- a/examples/system-monitor-server/package.json
+++ b/examples/system-monitor-server/package.json
@@ -29,7 +29,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/system-monitor-server/server.ts b/examples/system-monitor-server/server.ts
index 8fac5f2..a17bcf6 100644
--- a/examples/system-monitor-server/server.ts
+++ b/examples/system-monitor-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -135,8 +135,8 @@ export function createServer(): McpServer {
title: "Get System Info",
description:
"Returns system information, including hostname, platform, CPU info, and memory.",
- inputSchema: {},
- outputSchema: SystemInfoSchema.shape,
+ inputSchema: z.object({}),
+ outputSchema: SystemInfoSchema,
_meta: { ui: { resourceUri } },
},
(): CallToolResult => {
@@ -156,8 +156,8 @@ export function createServer(): McpServer {
title: "Poll System Stats",
description:
"Returns dynamic system metrics for polling: per-core CPU timing, memory usage, and uptime. App-only.",
- inputSchema: {},
- outputSchema: PollStatsSchema.shape,
+ inputSchema: z.object({}),
+ outputSchema: PollStatsSchema,
_meta: { ui: { visibility: ["app"] } },
},
async (): Promise => {
diff --git a/examples/threejs-server/main.ts b/examples/threejs-server/main.ts
index 13a2084..ef16e26 100644
--- a/examples/threejs-server/main.ts
+++ b/examples/threejs-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/threejs-server/package.json b/examples/threejs-server/package.json
index 9dda288..fb97d33 100644
--- a/examples/threejs-server/package.json
+++ b/examples/threejs-server/package.json
@@ -26,10 +26,11 @@
"serve": "bun --watch main.ts"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
diff --git a/examples/threejs-server/server.ts b/examples/threejs-server/server.ts
index ae320df..0a13c19 100644
--- a/examples/threejs-server/server.ts
+++ b/examples/threejs-server/server.ts
@@ -8,8 +8,10 @@ import {
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -161,7 +163,7 @@ export function createServer(): McpServer {
title: "Show Three.js Scene",
description:
"Render an interactive 3D scene with custom Three.js code. Supports transparent backgrounds (alpha: true) for seamless host UI integration. Available globals: THREE, OrbitControls, EffectComposer, RenderPass, UnrealBloomPass, canvas, width, height.",
- inputSchema: {
+ inputSchema: z.object({
code: z
.string()
.default(DEFAULT_THREEJS_CODE)
@@ -172,7 +174,7 @@ export function createServer(): McpServer {
.positive()
.default(400)
.describe("Height in pixels"),
- },
+ }),
outputSchema: z.object({
success: z.boolean(),
}),
@@ -192,7 +194,7 @@ export function createServer(): McpServer {
{
title: "Learn Three.js",
description: "Get documentation and examples for using the Three.js View",
- inputSchema: {},
+ inputSchema: z.object({}),
},
async () => {
return {
diff --git a/examples/threejs-server/src/mcp-app-wrapper.tsx b/examples/threejs-server/src/mcp-app-wrapper.tsx
index 34194b1..44fee0c 100644
--- a/examples/threejs-server/src/mcp-app-wrapper.tsx
+++ b/examples/threejs-server/src/mcp-app-wrapper.tsx
@@ -6,7 +6,7 @@
*/
import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps";
import { useApp } from "@modelcontextprotocol/ext-apps/react";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { StrictMode, useState, useCallback, useEffect, useRef } from "react";
import { createRoot } from "react-dom/client";
import { z } from "zod";
diff --git a/examples/transcript-server/main.ts b/examples/transcript-server/main.ts
index 68db8dc..e86ad7c 100644
--- a/examples/transcript-server/main.ts
+++ b/examples/transcript-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -25,7 +25,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/transcript-server/package.json b/examples/transcript-server/package.json
index ce5b737..eea4a80 100644
--- a/examples/transcript-server/package.json
+++ b/examples/transcript-server/package.json
@@ -27,7 +27,7 @@
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
diff --git a/examples/transcript-server/server.ts b/examples/transcript-server/server.ts
index 56bf88d..863eb29 100644
--- a/examples/transcript-server/server.ts
+++ b/examples/transcript-server/server.ts
@@ -1,8 +1,8 @@
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import {
@@ -10,6 +10,7 @@ import {
registerAppResource,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
+import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
@@ -33,7 +34,7 @@ export function createServer(): McpServer {
title: "Transcribe Speech",
description:
"Opens a live speech transcription interface using the Web Speech API.",
- inputSchema: {},
+ inputSchema: z.object({}),
_meta: { ui: { resourceUri } },
},
async (): Promise => {
diff --git a/examples/video-resource-server/main.ts b/examples/video-resource-server/main.ts
index 082fa5a..1983373 100644
--- a/examples/video-resource-server/main.ts
+++ b/examples/video-resource-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/video-resource-server/package.json b/examples/video-resource-server/package.json
index 605b8de..ea816b9 100644
--- a/examples/video-resource-server/package.json
+++ b/examples/video-resource-server/package.json
@@ -24,10 +24,11 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
diff --git a/examples/video-resource-server/server.ts b/examples/video-resource-server/server.ts
index 2cb317e..8ae6240 100644
--- a/examples/video-resource-server/server.ts
+++ b/examples/video-resource-server/server.ts
@@ -12,11 +12,9 @@ import {
import {
McpServer,
ResourceTemplate,
-} from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import fs from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
@@ -135,14 +133,14 @@ Available videos:
${Object.entries(VIDEO_LIBRARY)
.map(([id, v]) => `- ${id}: ${v.description}`)
.join("\n")}`,
- inputSchema: {
+ inputSchema: z.object({
videoId: z
.enum(Object.keys(VIDEO_LIBRARY) as [string, ...string[]])
.default("bunny-1mb")
.describe(
`Video ID to play. Available: ${Object.keys(VIDEO_LIBRARY).join(", ")}`,
),
- },
+ }),
outputSchema: z.object({
videoUri: z.string(),
description: z.string(),
diff --git a/examples/video-resource-server/src/mcp-app.ts b/examples/video-resource-server/src/mcp-app.ts
index 88ed913..2a3f8f9 100644
--- a/examples/video-resource-server/src/mcp-app.ts
+++ b/examples/video-resource-server/src/mcp-app.ts
@@ -5,7 +5,7 @@
* The video is served as a base64 blob and converted to a data URI for playback.
*/
import { App, type McpUiHostContext } from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import "./global.css";
import "./mcp-app.css";
diff --git a/examples/wiki-explorer-server/main.ts b/examples/wiki-explorer-server/main.ts
index cc7b3a2..bfeeffb 100644
--- a/examples/wiki-explorer-server/main.ts
+++ b/examples/wiki-explorer-server/main.ts
@@ -4,10 +4,10 @@
* Or: node dist/index.js [--stdio]
*/
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
-import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
+import { createMcpExpressApp } from "@modelcontextprotocol/express";
+import type { McpServer } from "@modelcontextprotocol/server";
+import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
@@ -27,7 +27,7 @@ export async function startStreamableHTTPServer(
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
- const transport = new StreamableHTTPServerTransport({
+ const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
diff --git a/examples/wiki-explorer-server/package.json b/examples/wiki-explorer-server/package.json
index 62f1de8..bd31d6f 100644
--- a/examples/wiki-explorer-server/package.json
+++ b/examples/wiki-explorer-server/package.json
@@ -26,10 +26,11 @@
"serve": "bun --watch main.ts"
},
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cheerio": "^1.0.0",
"cors": "^2.8.5",
"express": "^5.1.0",
diff --git a/examples/wiki-explorer-server/server.ts b/examples/wiki-explorer-server/server.ts
index 59d5e18..8bc4eb7 100644
--- a/examples/wiki-explorer-server/server.ts
+++ b/examples/wiki-explorer-server/server.ts
@@ -3,11 +3,11 @@ import {
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import type {
- CallToolResult,
- ReadResourceResult,
-} from "@modelcontextprotocol/sdk/types.js";
+import {
+ McpServer,
+ type CallToolResult,
+ type ReadResourceResult,
+} from "@modelcontextprotocol/server";
import * as cheerio from "cheerio";
import fs from "node:fs/promises";
import path from "node:path";
diff --git a/examples/wiki-explorer-server/src/mcp-app.ts b/examples/wiki-explorer-server/src/mcp-app.ts
index 291292d..9833d9c 100644
--- a/examples/wiki-explorer-server/src/mcp-app.ts
+++ b/examples/wiki-explorer-server/src/mcp-app.ts
@@ -2,7 +2,7 @@
* Wiki Explorer - Force-directed graph visualization of Wikipedia link networks
*/
import { App, type McpUiHostContext } from "@modelcontextprotocol/ext-apps";
-import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
+import type { CallToolResult } from "@modelcontextprotocol/client";
import { z } from "zod";
import {
forceCenter,
diff --git a/package-lock.json b/package-lock.json
index 5514bf1..c1ae34d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,6 @@
"@boneskull/typedoc-plugin-mermaid": "^0.2.0",
"@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/core": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/server": "2.0.0-beta.4",
"@playwright/test": "1.57.0",
"@types/bun": "^1.3.2",
@@ -55,7 +54,6 @@
"peerDependencies": {
"@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/core": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/server": "2.0.0-beta.4",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
@@ -74,8 +72,8 @@
"name": "@modelcontextprotocol/ext-apps-basic-host",
"version": "1.7.4",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"zod": "^4.1.13"
@@ -100,10 +98,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"preact": "^10.0.0",
@@ -129,10 +128,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
@@ -161,10 +161,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"solid-js": "1.9.10",
@@ -190,10 +191,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"svelte": "^5.0.0",
@@ -219,10 +221,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
@@ -246,10 +249,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"vue": "^3.5.0",
@@ -278,7 +282,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -306,7 +310,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
@@ -338,7 +342,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -366,7 +370,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"zod": "^4.1.13"
},
"bin": {
@@ -388,10 +392,11 @@
"examples/integration-server": {
"version": "1.7.4",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
@@ -421,10 +426,11 @@
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
- "jose": "^6.0.0"
+ "jose": "^6.0.0",
+ "zod": "^4.1.13"
},
"bin": {
"mcp-server-lazy-auth": "dist/index.js"
@@ -445,10 +451,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
@@ -473,10 +480,11 @@
"license": "MIT",
"dependencies": {
"@cantoo/pdf-lib": "^2.6.5",
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"pdfjs-dist": "^5.0.0",
@@ -500,8 +508,7 @@
"name": "@modelcontextprotocol/server-qr",
"version": "1.7.4",
"dependencies": {
- "@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0"
+ "@modelcontextprotocol/ext-apps": "^1.7.0"
}
},
"examples/quickstart": {
@@ -512,9 +519,10 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
- "express": "^5.1.0"
+ "express": "^5.1.0",
+ "zod": "^4.1.13"
},
"devDependencies": {
"@types/cors": "^2.8.19",
@@ -533,8 +541,7 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
- "@modelcontextprotocol/ext-apps": "^1.7.0",
- "@modelcontextprotocol/sdk": "^1.29.0"
+ "@modelcontextprotocol/ext-apps": "^1.7.0"
}
},
"examples/scenario-modeler-server": {
@@ -545,7 +552,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -578,7 +585,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
@@ -605,7 +612,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"abcjs": "^6.4.4",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -633,7 +640,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"chart.js": "^4.4.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -659,10 +666,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
@@ -696,7 +704,7 @@
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
@@ -721,10 +729,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"zod": "^4.1.13"
@@ -748,10 +757,11 @@
"version": "1.7.4",
"license": "MIT",
"dependencies": {
+ "@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/express": "2.0.0-beta.4",
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
+ "@modelcontextprotocol/server": "2.0.0-beta.4",
"cheerio": "^1.0.0",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -2230,7 +2240,6 @@
"version": "2.0.0-beta.4",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0-beta.4.tgz",
"integrity": "sha512-VNHA/UXDk7mCpVl+jOg5B4WMRRD2OEl+it360Lhi6HiCbrIB2f6pZ0cqSDKXQVUtZvqnhdQHzZAM9h8EKWhq/A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/core": "2.0.0-beta.4",
@@ -2336,6 +2345,7 @@
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz",
"integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@hono/node-server": "^1.19.9",
"ajv": "^8.17.1",
@@ -3995,6 +4005,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -4011,6 +4022,7 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"ajv": "^8.0.0"
},
@@ -5546,6 +5558,7 @@
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz",
"integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"ip-address": "^10.2.0"
},
@@ -5563,7 +5576,8 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/fast-uri": {
"version": "3.1.2",
@@ -5579,7 +5593,8 @@
"url": "https://opencollective.com/fastify"
}
],
- "license": "BSD-3-Clause"
+ "license": "BSD-3-Clause",
+ "peer": true
},
"node_modules/fflate": {
"version": "0.8.2",
@@ -5906,6 +5921,7 @@
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz",
"integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -6047,6 +6063,7 @@
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">= 12"
}
@@ -6242,13 +6259,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/json-schema-typed": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
"integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
- "license": "BSD-2-Clause"
+ "license": "BSD-2-Clause",
+ "peer": true
},
"node_modules/json5": {
"version": "2.2.3",
@@ -7224,6 +7243,7 @@
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -9350,6 +9370,7 @@
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz",
"integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==",
"license": "ISC",
+ "peer": true,
"peerDependencies": {
"zod": "^3.25 || ^4"
}
diff --git a/package.json b/package.json
index 35bcdf0..ecbf386 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,6 @@
"@boneskull/typedoc-plugin-mermaid": "^0.2.0",
"@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/core": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/server": "2.0.0-beta.4",
"@playwright/test": "1.57.0",
"@types/bun": "^1.3.2",
@@ -113,7 +112,6 @@
"peerDependencies": {
"@modelcontextprotocol/client": "2.0.0-beta.4",
"@modelcontextprotocol/core": "2.0.0-beta.4",
- "@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/server": "2.0.0-beta.4",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
diff --git a/plugins/mcp-apps/skills/add-app-to-server/SKILL.md b/plugins/mcp-apps/skills/add-app-to-server/SKILL.md
index 02d09a4..69e41f8 100644
--- a/plugins/mcp-apps/skills/add-app-to-server/SKILL.md
+++ b/plugins/mcp-apps/skills/add-app-to-server/SKILL.md
@@ -77,13 +77,15 @@ Before writing any code, analyze the server's existing tools and determine which
## Step 2: Add Dependencies
```bash
-npm install @modelcontextprotocol/ext-apps
+npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.4 @modelcontextprotocol/core@2.0.0-beta.4 @modelcontextprotocol/server@2.0.0-beta.4 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).
-Use `npm install` to add dependencies rather than manually writing version numbers. This lets npm resolve the latest compatible versions. Never specify version numbers from memory.
+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.
## Step 3: Set Up the Build Pipeline
@@ -146,10 +148,14 @@ Transform plain MCP tools into App tools with UI.
**Before** (plain MCP tool):
```typescript
-server.tool("my-tool", { param: z.string() }, async (args) => {
- const data = await fetchData(args.param);
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
-});
+server.registerTool(
+ "my-tool",
+ { inputSchema: z.object({ param: z.string() }) },
+ async ({ param }) => {
+ const data = await fetchData(param);
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
+ },
+);
```
**After** (App tool with UI):
@@ -158,17 +164,22 @@ import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@model
const resourceUri = "ui://my-tool/mcp-app.html";
-registerAppTool(server, "my-tool", {
- description: "Shows data with an interactive UI",
- inputSchema: { param: z.string() },
- _meta: { ui: { resourceUri } },
-}, async (args) => {
- const data = await fetchData(args.param);
- return {
- content: [{ type: "text", text: JSON.stringify(data) }], // text fallback for non-UI hosts
- structuredContent: { data }, // structured data for the UI
- };
-});
+registerAppTool(
+ server,
+ "my-tool",
+ {
+ description: "Shows data with an interactive UI",
+ inputSchema: z.object({ param: z.string() }),
+ _meta: { ui: { resourceUri } },
+ },
+ async ({ param }) => {
+ const data = await fetchData(param);
+ return {
+ content: [{ type: "text", text: JSON.stringify(data) }], // text fallback for non-UI hosts
+ structuredContent: { data }, // structured data for the UI
+ };
+ },
+);
```
Key guidance:
@@ -187,17 +198,21 @@ import path from "node:path";
const resourceUri = "ui://my-tool/mcp-app.html";
-registerAppResource(server, {
- uri: resourceUri,
- name: "My Tool UI",
- mimeType: RESOURCE_MIME_TYPE,
-}, async () => {
- const html = await fs.readFile(
- path.resolve(import.meta.dirname, "dist", "mcp-app.html"),
- "utf-8",
- );
- return { contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }] };
-});
+registerAppResource(
+ server,
+ "My Tool UI",
+ resourceUri,
+ {},
+ async () => {
+ const html = await fs.readFile(
+ path.resolve(import.meta.dirname, "dist", "mcp-app.html"),
+ "utf-8",
+ );
+ return {
+ contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }],
+ };
+ },
+);
```
If multiple tools share the same UI, they can reference the same `resourceUri` and the same resource registration.
@@ -271,25 +286,32 @@ registerAppTool(server, "poll-data", {
});
```
-The UI calls these via `app.callServerTool("poll-data", {})`.
+The UI calls these via
+`app.callServerTool({ name: "poll-data", arguments: {} })`.
### CSP Configuration
If the UI needs to load external resources (fonts, APIs, CDNs), declare the domains:
```typescript
-registerAppResource(server, {
- uri: resourceUri,
- name: "My Tool UI",
- mimeType: RESOURCE_MIME_TYPE,
- _meta: {
- ui: {
- connectDomains: ["api.example.com"], // fetch/XHR targets
- resourceDomains: ["cdn.example.com"], // scripts, styles, images
- frameDomains: ["embed.example.com"], // nested iframes
+registerAppResource(server, "My Tool UI", resourceUri, {}, async () => ({
+ contents: [
+ {
+ uri: resourceUri,
+ mimeType: RESOURCE_MIME_TYPE,
+ text: html,
+ _meta: {
+ ui: {
+ csp: {
+ connectDomains: ["https://api.example.com"], // fetch/XHR targets
+ resourceDomains: ["https://cdn.example.com"], // scripts, styles, images
+ frameDomains: ["https://embed.example.com"], // nested iframes
+ },
+ },
+ },
},
- },
-}, async () => { /* ... */ });
+ ],
+}));
```
### Streaming Partial Input
@@ -326,7 +348,14 @@ server.server.oninitialized = () => {
}, appToolHandler);
} else {
// Text-only client — register plain tool
- server.tool("my-tool", "Shows data", { param: z.string() }, plainToolHandler);
+ server.registerTool(
+ "my-tool",
+ {
+ description: "Shows data",
+ inputSchema: z.object({ param: z.string() }),
+ },
+ plainToolHandler,
+ );
}
};
```
diff --git a/plugins/mcp-apps/skills/convert-web-app/SKILL.md b/plugins/mcp-apps/skills/convert-web-app/SKILL.md
index 5db2d94..22686ef 100644
--- a/plugins/mcp-apps/skills/convert-web-app/SKILL.md
+++ b/plugins/mcp-apps/skills/convert-web-app/SKILL.md
@@ -115,19 +115,20 @@ Create a new MCP server with tool and resource registration. This wraps the exis
### Dependencies
```bash
-npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk zod
+npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.4 @modelcontextprotocol/core@2.0.0-beta.4 @modelcontextprotocol/server@2.0.0-beta.4 zod@^4.2.0
npm install -D tsx vite vite-plugin-singlefile
```
-Use `npm install` to add dependencies rather than manually writing version numbers. This lets npm resolve the latest compatible versions. Never specify version numbers from memory.
+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.
### Server Code
Create `server.ts`:
```typescript
-import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
-import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+import { McpServer } from "@modelcontextprotocol/server";
+import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import fs from "node:fs/promises";
import path from "node:path";
@@ -140,7 +141,9 @@ const resourceUri = "ui://my-app/mcp-app.html";
// Register the tool — inputSchema maps to the app's data sources
registerAppTool(server, "show-app", {
description: "Displays the app with the given parameters",
- inputSchema: { query: z.string().describe("The search query") },
+ inputSchema: z.object({
+ query: z.string().describe("The search query"),
+ }),
_meta: { ui: { resourceUri } },
}, async (args) => {
// Process args server-side if needed
@@ -151,19 +154,29 @@ registerAppTool(server, "show-app", {
});
// Register the HTML resource
-registerAppResource(server, {
- uri: resourceUri,
- name: "My App UI",
- mimeType: RESOURCE_MIME_TYPE,
- // Add CSP domains from Step 2 if needed:
- // _meta: { ui: { connectDomains: ["api.example.com"], resourceDomains: ["cdn.example.com"] } },
-}, async () => {
- const html = await fs.readFile(
- path.resolve(import.meta.dirname, "dist", "mcp-app.html"),
- "utf-8",
- );
- return { contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }] };
-});
+registerAppResource(
+ server,
+ "My App UI",
+ resourceUri,
+ {},
+ async () => {
+ const html = await fs.readFile(
+ path.resolve(import.meta.dirname, "dist", "mcp-app.html"),
+ "utf-8",
+ );
+ return {
+ contents: [
+ {
+ uri: resourceUri,
+ mimeType: RESOURCE_MIME_TYPE,
+ text: html,
+ // Add CSP domains from Step 2 if needed:
+ // _meta: { ui: { csp: { connectDomains: ["https://api.example.com"], resourceDomains: ["https://cdn.example.com"] } } },
+ },
+ ],
+ };
+ },
+);
// Start the server
const transport = new StdioServerTransport();
@@ -310,7 +323,10 @@ const data = await fetch("/api/data").then(r => r.json());
// After (hybrid):
async function fetchData(): Promise {
if (isMcpApp) {
- const result = await app.callServerTool("fetch-data", {});
+ const result = await app.callServerTool({
+ name: "fetch-data",
+ arguments: {},
+ });
return result.structuredContent;
}
return fetch("/api/data").then(r => r.json());
@@ -437,7 +453,8 @@ registerAppTool(server, "refresh-data", {
});
```
-The UI calls these via `app.callServerTool("refresh-data", {})`.
+The UI calls these via
+`app.callServerTool({ name: "refresh-data", arguments: {} })`.
### Streaming Partial Input
diff --git a/plugins/mcp-apps/skills/create-mcp-app/SKILL.md b/plugins/mcp-apps/skills/create-mcp-app/SKILL.md
index 5bd1219..fc41e70 100644
--- a/plugins/mcp-apps/skills/create-mcp-app/SKILL.md
+++ b/plugins/mcp-apps/skills/create-mcp-app/SKILL.md
@@ -110,11 +110,12 @@ 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/sdk zod express cors
+npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@2.0.0-beta.4 @modelcontextprotocol/core@2.0.0-beta.4 @modelcontextprotocol/server@2.0.0-beta.4 @modelcontextprotocol/node@2.0.0-beta.4 @modelcontextprotocol/express@2.0.0-beta.4 zod@^4.2.0 express cors
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors
```
-This lets npm resolve the latest compatible versions. **Never** specify version numbers from memory.
+Use the exact base MCP SDK prerelease required by ext-apps. Do not substitute
+unpublished local packages or guess a different prerelease.
### TypeScript Server Execution
diff --git a/scripts/typedoc-plugin-base-sdk-links.mjs b/scripts/typedoc-plugin-base-sdk-links.mjs
new file mode 100644
index 0000000..6098918
--- /dev/null
+++ b/scripts/typedoc-plugin-base-sdk-links.mjs
@@ -0,0 +1,16 @@
+/**
+ * Resolve module-local links inherited from the base MCP SDK declarations.
+ *
+ * TypeDoc's externalSymbolLinkMappings handles package-qualified symbols, but
+ * the base SDK writes this particular reference as `index.inputRequired`.
+ */
+
+const BASE_SDK_DOCS = "https://ts.sdk.modelcontextprotocol.io/v2/";
+
+/** @param {import("typedoc").Application} app */
+export function load(app) {
+ app.converter.addUnknownSymbolResolver((ref) => {
+ const name = ref.symbolReference?.path?.map((part) => part.path).join(".");
+ if (name === "index.inputRequired") return BASE_SDK_DOCS;
+ });
+}
diff --git a/src/app-bridge.examples.ts b/src/app-bridge.examples.ts
index d5dc5bc..47ad623 100644
--- a/src/app-bridge.examples.ts
+++ b/src/app-bridge.examples.ts
@@ -7,17 +7,11 @@
* @module
*/
-import { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
-import {
- CallToolResult,
- CallToolResultSchema,
+import { Client, type Transport } from "@modelcontextprotocol/client";
+import type {
CreateMessageRequest,
CreateMessageResult,
- ListResourcesResultSchema,
- ReadResourceResultSchema,
- ListPromptsResultSchema,
-} from "@modelcontextprotocol/sdk/types.js";
+} from "@modelcontextprotocol/server";
import { AppBridge, PostMessageTransport } from "./app-bridge.js";
import type { McpUiDisplayMode } from "./types.js";
@@ -223,8 +217,7 @@ function AppBridge_oncalltool_forwardToServer(
bridge.oncalltool = async (params, extra) => {
return mcpClient.request(
{ method: "tools/call", params },
- CallToolResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
//#endregion AppBridge_oncalltool_forwardToServer
@@ -245,7 +238,9 @@ function AppBridge_oncreatesamplingmessage_forwardToLlm(
//#region AppBridge_oncreatesamplingmessage_forwardToLlm
bridge.oncreatesamplingmessage = async (params, extra) => {
// Apply rate limiting, user approval, cost controls here
- return await myLlmProvider.complete(params, { signal: extra.signal });
+ return await myLlmProvider.complete(params, {
+ signal: extra.mcpReq.signal,
+ });
};
//#endregion AppBridge_oncreatesamplingmessage_forwardToLlm
}
@@ -261,8 +256,7 @@ function AppBridge_onlistresources_returnResources(
bridge.onlistresources = async (params, extra) => {
return mcpClient.request(
{ method: "resources/list", params },
- ListResourcesResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
//#endregion AppBridge_onlistresources_returnResources
@@ -279,8 +273,7 @@ function AppBridge_onreadresource_returnResource(
bridge.onreadresource = async (params, extra) => {
return mcpClient.request(
{ method: "resources/read", params },
- ReadResourceResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
//#endregion AppBridge_onreadresource_returnResource
@@ -297,8 +290,7 @@ function AppBridge_onlistprompts_returnPrompts(
bridge.onlistprompts = async (params, extra) => {
return mcpClient.request(
{ method: "prompts/list", params },
- ListPromptsResultSchema,
- { signal: extra.signal },
+ { signal: extra.mcpReq.signal },
);
};
//#endregion AppBridge_onlistprompts_returnPrompts
@@ -444,10 +436,10 @@ async function AppBridge_sendToolResult_afterExecution(
args: Record,
) {
//#region AppBridge_sendToolResult_afterExecution
- const result = await mcpClient.request(
- { method: "tools/call", params: { name: "get_weather", arguments: args } },
- CallToolResultSchema,
- );
+ const result = await mcpClient.request({
+ method: "tools/call",
+ params: { name: "get_weather", arguments: args },
+ });
bridge.sendToolResult(result);
//#endregion AppBridge_sendToolResult_afterExecution
}
diff --git a/src/app-bridge.ts b/src/app-bridge.ts
index c65510d..d353cf7 100644
--- a/src/app-bridge.ts
+++ b/src/app-bridge.ts
@@ -261,7 +261,7 @@ export type AppBridgeEventMap = {
/**
* Host-side bridge for communicating with a single View ({@link app!App `App`}).
*
- * `AppBridge` extends the MCP SDK's `Protocol` class and acts as a proxy between
+ * `AppBridge` extends the base MCP SDK's public `Server` class and acts as a proxy between
* the host application and a view running in an iframe. When an MCP client
* is provided to the constructor, it automatically forwards MCP server capabilities
* (tools, resources, prompts) to the view. It also handles the initialization
@@ -667,8 +667,7 @@ export class AppBridge extends Server {
* ```typescript
* bridge.onsandboxready = async () => {
* const resource = await mcpClient.request(
- * { method: "resources/read", params: { uri: "ui://my-app" } },
- * ReadResourceResultSchema
+ * { method: "resources/read", params: { uri: "ui://my-app" } }
* );
*
* bridge.sendSandboxResourceReady({
@@ -1154,14 +1153,13 @@ export class AppBridge extends Server {
* bridge.oncalltool = async (params, extra) => {
* return mcpClient.request(
* { method: "tools/call", params },
- * CallToolResultSchema,
- * { signal: extra.signal },
+ * { signal: extra.mcpReq.signal },
* );
* };
* ```
*
- * @see `CallToolRequest` from @modelcontextprotocol/sdk for the request type
- * @see `CallToolResult` from @modelcontextprotocol/sdk for the result type
+ * @see `CallToolRequest` from @modelcontextprotocol/server for the request type
+ * @see `CallToolResult` from @modelcontextprotocol/server for the result type
*/
private _oncalltool?: (
params: CallToolRequest["params"],
@@ -1209,12 +1207,14 @@ export class AppBridge extends Server {
* ```ts source="./app-bridge.examples.ts#AppBridge_oncreatesamplingmessage_forwardToLlm"
* bridge.oncreatesamplingmessage = async (params, extra) => {
* // Apply rate limiting, user approval, cost controls here
- * return await myLlmProvider.complete(params, { signal: extra.signal });
+ * return await myLlmProvider.complete(params, {
+ * signal: extra.mcpReq.signal,
+ * });
* };
* ```
*
- * @see `CreateMessageRequest` from @modelcontextprotocol/sdk for the request type
- * @see `CreateMessageResult` / `CreateMessageResultWithTools` from @modelcontextprotocol/sdk for result types
+ * @see `CreateMessageRequest` from @modelcontextprotocol/server for the request type
+ * @see `CreateMessageResult` / `CreateMessageResultWithTools` from @modelcontextprotocol/server for result types
*/
set oncreatesamplingmessage(
callback: (
@@ -1244,7 +1244,7 @@ export class AppBridge extends Server {
* });
* ```
*
- * @see `ToolListChangedNotification` from @modelcontextprotocol/sdk for the notification type
+ * @see `ToolListChangedNotification` from @modelcontextprotocol/server for the notification type
*/
sendToolListChanged(params: ToolListChangedNotification["params"] = {}) {
return this.notification({
@@ -1270,14 +1270,13 @@ export class AppBridge extends Server {
* bridge.onlistresources = async (params, extra) => {
* return mcpClient.request(
* { method: "resources/list", params },
- * ListResourcesResultSchema,
- * { signal: extra.signal },
+ * { signal: extra.mcpReq.signal },
* );
* };
* ```
*
- * @see `ListResourcesRequest` from @modelcontextprotocol/sdk for the request type
- * @see `ListResourcesResult` from @modelcontextprotocol/sdk for the result type
+ * @see `ListResourcesRequest` from @modelcontextprotocol/server for the request type
+ * @see `ListResourcesResult` from @modelcontextprotocol/server for the result type
*/
private _onlistresources?: (
params: ListResourcesRequest["params"],
@@ -1325,14 +1324,13 @@ export class AppBridge extends Server {
* bridge.onlistresourcetemplates = async (params, extra) => {
* return mcpClient.request(
* { method: "resources/templates/list", params },
- * ListResourceTemplatesResultSchema,
- * { signal: extra.signal }
+ * { signal: extra.mcpReq.signal }
* );
* };
* ```
*
- * @see `ListResourceTemplatesRequest` from @modelcontextprotocol/sdk for the request type
- * @see `ListResourceTemplatesResult` from @modelcontextprotocol/sdk for the result type
+ * @see `ListResourceTemplatesRequest` from @modelcontextprotocol/server for the request type
+ * @see `ListResourceTemplatesResult` from @modelcontextprotocol/server for the result type
*/
private _onlistresourcetemplates?: (
params: ListResourceTemplatesRequest["params"],
@@ -1383,14 +1381,13 @@ export class AppBridge extends Server {
* bridge.onreadresource = async (params, extra) => {
* return mcpClient.request(
* { method: "resources/read", params },
- * ReadResourceResultSchema,
- * { signal: extra.signal },
+ * { signal: extra.mcpReq.signal },
* );
* };
* ```
*
- * @see `ReadResourceRequest` from @modelcontextprotocol/sdk for the request type
- * @see `ReadResourceResult` from @modelcontextprotocol/sdk for the result type
+ * @see `ReadResourceRequest` from @modelcontextprotocol/server for the request type
+ * @see `ReadResourceResult` from @modelcontextprotocol/server for the result type
*/
private _onreadresource?: (
params: ReadResourceRequest["params"],
@@ -1438,7 +1435,7 @@ export class AppBridge extends Server {
* });
* ```
*
- * @see `ResourceListChangedNotification` from @modelcontextprotocol/sdk for the notification type
+ * @see `ResourceListChangedNotification` from @modelcontextprotocol/server for the notification type
*/
sendResourceListChanged(
params: ResourceListChangedNotification["params"] = {},
@@ -1466,14 +1463,13 @@ export class AppBridge extends Server {
* bridge.onlistprompts = async (params, extra) => {
* return mcpClient.request(
* { method: "prompts/list", params },
- * ListPromptsResultSchema,
- * { signal: extra.signal },
+ * { signal: extra.mcpReq.signal },
* );
* };
* ```
*
- * @see `ListPromptsRequest` from @modelcontextprotocol/sdk for the request type
- * @see `ListPromptsResult` from @modelcontextprotocol/sdk for the result type
+ * @see `ListPromptsRequest` from @modelcontextprotocol/server for the request type
+ * @see `ListPromptsResult` from @modelcontextprotocol/server for the result type
*/
private _onlistprompts?: (
params: ListPromptsRequest["params"],
@@ -1520,7 +1516,7 @@ export class AppBridge extends Server {
* });
* ```
*
- * @see `PromptListChangedNotification` from @modelcontextprotocol/sdk for the notification type
+ * @see `PromptListChangedNotification` from @modelcontextprotocol/server for the notification type
*/
sendPromptListChanged(params: PromptListChangedNotification["params"] = {}) {
return this.notification({
@@ -1722,10 +1718,10 @@ export class AppBridge extends Server {
*
* @example
* ```ts source="./app-bridge.examples.ts#AppBridge_sendToolResult_afterExecution"
- * const result = await mcpClient.request(
- * { method: "tools/call", params: { name: "get_weather", arguments: args } },
- * CallToolResultSchema,
- * );
+ * const result = await mcpClient.request({
+ * method: "tools/call",
+ * params: { name: "get_weather", arguments: args },
+ * });
* bridge.sendToolResult(result);
* ```
*
diff --git a/src/app.examples.ts b/src/app.examples.ts
index 81bdd44..7d475ef 100644
--- a/src/app.examples.ts
+++ b/src/app.examples.ts
@@ -7,11 +7,8 @@
* @module
*/
-import type { Tool } from "@modelcontextprotocol/sdk/types.js";
-import type {
- McpServer,
- ToolCallback,
-} from "@modelcontextprotocol/sdk/server/mcp.js";
+import type { SamplingMessage, Tool } from "@modelcontextprotocol/client";
+import type { McpServer, ToolCallback } from "@modelcontextprotocol/server";
import {
App,
PostMessageTransport,
@@ -369,7 +366,7 @@ async function App_createSamplingMessage_simple(app: App) {
*/
async function App_createSamplingMessage_withTools(
app: App,
- messages: import("@modelcontextprotocol/sdk/types.js").SamplingMessage[],
+ messages: SamplingMessage[],
) {
//#region App_createSamplingMessage_withTools
if (!app.getHostCapabilities()?.sampling?.tools) return;
diff --git a/src/app.ts b/src/app.ts
index 3c8f5b7..7e752ce 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -174,9 +174,9 @@ export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
/**
* Options for configuring {@link App `App`} behavior.
*
- * Extends `ProtocolOptions` from the MCP SDK with `App`-specific configuration.
+ * Extends `ClientOptions` from the base MCP SDK with `App`-specific configuration.
*
- * @see `ProtocolOptions` from @modelcontextprotocol/sdk for inherited options
+ * @see `ClientOptions` from @modelcontextprotocol/client for inherited options
*/
export type AppOptions = Omit<
ClientOptions,
@@ -243,7 +243,7 @@ export type AppToolResult<
* validated/parsed input; when `In` is `undefined`, the callback receives only
* `extra`. When `Out` is provided, the return's `structuredContent` is typed.
*
- * Mirrors `ToolCallback` from `@modelcontextprotocol/sdk/server/mcp.js` but is
+ * Mirrors `ToolCallback` from `@modelcontextprotocol/server` but is
* parameterized over {@link StandardSchemaV1} instead of zod, so any
* Standard-Schema-compatible library (Zod, ArkType, Valibot, …) can be used.
*/
@@ -261,7 +261,7 @@ export type AppToolCallback<
/**
* Handle returned by {@link App.registerTool}. Mirrors `RegisteredTool` from
- * `@modelcontextprotocol/sdk/server/mcp.js` but stores
+ * `@modelcontextprotocol/server` but stores
* {@link StandardSchemaV1} schemas.
*/
export type RegisteredAppTool = {
@@ -302,9 +302,8 @@ export type AppEventMap = {
* Main class for MCP Apps to communicate with their host.
*
* The `App` class provides a framework-agnostic way to build interactive MCP Apps
- * that run inside host applications. It extends the MCP SDK's `Protocol` class and
- * handles the connection lifecycle, initialization handshake, and bidirectional
- * communication with the host.
+ * that run inside host applications. It extends the base MCP SDK's public
+ * `Client` class and adds the Apps handshake, lifecycle, and high-level APIs.
*
* ## Architecture
*
@@ -321,7 +320,7 @@ export type AppEventMap = {
*
* ## Protocol and event methods
*
- * As a subclass of the MCP SDK's `Protocol`, `App` provides:
+ * As a subclass of the base MCP SDK's `Client`, `App` provides:
* - `setRequestHandler()` - Register handlers for requests from host
* - `setNotificationHandler()` - Register handlers for notifications from host
* - `addEventListener()` - Append a listener for a notification event (multi-listener)
@@ -1458,8 +1457,8 @@ export class App extends Client {
* }
* ```
*
- * @see `CreateMessageRequest` from @modelcontextprotocol/sdk for the request type
- * @see `CreateMessageResult` / `CreateMessageResultWithTools` from @modelcontextprotocol/sdk for result types
+ * @see `CreateMessageRequest` from @modelcontextprotocol/client for the request type
+ * @see `CreateMessageResult` / `CreateMessageResultWithTools` from @modelcontextprotocol/client for result types
*/
async createSamplingMessage(
params: CreateMessageRequest["params"] & { tools?: undefined },
diff --git a/src/events.ts b/src/events.ts
index b891867..aff1446 100644
--- a/src/events.ts
+++ b/src/events.ts
@@ -38,9 +38,8 @@ export class EventDispatcher> {
getHandler(
event: K,
): ((params: EventMap[K]) => void) | undefined {
- return (this._eventSlots.get(event) as
- | EventSlot
- | undefined)?.onHandler;
+ return (this._eventSlots.get(event) as EventSlot | undefined)
+ ?.onHandler;
}
/** Add a listener. Listeners run in insertion order after the handler. */
diff --git a/src/message-transport.test.ts b/src/message-transport.test.ts
index d5f5092..2a115f3 100644
--- a/src/message-transport.test.ts
+++ b/src/message-transport.test.ts
@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach, afterEach, mock } from "bun:test";
-import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
+import type { JSONRPCMessage } from "@modelcontextprotocol/client";
import { PostMessageTransport } from "./message-transport";
diff --git a/src/server/index.examples.ts b/src/server/index.examples.ts
index d583ae8..9ceebce 100644
--- a/src/server/index.examples.ts
+++ b/src/server/index.examples.ts
@@ -9,17 +9,14 @@
import * as crypto from "node:crypto";
import * as fs from "node:fs/promises";
-import type {
- McpServer,
- ToolCallback,
- ReadResourceCallback,
-} from "@modelcontextprotocol/sdk/server/mcp.js";
+import type { McpServer, ToolCallback } from "@modelcontextprotocol/server";
import { z } from "zod";
import {
registerAppTool,
registerAppResource,
getUiCapability,
RESOURCE_MIME_TYPE,
+ type ReadResourceCallback,
} from "./index.js";
// Stubs for external functions used in examples
@@ -74,7 +71,7 @@ function registerAppTool_basicUsage(server: McpServer) {
{
title: "Get Weather",
description: "Get current weather for a location",
- inputSchema: { location: z.string() },
+ inputSchema: z.object({ location: z.string() }),
_meta: {
ui: { resourceUri: "ui://weather/view.html" },
},
@@ -122,7 +119,7 @@ function registerAppTool_appOnlyVisibility(server: McpServer) {
"update-quantity",
{
description: "Update item quantity in cart",
- inputSchema: { itemId: z.string(), quantity: z.number() },
+ inputSchema: z.object({ itemId: z.string(), quantity: z.number() }),
_meta: {
ui: {
resourceUri: "ui://shop/cart.html",
diff --git a/src/server/index.test.ts b/src/server/index.test.ts
index 1853cc0..5de341f 100644
--- a/src/server/index.test.ts
+++ b/src/server/index.test.ts
@@ -7,7 +7,7 @@ import {
getUiCapability,
EXTENSION_ID,
} from "./index";
-import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import type { McpServer } from "@modelcontextprotocol/server";
describe("registerAppTool", () => {
it("should pass through config to server.registerTool", () => {
diff --git a/src/server/index.ts b/src/server/index.ts
index b8b3ad0..61e7438 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -150,7 +150,7 @@ export interface McpUiAppResourceConfig extends ResourceMetadata {
* {
* title: "Get Weather",
* description: "Get current weather for a location",
- * inputSchema: { location: z.string() },
+ * inputSchema: z.object({ location: z.string() }),
* _meta: {
* ui: { resourceUri: "ui://weather/view.html" },
* },
@@ -190,7 +190,7 @@ export interface McpUiAppResourceConfig extends ResourceMetadata {
* "update-quantity",
* {
* description: "Update item quantity in cart",
- * inputSchema: { itemId: z.string(), quantity: z.number() },
+ * inputSchema: z.object({ itemId: z.string(), quantity: z.number() }),
* _meta: {
* ui: {
* resourceUri: "ui://shop/cart.html",
diff --git a/typedoc.config.mjs b/typedoc.config.mjs
index 00babc4..041bf5e 100644
--- a/typedoc.config.mjs
+++ b/typedoc.config.mjs
@@ -1,5 +1,7 @@
import { OptionDefaults } from "typedoc";
+const BASE_SDK_DOCS = "https://ts.sdk.modelcontextprotocol.io/v2/";
+
/** @type {Partial} */
const config = {
name: "MCP Apps",
@@ -29,6 +31,28 @@ const config = {
excludePrivate: true,
excludeInternal: false,
intentionallyNotExported: ["RequestHandlerExtra"],
+ externalSymbolLinkMappings: {
+ "@modelcontextprotocol/client": {
+ ClientOptions: BASE_SDK_DOCS,
+ ConnectOptions: BASE_SDK_DOCS,
+ DiscoverResult: BASE_SDK_DOCS,
+ ProtocolError: BASE_SDK_DOCS,
+ "Protocol.close": BASE_SDK_DOCS,
+ "Protocol.notification": BASE_SDK_DOCS,
+ ResponseCacheStore: BASE_SDK_DOCS,
+ SdkError: BASE_SDK_DOCS,
+ "SdkErrorCode.MethodNotSupportedByProtocolVersion": BASE_SDK_DOCS,
+ "__type.enforceStrictCapabilities": BASE_SDK_DOCS,
+ },
+ "@modelcontextprotocol/server": {
+ LoggingMessageNotification: BASE_SDK_DOCS,
+ "McpServer.registerTool": BASE_SDK_DOCS,
+ "MessageExtraInfo.classification": BASE_SDK_DOCS,
+ "Protocol.close": BASE_SDK_DOCS,
+ "Protocol.notification": BASE_SDK_DOCS,
+ "SdkErrorCode.UnsupportedResultType": BASE_SDK_DOCS,
+ },
+ },
blockTags: [...OptionDefaults.blockTags, "@description"],
jsDocCompatibility: {
exampleTag: false,
@@ -49,6 +73,7 @@ const config = {
out: "docs/api",
plugin: [
"typedoc-github-theme",
+ "./scripts/typedoc-plugin-base-sdk-links.mjs",
"./scripts/typedoc-plugin-fix-mermaid-entities.mjs",
"./scripts/typedoc-plugin-seo.mjs",
"./scripts/typedoc-plugin-mcpstyle.mjs",
From f50ec6ebfbca14bf3d3070b6d01b90f12ba93359 Mon Sep 17 00:00:00 2001
From: Andrew Khadder
Date: Tue, 14 Jul 2026 17:16:27 -0700
Subject: [PATCH 12/45] fix: regenerate lockfile for npm 10
---
package-lock.json | 401 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 401 insertions(+)
diff --git a/package-lock.json b/package-lock.json
index c1ae34d..9e0a71b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -93,6 +93,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-host/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-host/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-preact": {
"name": "@modelcontextprotocol/server-basic-preact",
"version": "1.7.4",
@@ -123,6 +140,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-server-preact/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-preact/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-react": {
"name": "@modelcontextprotocol/server-basic-react",
"version": "1.7.4",
@@ -156,6 +190,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-server-react/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-react/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-solid": {
"name": "@modelcontextprotocol/server-basic-solid",
"version": "1.7.4",
@@ -186,6 +237,23 @@
"vite-plugin-solid": "^2.11.12"
}
},
+ "examples/basic-server-solid/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-solid/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-svelte": {
"name": "@modelcontextprotocol/server-basic-svelte",
"version": "1.7.4",
@@ -216,6 +284,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-server-svelte/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-svelte/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-vanillajs": {
"name": "@modelcontextprotocol/server-basic-vanillajs",
"version": "1.7.4",
@@ -244,6 +329,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-server-vanillajs/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-vanillajs/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/basic-server-vue": {
"name": "@modelcontextprotocol/server-basic-vue",
"version": "1.7.4",
@@ -274,6 +376,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/basic-server-vue/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/basic-server-vue/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/budget-allocator-server": {
"name": "@modelcontextprotocol/server-budget-allocator",
"version": "1.7.4",
@@ -302,6 +421,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/budget-allocator-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/budget-allocator-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/cohort-heatmap-server": {
"name": "@modelcontextprotocol/server-cohort-heatmap",
"version": "1.7.4",
@@ -334,6 +470,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/cohort-heatmap-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/cohort-heatmap-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/customer-segmentation-server": {
"name": "@modelcontextprotocol/server-customer-segmentation",
"version": "1.7.4",
@@ -362,6 +515,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/customer-segmentation-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/customer-segmentation-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/debug-server": {
"name": "@modelcontextprotocol/server-debug",
"version": "1.7.4",
@@ -389,6 +559,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/debug-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/debug-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/integration-server": {
"version": "1.7.4",
"dependencies": {
@@ -419,6 +606,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/integration-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/integration-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/lazy-auth-server": {
"name": "@modelcontextprotocol/server-lazy-auth",
"version": "1.7.4",
@@ -446,6 +650,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/lazy-auth-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/lazy-auth-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/map-server": {
"name": "@modelcontextprotocol/server-map",
"version": "1.7.4",
@@ -474,6 +695,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/map-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/map-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/pdf-server": {
"name": "@modelcontextprotocol/server-pdf",
"version": "1.7.4",
@@ -504,6 +742,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/pdf-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/pdf-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/qr-server": {
"name": "@modelcontextprotocol/server-qr",
"version": "1.7.4",
@@ -536,6 +791,16 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/quickstart/node_modules/@types/node": {
+ "version": "22.19.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.5.tgz",
+ "integrity": "sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
"examples/say-server": {
"name": "@modelcontextprotocol/server-say",
"version": "1.7.4",
@@ -577,6 +842,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/scenario-modeler-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/scenario-modeler-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/shadertoy-server": {
"name": "@modelcontextprotocol/server-shadertoy",
"version": "1.7.4",
@@ -604,6 +886,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/shadertoy-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/shadertoy-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/sheet-music-server": {
"name": "@modelcontextprotocol/server-sheet-music",
"version": "1.7.4",
@@ -632,6 +931,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/sheet-music-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/sheet-music-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/system-monitor-server": {
"name": "@modelcontextprotocol/server-system-monitor",
"version": "1.7.4",
@@ -661,6 +977,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/system-monitor-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/system-monitor-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/threejs-server": {
"name": "@modelcontextprotocol/server-threejs",
"version": "1.7.4",
@@ -696,6 +1029,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/threejs-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/threejs-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/transcript-server": {
"name": "@modelcontextprotocol/server-transcript",
"version": "1.7.4",
@@ -724,6 +1074,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/transcript-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/transcript-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/video-resource-server": {
"name": "@modelcontextprotocol/server-video-resource",
"version": "1.7.4",
@@ -752,6 +1119,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/video-resource-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/video-resource-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/wiki-explorer-server": {
"name": "@modelcontextprotocol/server-wiki-explorer",
"version": "1.7.4",
@@ -782,6 +1166,23 @@
"vite-plugin-singlefile": "^2.3.0"
}
},
+ "examples/wiki-explorer-server/node_modules/@types/node": {
+ "version": "22.10.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
+ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "examples/wiki-explorer-server/node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@babel/code-frame": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
From 9778cf97a2643e58d43d3e5cdc86fe6a43773fbc Mon Sep 17 00:00:00 2001
From: Mel Ludowise
Date: Thu, 16 Jul 2026 09:00:17 -0700
Subject: [PATCH 13/45] Make lazy-auth-server usable on mobile (#714)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The consent page shipped without a viewport meta tag, so mobile browsers
laid it out at a desktop width. Its Approve/Deny buttons were 37px tall
and nested a