Skip to content

Commit 502126d

Browse files
committed
Merge remote-tracking branch 'origin/main' into ochafik/pdf-server
2 parents 3efa1c4 + 152b953 commit 502126d

File tree

39 files changed

+1016
-44
lines changed

39 files changed

+1016
-44
lines changed

README.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,28 @@ Or edit your `package.json` manually:
5656

5757
## Examples
5858

59-
Start with these foundational examples to learn the SDK:
60-
61-
- [`examples/basic-server-vanillajs`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-vanillajs) — MCP server + MCP App using vanilla JS
62-
- [`examples/basic-server-react`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-react) — MCP server + MCP App using [React](https://github.com/facebook/react)
63-
- [`examples/basic-server-vue`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-vue) — MCP server + MCP App using [Vue](https://github.com/vuejs/vue)
64-
- [`examples/basic-server-svelte`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-svelte) — MCP server + MCP App using [Svelte](https://github.com/sveltejs/svelte)
65-
- [`examples/basic-server-preact`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-preact) — MCP server + MCP App using [Preact](https://github.com/preactjs/preact)
66-
- [`examples/basic-server-solid`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-solid) — MCP server + MCP App using [Solid](https://github.com/solidjs/solid)
67-
- [`examples/basic-host`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) — MCP host application supporting MCP Apps
59+
<!-- prettier-ignore-start -->
60+
| | | |
61+
|:---:|:---:|:---:|
62+
| [![Map](examples/map-server/grid-cell.png "Interactive 3D globe viewer using CesiumJS")](examples/map-server) | [![Three.js](examples/threejs-server/grid-cell.png "Interactive 3D scene renderer")](examples/threejs-server) | [![ShaderToy](examples/shadertoy-server/grid-cell.png "Real-time GLSL shader renderer")](examples/shadertoy-server) |
63+
| [**Map**](examples/map-server) | [**Three.js**](examples/threejs-server) | [**ShaderToy**](examples/shadertoy-server) |
64+
| [![Sheet Music](examples/sheet-music-server/grid-cell.png "ABC notation to sheet music")](examples/sheet-music-server) | [![Wiki Explorer](examples/wiki-explorer-server/grid-cell.png "Wikipedia link graph visualization")](examples/wiki-explorer-server) | [![Cohort Heatmap](examples/cohort-heatmap-server/grid-cell.png "Customer retention heatmap")](examples/cohort-heatmap-server) |
65+
| [**Sheet Music**](examples/sheet-music-server) | [**Wiki Explorer**](examples/wiki-explorer-server) | [**Cohort Heatmap**](examples/cohort-heatmap-server) |
66+
| [![Scenario Modeler](examples/scenario-modeler-server/grid-cell.png "SaaS business projections")](examples/scenario-modeler-server) | [![Budget Allocator](examples/budget-allocator-server/grid-cell.png "Interactive budget allocation")](examples/budget-allocator-server) | [![Customer Segmentation](examples/customer-segmentation-server/grid-cell.png "Scatter chart with clustering")](examples/customer-segmentation-server) |
67+
| [**Scenario Modeler**](examples/scenario-modeler-server) | [**Budget Allocator**](examples/budget-allocator-server) | [**Customer Segmentation**](examples/customer-segmentation-server) |
68+
| [![System Monitor](examples/system-monitor-server/grid-cell.png "Real-time OS metrics")](examples/system-monitor-server) | [![Transcript](examples/transcript-server/grid-cell.png "Live speech transcription")](examples/transcript-server) | [![Video Resource](examples/video-resource-server/grid-cell.png "Binary video via MCP resources")](examples/video-resource-server) |
69+
| [**System Monitor**](examples/system-monitor-server) | [**Transcript**](examples/transcript-server) | [**Video Resource**](examples/video-resource-server) |
70+
71+
### Starter Templates
72+
73+
| | |
74+
|:---:|:---|
75+
| [![Basic](examples/basic-server-react/grid-cell.png "Starter template")](examples/basic-server-react) | The same app built with different frameworks — pick your favorite!<br><br>[React](examples/basic-server-react) · [Vue](examples/basic-server-vue) · [Svelte](examples/basic-server-svelte) · [Preact](examples/basic-server-preact) · [Solid](examples/basic-server-solid) · [Vanilla JS](examples/basic-server-vanillajs) |
76+
<!-- prettier-ignore-end -->
6877

6978
The [`examples/`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples) directory contains additional demo apps showcasing real-world use cases.
7079

71-
To run all examples together:
80+
To run all examples:
7281

7382
```bash
7483
npm install

docs/migrate_from_openai_apps.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Migrating from OpenAI Apps SDK to MCP Apps SDK
2+
3+
This guide helps you migrate from the OpenAI Apps SDK (`window.openai.*`) to the MCP Apps SDK (`@modelcontextprotocol/ext-apps`).
4+
5+
## Quick Start Comparison
6+
7+
| OpenAI Apps SDK | MCP Apps SDK |
8+
| --------------------------------- | ---------------------------------- |
9+
| Implicit global (`window.openai`) | Explicit instance (`new App(...)`) |
10+
| Properties pre-populated on load | Async connection + notifications |
11+
| Sync property access | Getters + event handlers |
12+
13+
## Setup & Connection
14+
15+
| OpenAI | MCP Apps | Notes |
16+
| -------------------------------- | -------------------------------------------------- | ------------------------------------------------------ |
17+
| `window.openai` (auto-available) | `const app = new App({name, version}, {})` | MCP requires explicit instantiation |
18+
| (implicit) | `await app.connect()` | MCP requires async connection; auto-detects OpenAI env |
19+
|| `await app.connect(new OpenAITransport())` | Force OpenAI mode (not yet available, see [PR #172](https://github.com/modelcontextprotocol/ext-apps/pull/172)) |
20+
|| `await app.connect(new PostMessageTransport(...))` | Force MCP mode explicitly |
21+
22+
## Host Context Properties
23+
24+
| OpenAI | MCP Apps | Notes |
25+
| --------------------------- | --------------------------------------------- | --------------------------------------- |
26+
| `window.openai.theme` | `app.getHostContext()?.theme` | `"light"` \| `"dark"` |
27+
| `window.openai.locale` | `app.getHostContext()?.locale` | BCP 47 language tag (e.g., `"en-US"`) |
28+
| `window.openai.displayMode` | `app.getHostContext()?.displayMode` | `"inline"` \| `"pip"` \| `"fullscreen"` |
29+
| `window.openai.maxHeight` | `app.getHostContext()?.viewport?.maxHeight` | Max container height in px |
30+
| `window.openai.safeArea` | `app.getHostContext()?.safeAreaInsets` | `{ top, right, bottom, left }` |
31+
| `window.openai.userAgent` | `app.getHostContext()?.userAgent` | Host user agent string |
32+
|| `app.getHostContext()?.availableDisplayModes` | MCP adds: which modes host supports |
33+
|| `app.getHostContext()?.toolInfo` | MCP adds: tool metadata during call |
34+
35+
## Tool Data (Input/Output)
36+
37+
| OpenAI | MCP Apps | Notes |
38+
| ------------------------------------ | ---------------------------------------------------- | ----------------------------------- |
39+
| `window.openai.toolInput` | `app.ontoolinput = (params) => { params.arguments }` | Tool arguments; MCP uses callback |
40+
| `window.openai.toolOutput` | `app.ontoolresult = (params) => { params.content }` | Tool result; MCP uses callback |
41+
| `window.openai.toolResponseMetadata` | `app.ontoolresult``params._meta` | Widget-only metadata from server |
42+
|| `app.ontoolinputpartial = (params) => {...}` | MCP adds: streaming partial args |
43+
|| `app.ontoolcancelled = (params) => {...}` | MCP adds: cancellation notification |
44+
45+
## Calling Tools
46+
47+
| OpenAI | MCP Apps | Notes |
48+
| ------------------------------------------ | ----------------------------------------------------- | ---------------------------- |
49+
| `await window.openai.callTool(name, args)` | `await app.callServerTool({ name, arguments: args })` | Call another MCP server tool |
50+
51+
## Sending Messages
52+
53+
| OpenAI | MCP Apps | Notes |
54+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------- |
55+
| `await window.openai.sendFollowUpMessage({ prompt })` | `await app.sendMessage({ role: "user", content: [{ type: "text", text: prompt }] })` | MCP uses structured content array |
56+
57+
## External Links
58+
59+
| OpenAI | MCP Apps | Notes |
60+
| -------------------------------------------- | ----------------------------------- | ------------------------------------ |
61+
| `await window.openai.openExternal({ href })` | `await app.openLink({ url: href })` | Different param name: `href``url` |
62+
63+
## Display Mode
64+
65+
| OpenAI | MCP Apps | Notes |
66+
| -------------------------------------------------- | --------------------------------------------------------- | ----------------------------------- |
67+
| `await window.openai.requestDisplayMode({ mode })` | `await app.requestDisplayMode({ mode })` | Same API |
68+
|| Check `app.getHostContext()?.availableDisplayModes` first | MCP lets you check what's available |
69+
70+
## Size Reporting
71+
72+
| OpenAI | MCP Apps | Notes |
73+
| --------------------------------------------- | ----------------------------------------- | ----------------------------------- |
74+
| `window.openai.notifyIntrinsicHeight(height)` | `app.sendSizeChanged({ width, height })` | MCP includes width |
75+
| Manual only | Auto via `{ autoResize: true }` (default) | MCP auto-reports via ResizeObserver |
76+
77+
## State Persistence
78+
79+
| OpenAI | MCP Apps | Notes |
80+
| ------------------------------------- | -------- | ----------------------------------------------- |
81+
| `window.openai.widgetState` || Not directly available in MCP |
82+
| `window.openai.setWidgetState(state)` || Use alternative mechanisms (`localStorage`, server-side state, etc.) |
83+
84+
## File Operations (Not Yet in MCP Apps)
85+
86+
| OpenAI | MCP Apps | Notes |
87+
| ---------------------------------------------------- | -------- | ------------------- |
88+
| `await window.openai.uploadFile(file)` || Not yet implemented |
89+
| `await window.openai.getFileDownloadUrl({ fileId })` || Not yet implemented |
90+
91+
## Other (Not Yet in MCP Apps)
92+
93+
| OpenAI | MCP Apps | Notes |
94+
| ------------------------------------------- | -------- | ------------------- |
95+
| `await window.openai.requestModal(options)` || Not yet implemented |
96+
| `window.openai.requestClose()` || Not yet implemented |
97+
| `window.openai.view` || Not yet mapped |
98+
99+
## Event Handling
100+
101+
| OpenAI | MCP Apps | Notes |
102+
| ------------------------------ | ------------------------------------------- | -------------------------------- |
103+
| Read `window.openai.*` on load | `app.ontoolinput = (params) => {...}` | Register before `connect()` |
104+
| Read `window.openai.*` on load | `app.ontoolresult = (params) => {...}` | Register before `connect()` |
105+
| Poll or re-read properties | `app.onhostcontextchanged = (ctx) => {...}` | MCP pushes context changes |
106+
|| `app.onteardown = async () => {...}` | MCP adds: cleanup before unmount |
107+
108+
## Logging
109+
110+
| OpenAI | MCP Apps | Notes |
111+
| ------------------ | --------------------------------------------- | ------------------------------- |
112+
| `console.log(...)` | `app.sendLog({ level: "info", data: "..." })` | MCP provides structured logging |
113+
114+
## Host Info
115+
116+
| OpenAI | MCP Apps | Notes |
117+
| ------ | --------------------------- | ------------------------------------------------- |
118+
|| `app.getHostVersion()` | Returns `{ name, version }` of host |
119+
|| `app.getHostCapabilities()` | Check `serverTools`, `openLinks`, `logging`, etc. |
120+
121+
## Full Migration Example
122+
123+
### Before (OpenAI)
124+
125+
```typescript
126+
// OpenAI Apps SDK
127+
const theme = window.openai.theme;
128+
const toolArgs = window.openai.toolInput;
129+
const toolResult = window.openai.toolOutput;
130+
131+
// Call a tool
132+
const result = await window.openai.callTool("get_weather", { city: "Tokyo" });
133+
134+
// Send a message
135+
await window.openai.sendFollowUpMessage({ prompt: "Weather updated!" });
136+
137+
// Report height
138+
window.openai.notifyIntrinsicHeight(400);
139+
140+
// Open link
141+
await window.openai.openExternal({ href: "https://example.com" });
142+
```
143+
144+
### After (MCP Apps)
145+
146+
```typescript
147+
import { App } from "@modelcontextprotocol/ext-apps";
148+
149+
const app = new App(
150+
{ name: "MyApp", version: "1.0.0" },
151+
{},
152+
{ autoResize: true }, // auto height reporting
153+
);
154+
155+
// Register handlers BEFORE connect
156+
app.ontoolinput = (params) => {
157+
console.log("Tool args:", params.arguments);
158+
};
159+
160+
app.ontoolresult = (params) => {
161+
console.log("Tool result:", params.content);
162+
};
163+
164+
app.onhostcontextchanged = (ctx) => {
165+
if (ctx.theme) applyTheme(ctx.theme);
166+
};
167+
168+
// Connect (auto-detects OpenAI vs MCP)
169+
await app.connect();
170+
171+
// Access context
172+
const theme = app.getHostContext()?.theme;
173+
174+
// Call a tool
175+
const result = await app.callServerTool({
176+
name: "get_weather",
177+
arguments: { city: "Tokyo" },
178+
});
179+
180+
// Send a message
181+
await app.sendMessage({
182+
role: "user",
183+
content: [{ type: "text", text: "Weather updated!" }],
184+
});
185+
186+
// Open link (note: url not href)
187+
await app.openLink({ url: "https://example.com" });
188+
```
189+
190+
## Key Differences Summary
191+
192+
1. **Initialization**: OpenAI is implicit; MCP requires `new App()` + `await app.connect()`
193+
2. **Data Flow**: OpenAI pre-populates; MCP uses async notifications (register handlers before `connect()`)
194+
3. **Auto-resize**: MCP has built-in ResizeObserver support via `autoResize` option
195+
4. **Structured Content**: MCP uses `{ type: "text", text: "..." }` arrays for messages
196+
5. **Context Changes**: MCP pushes updates via `onhostcontextchanged`; no polling needed
197+
6. **Capabilities**: MCP lets you check what the host supports before calling methods

examples/basic-server-react/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Example: Basic Server (React)
22

3+
![Screenshot](screenshot.png)
4+
35
An MCP App example with a React UI.
46

57
> [!TIP]
24.9 KB
Loading
20.8 KB
Loading
32.5 KB
Loading
39.5 KB
Loading
49 KB
Loading
63.9 KB
Loading
39.1 KB
Loading

0 commit comments

Comments
 (0)