Skip to content

Commit fbe2459

Browse files
authored
Create migrate_from_openai_apps.md
1 parent bd892b6 commit fbe2459

1 file changed

Lines changed: 198 additions & 0 deletions

File tree

docs/migrate_from_openai_apps.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
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 explicitly |
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+
| Returns `{ structuredContent?, content?, isError? }` | Returns `{ content, structuredContent?, isError? }` | Same shape, slightly different ordering |
51+
52+
## Sending Messages
53+
54+
| OpenAI | MCP Apps | Notes |
55+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------- |
56+
| `await window.openai.sendFollowUpMessage({ prompt })` | `await app.sendMessage({ role: "user", content: [{ type: "text", text: prompt }] })` | MCP uses structured content array |
57+
58+
## External Links
59+
60+
| OpenAI | MCP Apps | Notes |
61+
| -------------------------------------------- | ----------------------------------- | ------------------------------------ |
62+
| `await window.openai.openExternal({ href })` | `await app.openLink({ url: href })` | Different param name: `href``url` |
63+
64+
## Display Mode
65+
66+
| OpenAI | MCP Apps | Notes |
67+
| -------------------------------------------------- | --------------------------------------------------------- | ----------------------------------- |
68+
| `await window.openai.requestDisplayMode({ mode })` | `await app.requestDisplayMode({ mode })` | Same API |
69+
|| Check `app.getHostContext()?.availableDisplayModes` first | MCP lets you check what's available |
70+
71+
## Size Reporting
72+
73+
| OpenAI | MCP Apps | Notes |
74+
| --------------------------------------------- | ----------------------------------------- | ----------------------------------- |
75+
| `window.openai.notifyIntrinsicHeight(height)` | `app.sendSizeChanged({ width, height })` | MCP includes width |
76+
| Manual only | Auto via `{ autoResize: true }` (default) | MCP auto-reports via ResizeObserver |
77+
78+
## State Persistence
79+
80+
| OpenAI | MCP Apps | Notes |
81+
| ------------------------------------- | -------- | ----------------------------------------------- |
82+
| `window.openai.widgetState` || Not directly available in MCP |
83+
| `window.openai.setWidgetState(state)` || Use framework state (React, localStorage, etc.) |
84+
85+
## File Operations (Not Yet in MCP Apps)
86+
87+
| OpenAI | MCP Apps | Notes |
88+
| ---------------------------------------------------- | -------- | ------------------- |
89+
| `await window.openai.uploadFile(file)` || Not yet implemented |
90+
| `await window.openai.getFileDownloadUrl({ fileId })` || Not yet implemented |
91+
92+
## Other (Not Yet in MCP Apps)
93+
94+
| OpenAI | MCP Apps | Notes |
95+
| ------------------------------------------- | -------- | ------------------- |
96+
| `await window.openai.requestModal(options)` || Not yet implemented |
97+
| `window.openai.requestClose()` || Not yet implemented |
98+
| `window.openai.view` || Not yet mapped |
99+
100+
## Event Handling
101+
102+
| OpenAI | MCP Apps | Notes |
103+
| ------------------------------ | ------------------------------------------- | -------------------------------- |
104+
| Read `window.openai.*` on load | `app.ontoolinput = (params) => {...}` | Register before `connect()` |
105+
| Read `window.openai.*` on load | `app.ontoolresult = (params) => {...}` | Register before `connect()` |
106+
| Poll or re-read properties | `app.onhostcontextchanged = (ctx) => {...}` | MCP pushes context changes |
107+
|| `app.onteardown = async () => {...}` | MCP adds: cleanup before unmount |
108+
109+
## Logging
110+
111+
| OpenAI | MCP Apps | Notes |
112+
| ------------------ | --------------------------------------------- | ------------------------------- |
113+
| `console.log(...)` | `app.sendLog({ level: "info", data: "..." })` | MCP provides structured logging |
114+
115+
## Host Info
116+
117+
| OpenAI | MCP Apps | Notes |
118+
| ------ | --------------------------- | ------------------------------------------------- |
119+
|| `app.getHostVersion()` | Returns `{ name, version }` of host |
120+
|| `app.getHostCapabilities()` | Check `serverTools`, `openLinks`, `logging`, etc. |
121+
122+
## Full Migration Example
123+
124+
### Before (OpenAI)
125+
126+
```typescript
127+
// OpenAI Apps SDK
128+
const theme = window.openai.theme;
129+
const toolArgs = window.openai.toolInput;
130+
const toolResult = window.openai.toolOutput;
131+
132+
// Call a tool
133+
const result = await window.openai.callTool("get_weather", { city: "Tokyo" });
134+
135+
// Send a message
136+
await window.openai.sendFollowUpMessage({ prompt: "Weather updated!" });
137+
138+
// Report height
139+
window.openai.notifyIntrinsicHeight(400);
140+
141+
// Open link
142+
await window.openai.openExternal({ href: "https://example.com" });
143+
```
144+
145+
### After (MCP Apps)
146+
147+
```typescript
148+
import { App } from "@modelcontextprotocol/ext-apps";
149+
150+
const app = new App(
151+
{ name: "MyApp", version: "1.0.0" },
152+
{},
153+
{ autoResize: true }, // auto height reporting
154+
);
155+
156+
// Register handlers BEFORE connect
157+
app.ontoolinput = (params) => {
158+
console.log("Tool args:", params.arguments);
159+
};
160+
161+
app.ontoolresult = (params) => {
162+
console.log("Tool result:", params.content);
163+
};
164+
165+
app.onhostcontextchanged = (ctx) => {
166+
if (ctx.theme) applyTheme(ctx.theme);
167+
};
168+
169+
// Connect (auto-detects OpenAI vs MCP)
170+
await app.connect();
171+
172+
// Access context
173+
const theme = app.getHostContext()?.theme;
174+
175+
// Call a tool
176+
const result = await app.callServerTool({
177+
name: "get_weather",
178+
arguments: { city: "Tokyo" },
179+
});
180+
181+
// Send a message
182+
await app.sendMessage({
183+
role: "user",
184+
content: [{ type: "text", text: "Weather updated!" }],
185+
});
186+
187+
// Open link (note: url not href)
188+
await app.openLink({ url: "https://example.com" });
189+
```
190+
191+
## Key Differences Summary
192+
193+
1. **Initialization**: OpenAI is implicit; MCP requires `new App()` + `await app.connect()`
194+
2. **Data Flow**: OpenAI pre-populates; MCP uses async notifications (register handlers before `connect()`)
195+
3. **Auto-resize**: MCP has built-in ResizeObserver support via `autoResize` option
196+
4. **Structured Content**: MCP uses `{ type: "text", text: "..." }` arrays for messages
197+
5. **Context Changes**: MCP pushes updates via `onhostcontextchanged`; no polling needed
198+
6. **Capabilities**: MCP lets you check what the host supports before calling methods

0 commit comments

Comments
 (0)