Skip to content

Commit a809478

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/update-context
2 parents 27f950a + 9963d0f commit a809478

File tree

100 files changed

+10088
-1905
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+10088
-1905
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
# Force LF line endings for all text files (for consistent prettier formatting)
2+
* text=auto eol=lf
3+
14
package-lock.json linguist-generated=true
5+
src/generated/** linguist-generated=true

.github/workflows/ci.yml

Lines changed: 119 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,145 @@ on:
66
pull_request:
77
branches: [main]
88

9+
permissions:
10+
contents: read
11+
912
jobs:
1013
build:
11-
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
include:
18+
- os: ubuntu-latest
19+
name: Linux x64
20+
- os: ubuntu-24.04-arm
21+
name: Linux ARM64
22+
- os: windows-latest
23+
name: Windows x64
24+
- os: windows-11-arm
25+
name: Windows ARM64
26+
- os: macos-latest
27+
name: macOS ARM64
28+
29+
name: Build (${{ matrix.name }})
30+
runs-on: ${{ matrix.os }}
31+
1232
steps:
1333
- uses: actions/checkout@v4
1434

1535
- name: Verify no private URLs in package-lock.json
36+
shell: bash
1637
run: '! grep -E "\"resolved\": \"https?://" package-lock.json | grep -v registry.npmjs.org'
1738

18-
- uses: oven-sh/setup-bun@v2
19-
with:
20-
bun-version: latest
21-
2239
- uses: actions/setup-node@v4
2340
with:
2441
node-version: "20"
2542

2643
- run: npm install
2744

28-
- run: npm run build:all
45+
- run: npm run build
46+
47+
- run: npm run examples:build
2948

3049
- name: Verify generated schemas are up-to-date
50+
shell: bash
3151
run: |
3252
npm run generate:schemas
33-
npm run prettier:fix
3453
git diff --exit-code src/generated/ || (echo "Generated schemas are out of date. Run 'npm run generate:schemas' and commit." && exit 1)
3554
3655
- run: npm test
3756

3857
- run: npm run prettier
58+
59+
e2e:
60+
runs-on: ubuntu-latest
61+
steps:
62+
- uses: actions/checkout@v4
63+
64+
- uses: oven-sh/setup-bun@v2
65+
with:
66+
bun-version: latest
67+
68+
- uses: actions/setup-node@v4
69+
with:
70+
node-version: "20"
71+
72+
- run: npm ci
73+
74+
- name: Install Playwright browsers
75+
run: npx playwright install --with-deps chromium
76+
77+
- name: Run E2E tests
78+
run: npx playwright test --reporter=list
79+
80+
- name: Upload test results
81+
uses: actions/upload-artifact@v4
82+
if: failure()
83+
with:
84+
name: test-results
85+
path: test-results/
86+
retention-days: 7
87+
88+
# Test build in Windows WSL (Ubuntu)
89+
build-wsl:
90+
name: Build (Windows WSL)
91+
runs-on: windows-latest
92+
93+
steps:
94+
- uses: actions/checkout@v4
95+
96+
- uses: Vampire/setup-wsl@v5
97+
with:
98+
distribution: Ubuntu-24.04
99+
100+
- name: Install Node.js in WSL
101+
shell: wsl-bash {0}
102+
run: |
103+
sudo apt-get update
104+
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
105+
sudo apt-get install -y nodejs
106+
107+
- name: Build and test in WSL
108+
shell: wsl-bash {0}
109+
run: |
110+
npm install
111+
npm run build
112+
npm run examples:build
113+
npm test
114+
npm run prettier
115+
116+
# Test that the package can be installed from git (triggers prepare script)
117+
test-git-install:
118+
strategy:
119+
fail-fast: false
120+
matrix:
121+
include:
122+
- os: ubuntu-latest
123+
name: Linux x64
124+
- os: ubuntu-24.04-arm
125+
name: Linux ARM64
126+
- os: windows-latest
127+
name: Windows x64
128+
- os: windows-11-arm
129+
name: Windows ARM64
130+
- os: macos-latest
131+
name: macOS ARM64
132+
133+
name: Test git install (${{ matrix.name }})
134+
runs-on: ${{ matrix.os }}
135+
136+
steps:
137+
- uses: actions/setup-node@v4
138+
with:
139+
node-version: "20"
140+
141+
- name: Create test project and install from git
142+
shell: bash
143+
run: |
144+
mkdir test-project
145+
cd test-project
146+
npm init -y
147+
# Install from the PR branch (use head repo for fork PRs)
148+
npm install "git+https://github.com/${{ github.event.pull_request.head.repo.full_name || github.repository }}#${{ github.head_ref || github.ref_name }}"
149+
# Verify the package is usable (ESM import)
150+
node --input-type=module -e "import { App } from '@modelcontextprotocol/ext-apps'; console.log('Import successful:', typeof App)"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ bun.lockb
66
.vscode/
77
docs/api/
88
tmp/
9+
intermediate-findings/
10+
11+
# Playwright
12+
playwright-report/
13+
test-results/

.husky/pre-commit

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# Verify no private registry URLs in package-lock.json
2+
if grep -E '"resolved": "https?://' package-lock.json | grep -v registry.npmjs.org > /dev/null; then
3+
echo "ERROR: package-lock.json contains non-npmjs.org URLs"
4+
echo "Run: docker run --rm -i -v \$PWD:/src -w /src node:latest npm i --registry=https://registry.npmjs.org/"
5+
exit 1
6+
fi
7+
18
npm run build:all
29
npm run prettier:fix
310

.prettierrc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "all",
4+
"singleQuote": false,
5+
"printWidth": 80,
6+
"tabWidth": 2
7+
}

CONTRIBUTING.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,45 @@ Or build and run examples:
4040
npm run examples:start
4141
```
4242

43+
## Testing
44+
45+
### Unit Tests
46+
47+
Run unit tests with Bun:
48+
49+
```bash
50+
npm test
51+
```
52+
53+
### E2E Tests
54+
55+
E2E tests use Playwright to verify all example servers work correctly with screenshot comparisons.
56+
57+
```bash
58+
# Run all E2E tests
59+
npm run test:e2e
60+
61+
# Run a specific server's tests
62+
npm run test:e2e -- --grep "Budget Allocator"
63+
64+
# Run tests in interactive UI mode
65+
npm run test:e2e:ui
66+
```
67+
68+
### Updating Golden Screenshots
69+
70+
When UI changes are intentional, update the golden screenshots:
71+
72+
```bash
73+
# Update all screenshots
74+
npm run test:e2e:update
75+
76+
# Update screenshots for a specific server
77+
npm run test:e2e:update -- --grep "Three.js"
78+
```
79+
80+
**Note**: Golden screenshots are platform-agnostic. Tests use canvas masking and tolerance thresholds to handle minor cross-platform rendering differences.
81+
4382
## Code of Conduct
4483

4584
This project follows our [Code of Conduct](CODE_OF_CONDUCT.md). Please review it before contributing.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ The [`examples/`](https://github.com/modelcontextprotocol/ext-apps/tree/main/exa
5555

5656
To run all examples together:
5757

58-
```
58+
```bash
5959
npm install
6060
npm run examples:start
6161
```

build.bun.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ function buildJs(entrypoint: string, opts: Record<string, any> = {}) {
2323
}
2424

2525
await Promise.all([
26-
buildJs("src/app.ts", { outdir: "dist/src" }),
26+
buildJs("src/app.ts", {
27+
outdir: "dist/src",
28+
external: ["@modelcontextprotocol/sdk"],
29+
}),
2730
buildJs("src/app-bridge.ts", {
2831
outdir: "dist/src",
2932
external: ["@modelcontextprotocol/sdk"],
3033
}),
3134
buildJs("src/react/index.tsx", {
3235
outdir: "dist/src/react",
33-
external: ["react", "react-dom"],
36+
external: ["react", "react-dom", "@modelcontextprotocol/sdk"],
37+
}),
38+
buildJs("src/server/index.ts", {
39+
outdir: "dist/src/server",
40+
external: ["@modelcontextprotocol/sdk"],
3441
}),
3542
]);

docs/quickstart.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,15 @@ Create `server.ts`:
9797
```typescript
9898
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9999
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
100-
import { RESOURCE_URI_META_KEY } from "@modelcontextprotocol/ext-apps";
100+
import {
101+
RESOURCE_MIME_TYPE,
102+
type McpUiToolMeta,
103+
} from "@modelcontextprotocol/ext-apps";
101104
import cors from "cors";
102105
import express from "express";
103106
import fs from "node:fs/promises";
104107
import path from "node:path";
105-
import { z } from "zod";
108+
import * as z from "zod";
106109

107110
const server = new McpServer({
108111
name: "My MCP App Server",
@@ -119,7 +122,7 @@ server.registerTool(
119122
description: "Returns the current server time.",
120123
inputSchema: {},
121124
outputSchema: { time: z.string() },
122-
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, // Links tool to UI
125+
_meta: { ui: { resourceUri } as McpUiToolMeta }, // Links tool to UI
123126
},
124127
async () => {
125128
const time = new Date().toISOString();
@@ -130,17 +133,22 @@ server.registerTool(
130133
},
131134
);
132135

133-
server.registerResource(resourceUri, resourceUri, {}, async () => {
134-
const html = await fs.readFile(
135-
path.join(import.meta.dirname, "dist", "mcp-app.html"),
136-
"utf-8",
137-
);
138-
return {
139-
contents: [
140-
{ uri: resourceUri, mimeType: "text/html;profile=mcp-app", text: html },
141-
],
142-
};
143-
});
136+
server.registerResource(
137+
resourceUri,
138+
resourceUri,
139+
{ mimeType: "text/html;profile=mcp-app" },
140+
async () => {
141+
const html = await fs.readFile(
142+
path.join(import.meta.dirname, "dist", "mcp-app.html"),
143+
"utf-8",
144+
);
145+
return {
146+
contents: [
147+
{ uri: resourceUri, mimeType: "text/html;profile=mcp-app", text: html },
148+
],
149+
};
150+
},
151+
);
144152

145153
// Express server for MCP endpoint
146154
const app = express();

examples/basic-host/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta name="color-scheme" content="light dark">
67
<title>MCP Apps Host</title>
78
<link rel="stylesheet" href="/src/global.css">
89
</head>

0 commit comments

Comments
 (0)