diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 37936222..2813b2dd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -40,6 +40,465 @@ Or build and run examples:
npm run examples:start
```
+### With MCP Clients
+
+To use these examples with MCP clients that support the stdio transport (such as Claude Desktop or VS Code), add this MCP server configuration to your client's settings:
+
+
+MCP client configuration for all examples (using stdio)
+
+```json
+{
+ "mcpServers": {
+ "basic-react": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-react",
+ "--stdio"
+ ]
+ },
+ "basic-vanillajs": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-vanillajs",
+ "--stdio"
+ ]
+ },
+ "basic-vue": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-vue",
+ "--stdio"
+ ]
+ },
+ "basic-svelte": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-svelte",
+ "--stdio"
+ ]
+ },
+ "basic-preact": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-preact",
+ "--stdio"
+ ]
+ },
+ "basic-solid": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-basic-solid",
+ "--stdio"
+ ]
+ },
+ "budget-allocator": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-budget-allocator",
+ "--stdio"
+ ]
+ },
+ "cohort-heatmap": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-cohort-heatmap",
+ "--stdio"
+ ]
+ },
+ "customer-segmentation": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-customer-segmentation",
+ "--stdio"
+ ]
+ },
+ "map": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-map",
+ "--stdio"
+ ]
+ },
+ "pdf": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-pdf",
+ "--stdio"
+ ]
+ },
+ "scenario-modeler": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-scenario-modeler",
+ "--stdio"
+ ]
+ },
+ "shadertoy": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-shadertoy",
+ "--stdio"
+ ]
+ },
+ "sheet-music": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-sheet-music",
+ "--stdio"
+ ]
+ },
+ "system-monitor": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-system-monitor",
+ "--stdio"
+ ]
+ },
+ "threejs": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-threejs",
+ "--stdio"
+ ]
+ },
+ "transcript": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-transcript",
+ "--stdio"
+ ]
+ },
+ "video-resource": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-video-resource",
+ "--stdio"
+ ]
+ },
+ "wiki-explorer": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "--silent",
+ "--registry=https://registry.npmjs.org/",
+ "@modelcontextprotocol/server-wiki-explorer",
+ "--stdio"
+ ]
+ },
+ "qr": {
+ "command": "uv",
+ "args": [
+ "run",
+ "/path/to/ext-apps/examples/qr-server/server.py",
+ "--stdio"
+ ]
+ },
+ "say": {
+ "command": "uv",
+ "args": [
+ "run",
+ "--default-index",
+ "https://pypi.org/simple",
+ "https://raw.githubusercontent.com/modelcontextprotocol/ext-apps/refs/heads/main/examples/say-server/server.py",
+ "--stdio"
+ ]
+ }
+ }
+}
+```
+
+
+
+> [!NOTE]
+> The `qr` server requires cloning the repository first. See [qr-server README](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/qr-server) for details.
+
+### Local Development
+
+To test local modifications with MCP clients, first clone and install the repository:
+
+```bash
+git clone https://github.com/modelcontextprotocol/ext-apps.git
+cd ext-apps
+npm install
+```
+
+Then configure your MCP client to build and run the local server. Replace `~/code/ext-apps` with your actual clone path.
+
+Most example servers have a `start:stdio` script that builds and launches in stdio mode. Use `npm --silent run start:stdio` for these:
+
+
+MCP client configuration for local development (all examples)
+
+```json
+{
+ "mcpServers": {
+ "basic-react": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-react",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "basic-vanillajs": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-vanillajs",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "basic-vue": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-vue",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "basic-svelte": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-svelte",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "basic-preact": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-preact",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "basic-solid": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/basic-server-solid",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "budget-allocator": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/budget-allocator-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "cohort-heatmap": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/cohort-heatmap-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "customer-segmentation": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/customer-segmentation-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "map": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/map-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "pdf": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/pdf-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "scenario-modeler": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/scenario-modeler-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "shadertoy": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/shadertoy-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "sheet-music": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/sheet-music-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "system-monitor": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/system-monitor-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "threejs": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/threejs-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "transcript": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/transcript-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "video-resource": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/video-resource-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "wiki-explorer": {
+ "command": "npm",
+ "args": [
+ "--silent",
+ "--prefix",
+ "~/code/ext-apps/examples/wiki-explorer-server",
+ "run",
+ "start:stdio"
+ ]
+ },
+ "qr": {
+ "command": "bash",
+ "args": [
+ "-c",
+ "uv run ~/code/ext-apps/examples/qr-server/server.py --stdio"
+ ]
+ },
+ "say": {
+ "command": "bash",
+ "args": [
+ "-c",
+ "uv run --index https://pypi.org/simple ~/code/ext-apps/examples/say-server/server.py --stdio"
+ ]
+ }
+ }
+}
+```
+
+
+
+This configuration rebuilds each server on launch, ensuring your local changes are picked up.
+
## Testing
### Unit Tests
diff --git a/examples/basic-server-preact/package.json b/examples/basic-server-preact/package.json
index 166b75f8..32fb1a00 100644
--- a/examples/basic-server-preact/package.json
+++ b/examples/basic-server-preact/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/basic-server-react/package.json b/examples/basic-server-react/package.json
index 0df22017..9732266d 100644
--- a/examples/basic-server-react/package.json
+++ b/examples/basic-server-react/package.json
@@ -27,7 +27,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/basic-server-solid/package.json b/examples/basic-server-solid/package.json
index b8115cbb..d31b8e3f 100644
--- a/examples/basic-server-solid/package.json
+++ b/examples/basic-server-solid/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/basic-server-svelte/package.json b/examples/basic-server-svelte/package.json
index 2f6a7b66..2f57cfca 100644
--- a/examples/basic-server-svelte/package.json
+++ b/examples/basic-server-svelte/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/basic-server-vanillajs/package.json b/examples/basic-server-vanillajs/package.json
index 44d3fdb2..eb0b24a2 100644
--- a/examples/basic-server-vanillajs/package.json
+++ b/examples/basic-server-vanillajs/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/basic-server-vue/package.json b/examples/basic-server-vue/package.json
index e77102b5..ea7e2b41 100644
--- a/examples/basic-server-vue/package.json
+++ b/examples/basic-server-vue/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/debug-server/package.json b/examples/debug-server/package.json
index ec2a644a..7f36b3a2 100644
--- a/examples/debug-server/package.json
+++ b/examples/debug-server/package.json
@@ -27,7 +27,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/sheet-music-server/package.json b/examples/sheet-music-server/package.json
index 54ea185e..d7a45a29 100644
--- a/examples/sheet-music-server/package.json
+++ b/examples/sheet-music-server/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/transcript-server/package.json b/examples/transcript-server/package.json
index e72c109c..c9202857 100644
--- a/examples/transcript-server/package.json
+++ b/examples/transcript-server/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},
diff --git a/examples/video-resource-server/package.json b/examples/video-resource-server/package.json
index cf641323..77c34a0e 100644
--- a/examples/video-resource-server/package.json
+++ b/examples/video-resource-server/package.json
@@ -17,7 +17,9 @@
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch main.ts",
+ "serve:stdio": "bun main.ts --stdio",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
+ "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio",
"dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"",
"prepublishOnly": "npm run build"
},