关于 migrate-oai-app
面向将现有 OpenAI Apps SDK 应用迁移到 MCP Apps SDK 的开发者,说明服务器端和客户端的改造方式。还包括 CSP 来源排查、功能差异和运行验证。
主要功能
- 01映射服务器端注册方式
- 02改用 App 事件处理器
- 03调查并配置 CSP 来源
- 04说明暂不支持的功能
- 05通过 basic-host 验证运行
适用场景
- 01迁移现有 OpenAI Apps
- 02替换客户端全局 API
- 03检查嵌入式界面的网络来源
MCP 相关
指导将 OpenAI Apps 迁移到 MCP Apps SDK,并使用 MCP 的工具和资源注册方式及 App 事件生命周期。迁移后的界面作为 MCP 资源在沙盒 iframe 中运行。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ modelcontextprotocol/ ext-apps --skill migrate-oai-app安装后在 Claude Code 中输入/migrate-oai-app确认已加载。
详细介绍
将 OpenAI App 迁移到 MCP
将现有的 OpenAI Apps SDK 应用迁移到 MCP Apps SDK(@modelcontextprotocol/ext-apps)。MCP Apps SDK 为对话客户端中的交互式 UI 提供标准化的开放协议。
最佳实践
- 使用包管理器添加依赖项(例如
npm install、pnpm add、yarn add),而不是手动填写版本号。这样包管理器就能解析最新的兼容版本。切勿凭记忆指定版本号。 - 提前添加一个最终待办事项,措辞必须完全如下:“重新阅读此技能中的‘完成前’检查清单,并逐项处理每个复选框;在将此待办事项标记为完成之前,说明你对每项所做的处理。”
获取参考代码
克隆 SDK 仓库,以获取完整的迁移文档和可运行示例:
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
迁移参考指南
阅读迁移参考指南中的“迁移前/迁移后”对照表:/tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md
API 参考(源文件)
直接阅读 /tmp/mcp-ext-apps/src/* 中的 JSDoc 文档:
| 文件 | 内容 |
|---|---|
src/app.ts | App 类、处理程序、生命周期 |
src/server/index.ts | registerAppTool、registerAppResource |
src/spec.types.ts | 类型定义 |
src/react/useApp.tsx | 供 React 应用使用的 useApp Hook |
src/react/use*.ts* | 供 React 应用使用的其他 use* Hook |
前端框架示例
请参阅 /tmp/mcp-ext-apps/examples/basic-server-{framework}/,查看按前端框架分类的 SDK 基本用法示例:
| 模板 | 关键文件 |
|---|---|
basic-server-vanillajs/ | server.ts、src/mcp-app.ts、mcp-app.html |
basic-server-react/ | server.ts、src/mcp-app.tsx(使用 useApp Hook) |
basic-server-vue/ | server.ts、src/App.vue |
basic-server-svelte/ | server.ts、src/App.svelte |
basic-server-preact/ | server.ts、src/mcp-app.tsx |
basic-server-solid/ | server.ts、src/mcp-app.tsx |
CSP 调查
MCP Apps HTML 作为 MCP 资源提供,而非网页,并在没有同源服务的沙箱 iframe 中运行。每个源都必须在 CSP 中声明,包括提供 JS/CSS bundle 的源(开发环境中的 localhost,生产环境中的 CDN)。缺少源时不会显示错误。
编写任何迁移代码之前,先构建应用并调查它引用的所有源:
- 使用现有构建命令构建应用
- 搜索生成的 HTML、CSS 和 JS,查找所有源(不只是“外部”源——每个网络请求都需要 CSP 授权)
- 对找到的每个源,追溯其来源:
- 如果来自常量 → 通用(开发和生产环境相同)
- 如果来自环境变量或条件语句 → 记录其机制,并确定开发和生产环境中的值
- 检查第三方库是否会自行发起请求(例如分析、错误跟踪等)
记录调查结果,分为以下三个列表,并注明每个源是通用、仅开发环境使用还是仅生产环境使用:
- resourceDomains:提供图片、字体、样式和脚本的源
- connectDomains:用于 API/fetch 请求的源
- frameDomains:用于嵌套 iframe 的源
如果没有找到任何源,应用可能不需要自定义 CSP 域名。
CORS 配置
MCP 客户端会发起跨域请求。如果使用 Express,app.use(cors()) 即可处理。
对于原始 HTTP 服务,还需配置标准 CORS,并额外执行以下设置:
- 允许的标头:
mcp-session-id、mcp-protocol-version、last-event-id - 暴露的标头:
mcp-session-id
关键概念变更
服务端
使用 registerAppTool() 和 registerAppResource() 辅助函数,而不是原始的 server.registerTool() / server.registerResource()。这些辅助函数会自动处理 MCP Apps 元数据格式。
请参阅 /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md 中的服务端对照表。
客户端
根本性的范式转变:OpenAI 使用一个同步的全局对象(window.openai.toolInput、window.openai.theme),它会在代码运行前预先填充。MCP Apps 使用带有异步事件处理程序的 App 实例。
主要区别:
- 创建
App实例并注册处理程序(ontoolinput、ontoolresult、onhostcontextchanged),然后再调用connect()。(事件可能会在连接后立即触发,因此必须先注册处理程序。) - 通过处理程序访问工具数据:
app.ontoolinput对应window.openai.toolInput,app.ontoolresult对应window.openai.toolOutput。 - 通过
app.getHostContext()访问主机环境(主题、区域设置等)。
对于 React 应用,useApp hook 会自动管理此生命周期——模式请参见 basic-server-react/。
客户端映射表请参见 /tmp/mcp-ext-apps/docs/migrate_from_openai_apps.md。
MCP Apps 尚不支持的功能
以下 OpenAI 功能目前还没有 MCP 对应功能:
服务端:
| OpenAI 功能 | 状态/替代方案 |
|---|---|
_meta["openai/toolInvocation/invoking"] / _meta["openai/toolInvocation/invoked"] | 暂不支持进度指示器 |
_meta["openai/widgetDescription"] | 使用 app.updateModelContext() 设置动态上下文 |
客户端:
| OpenAI 功能 | 状态/替代方案 |
|---|---|
window.openai.widgetState / setWidgetState() | 使用 localStorage 或服务端状态 |
window.openai.uploadFile() / getFileDownloadUrl() | 暂不支持文件操作 |
window.openai.requestModal() / requestClose() | 暂不支持模态框管理 |
window.openai.view | 暂不可用 |
完成前
请放慢速度,仔细完成以下清单中的每一项:
-
搜索并迁移所有剩余的服务端 OpenAI 模式:
模式 表示 "openai/旧元数据键 → _meta.ui.*text/html+skybridge旧 MIME 类型 → RESOURCE_MIME_TYPE常量text/html;profile=mcp-app新 MIME 类型,但优先使用 RESOURCE_MIME_TYPE常量_domains"或_domains:snake_case CSP → camelCase( connect_domains→connectDomains) -
搜索并迁移所有剩余的客户端 OpenAI 模式:
模式 表示 window.openai.toolInput旧全局对象 → ontoolinput处理程序中的params.argumentswindow.openai.toolOutput旧全局对象 → ontoolresult中的params.structuredContentwindow.openai旧全局 API → App实例方法 -
对于 CSP 调查中的每个源,指出它在
registerAppResource()CSP 配置中的位置。CSP 调查中的每个源(通用、仅开发环境、仅生产环境)都必须包含在 CSP 配置中——MCP Apps HTML 在沙盒化 iframe 中运行,没有同源服务。如果某个源未包含在 CSP 配置中,请立即添加。 -
对于 CSP 调查中的每个条件性源(仅开发环境、仅生产环境),指出控制运行时 URL 和 CSP 条目的同一配置设置(环境变量、配置文件等)所在的代码。如果 CSP 中有应设为条件性的硬编码源,请立即修正——应用必须达到可投入生产的状态。
测试
使用 basic-host
使用 basic-host 示例测试迁移后的应用:
# Terminal 1: Build and run your server
npm run build && npm run serve
# Terminal 2: Run basic-host (from cloned repo)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# Open http://localhost:8080
验证运行时行为
应用在 basic-host 中加载后,确认:
- 应用加载时没有控制台错误
ontoolinput处理程序会携带工具参数触发ontoolresult处理程序会携带工具结果触发