migrate-oai-app
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMigrate OpenAI App to MCP
将OpenAI App迁移至MCP
Migrate existing OpenAI Apps SDK applications to the MCP Apps SDK (). The MCP Apps SDK provides a standardized, open protocol for interactive UIs in conversational clients.
@modelcontextprotocol/ext-apps将现有OpenAI Apps SDK应用迁移至MCP Apps SDK()。MCP Apps SDK为对话式客户端中的交互式UI提供了一套标准化的开放协议。
@modelcontextprotocol/ext-appsBest Practices
最佳实践
- Use your package manager to add dependencies (e.g., ,
npm install,pnpm add) instead of manually writing version numbers. This lets the package manager resolve the latest compatible versions. Never specify version numbers from memory.yarn add - Preemptively add a final todo item with this exact wording: "Re-read the 'Before Finishing' checklist in this skill and address each checkbox individually, stating what you did for each one, before marking this todo complete."
- 使用包管理器添加依赖(例如、
npm install、pnpm add),而非手动编写版本号。这样包管理器会自动解析最新的兼容版本,切勿凭记忆指定版本号。yarn add - 提前添加一个最终待办事项,内容必须为:“在标记此待办事项完成前,重新阅读本技能中的‘完成前检查’清单,逐一处理每个检查项,并说明针对每项所做的操作。”
Getting Reference Code
获取参考代码
Clone the SDK repository for complete migration documentation and working examples:
bash
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps克隆SDK仓库以获取完整的迁移文档及可运行示例:
bash
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-appsMigration Reference Guide
迁移参考指南
Read the migration reference guide with "before/after" mapping tables:
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md阅读包含“迁移前/后”映射表的迁移参考指南:
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.mdAPI Reference (Source Files)
API参考(源文件)
Read JSDoc documentation directly from :
/tmp/mcp-ext-apps/src/*| File | Contents |
|---|---|
| |
| |
| Type definitions |
| |
| Other |
直接从读取JSDoc文档:
/tmp/mcp-ext-apps/src/*| 文件 | 内容 |
|---|---|
| |
| |
| 类型定义 |
| 用于React应用的 |
| 其他用于React应用的 |
Front-End Framework Examples
前端框架示例
See for basic SDK usage examples organized by front-end framework:
/tmp/mcp-ext-apps/examples/basic-server-{framework}/| Template | Key Files |
|---|---|
| |
| |
| |
| |
| |
| |
查看获取按前端框架分类的SDK基础使用示例:
/tmp/mcp-ext-apps/examples/basic-server-{framework}/| 模板 | 关键文件 |
|---|---|
| |
| |
| |
| |
| |
| |
CSP Investigation
CSP调查
MCP Apps HTML is served as an MCP resource, not as a web page, and runs in a sandboxed iframe with no same-origin server. Every origin must be declared in CSP—including the origin serving your JS/CSS bundles ( in dev, your CDN in production). Missing origins fail silently.
localhostBefore writing any migration code, build the app and investigate all origins it references:
- Build the app using the existing build command
- Search the resulting HTML, CSS, and JS for every origin (not just "external" origins—every network request will need CSP approval)
- For each origin found, trace back to source:
- If it comes from a constant → universal (same in dev and prod)
- If it comes from an env var or conditional → note the mechanism and identify both dev and prod values
- Check for third-party libraries that may make their own requests (analytics, error tracking, etc.)
Document your findings as three lists, and note for each origin whether it's universal, dev-only, or prod-only:
- resourceDomains: origins serving images, fonts, styles, scripts
- connectDomains: origins for API/fetch requests
- frameDomains: origins for nested iframes
If no origins are found, the app may not need custom CSP domains.
MCP Apps HTML作为MCP资源提供,而非网页,它在无同源服务器的沙箱化iframe中运行。所有源都必须在CSP中声明——包括提供JS/CSS包的源(开发环境为localhost,生产环境为你的CDN)。缺失的源会静默失败。
在编写任何迁移代码前,构建应用并调查它引用的所有源:
- 使用现有构建命令构建应用
- 在生成的HTML、CSS和JS文件中搜索所有源(不仅是“外部”源——每个网络请求都需要CSP批准)
- 针对找到的每个源,追溯至源头:
- 如果来自常量 → 通用(开发和生产环境相同)
- 如果来自环境变量或条件逻辑 → 记录其机制并确定开发和生产环境的值
- 检查可能发起自有请求的第三方库(分析工具、错误追踪工具等)
记录你的调查结果为三个列表,并注明每个源是通用、仅开发环境还是仅生产环境:
- resourceDomains:提供图片、字体、样式、脚本的源
- connectDomains:用于API/fetch请求的源
- frameDomains:用于嵌套iframe的源
如果未找到任何源,应用可能无需自定义CSP域。
CORS Configuration
CORS配置
MCP clients make cross-origin requests. If using Express, handles this.
app.use(cors())For raw HTTP servers, configure standard CORS and additionally:
- Allow headers: ,
mcp-session-id,mcp-protocol-versionlast-event-id - Expose headers:
mcp-session-id
MCP客户端会发起跨域请求。如果使用Express,可处理此问题。
app.use(cors())对于原生HTTP服务器,除配置标准CORS外,还需:
- 允许的请求头:、
mcp-session-id、mcp-protocol-versionlast-event-id - 暴露的响应头:
mcp-session-id
Key Conceptual Changes
核心概念变化
Server-Side
服务器端
Use and helpers instead of raw / . These helpers handle the MCP Apps metadata format automatically.
registerAppTool()registerAppResource()server.registerTool()server.registerResource()See for server-side mapping tables.
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md使用和辅助方法,而非原生的 / 。这些辅助方法会自动处理MCP Apps的元数据格式。
registerAppTool()registerAppResource()server.registerTool()server.registerResource()查看获取服务器端映射表。
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.mdClient-Side
客户端
The fundamental paradigm shift: OpenAI uses a synchronous global object (, ) that's pre-populated before your code runs. MCP Apps uses an instance with async event handlers.
window.openai.toolInputwindow.openai.themeAppKey differences:
- Create an instance and register handlers (
App,ontoolinput,ontoolresult) before callingonhostcontextchanged. (Events may fire immediately after connection, so handlers must be registered first.)connect() - Access tool data via handlers: for
app.ontoolinput,window.openai.toolInputforapp.ontoolresult.window.openai.toolOutput - Access host environment (theme, locale, etc.) via .
app.getHostContext()
For React apps, the hook manages this lifecycle automatically—see for the pattern.
useAppbasic-server-react/See for client-side mapping tables.
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md核心范式转变:OpenAI使用同步全局对象(、),会在代码运行前预填充。而MCP Apps使用带有异步事件处理器的实例。
window.openai.toolInputwindow.openai.themeApp主要差异:
- 在调用前,创建
connect()实例并注册处理器(App、ontoolinput、ontoolresult)。(连接后事件可能立即触发,因此必须先注册处理器。)onhostcontextchanged - 通过处理器访问工具数据:对应
app.ontoolinput,window.openai.toolInput对应app.ontoolresult。window.openai.toolOutput - 通过访问宿主环境(主题、区域设置等)。
app.getHostContext()
对于React应用,钩子会自动管理此生命周期——可查看中的实现模式。
useAppbasic-server-react/查看获取客户端映射表。
/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.mdFeatures Not Yet Available in MCP Apps
MCP Apps暂不支持的功能
These OpenAI features don't have MCP equivalents yet:
Server-side:
| OpenAI Feature | Status/Workaround |
|---|---|
| Progress indicators not yet available |
| Use |
Client-side:
| OpenAI Feature | Status/Workaround |
|---|---|
| Use |
| File operations not yet available |
| Modal management not yet available |
| Not yet available |
以下OpenAI功能目前无MCP等效替代方案:
服务器端:
| OpenAI功能 | 状态/替代方案 |
|---|---|
| 进度指示器暂不支持 |
| 使用 |
客户端:
| OpenAI功能 | 状态/替代方案 |
|---|---|
| 使用 |
| 文件操作暂不支持 |
| 模态框管理暂不支持 |
| 暂不支持 |
Before Finishing
完成前检查
Slow down and carefully follow each item in this checklist:
-
Search for and migrate any remaining server-side OpenAI patterns:
Pattern Indicates "openai/Old metadata keys → _meta.ui.*text/html+skybridgeOld MIME type → constantRESOURCE_MIME_TYPEtext/html;profile=mcp-appNew MIME type, but prefer constantRESOURCE_MIME_TYPEor_domains"_domains:snake_case CSP → camelCase ( →connect_domains)connectDomains -
Search for and migrate any remaining client-side OpenAI patterns:
Pattern Indicates window.openai.toolInputOld global → inparams.argumentshandlerontoolinputwindow.openai.toolOutputOld global → inparams.structuredContentontoolresultwindow.openaiOld global API → instance methodsApp -
For each origin from your CSP investigation, show where it appears in theCSP config. Every origin from the CSP investigation (universal, dev-only, prod-only) must be included in the CSP config—MCP Apps HTML runs in a sandboxed iframe with no same-origin server. If an origin was not included in the CSP config, add it now.
registerAppResource() -
For each conditional (dev-only, prod-only) origin from your CSP investigation, show the code where the same configuration setting (env var, config file, etc.) controls both the runtime URL and the CSP entry. If the CSP has a hardcoded origin that should be conditional, fix it now—the app must be production-ready.
放慢节奏,仔细完成以下清单中的每一项:
-
搜索并迁移所有剩余的服务器端OpenAI模式:
模式 说明 "openai/旧元数据键 → 替换为 _meta.ui.*text/html+skybridge旧MIME类型 → 使用 常量RESOURCE_MIME_TYPEtext/html;profile=mcp-app新MIME类型,但建议使用 常量RESOURCE_MIME_TYPE或_domains"_domains:蛇形命名法CSP → 驼峰命名法( →connect_domains)connectDomains -
搜索并迁移所有剩余的客户端OpenAI模式:
模式 说明 window.openai.toolInput旧全局对象 → 使用 处理器中的ontoolinputparams.argumentswindow.openai.toolOutput旧全局对象 → 使用 处理器中的ontoolresultparams.structuredContentwindow.openai旧全局API → 使用 实例方法App -
针对CSP调查中发现的每个源,说明其在的CSP配置中的位置。CSP调查中发现的所有源(通用、仅开发、仅生产)都必须包含在CSP配置中——MCP Apps HTML在无同源服务器的沙箱化iframe中运行。如果某个源未包含在CSP配置中,请立即添加。
registerAppResource() -
针对CSP调查中发现的每个条件源(仅开发、仅生产),展示控制运行时URL和CSP条目的同一配置设置(环境变量、配置文件等)的代码。如果CSP中有应设为条件的硬编码源,请立即修复——应用必须具备生产就绪性。
Testing
测试
Using basic-host
使用basic-host进行测试
Test the migrated app with the basic-host example:
bash
undefined使用basic-host示例测试迁移后的应用:
bash
undefinedTerminal 1: Build and run your server
终端1:构建并运行你的服务器
npm run build && npm run serve
npm run build && npm run serve
Terminal 2: Run basic-host (from cloned repo)
终端2:运行basic-host(来自克隆的仓库)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
undefinedundefinedVerify Runtime Behavior
验证运行时行为
Once the app loads in basic-host, confirm:
- App loads without console errors
- handler fires with tool arguments
ontoolinput - handler fires with tool result
ontoolresult
当应用在basic-host中加载后,确认:
- 应用加载时无控制台错误
- 处理器随工具参数触发
ontoolinput - 处理器随工具结果触发
ontoolresult