MCP Apps vs OpenAI Apps SDK:附概念映射表的迁移完全手册
【免费下载链接】ext-appsOfficial repo for spec & SDK of MCP Apps protocol - standard for UIs embedded AI chatbots, served by MCP servers项目地址: https://gitcode.com/GitHub_Trending/ex/ext-apps
如果你正在使用 OpenAI Apps SDK 构建聊天机器人里的交互式 UI,本文将带你完成向MCP Apps的迁移。MCP Apps 是模型上下文协议(Model Context Protocol)的官方扩展(@modelcontextprotocol/ext-apps),让 MCP 服务器把图表、表单、仪表盘等交互式 UI 直接渲染进 Claude、ChatGPT、VS Code 等任意兼容的聊天客户端,实现"一次编写、处处运行"。下文提供完整的概念映射表、分步迁移流程和未支持功能的替代方案。
💡 完整映射参考:docs/migrate_from_openai_apps.md,迁移技能:plugins/mcp-apps/skills/migrate-oai-app/SKILL.md
为什么值得从 OpenAI Apps SDK 迁移到 MCP Apps?
OpenAI Apps SDK 让 UI 只运行在 ChatGPT 生态里,而 MCP Apps 将"工具 + 交互界面"标准化为开放协议:
- 跨客户端移植:同一套代码可在 Claude、ChatGPT、VS Code、Goose、Postman 等所有兼容宿主中渲染
- 安全模型统一:沙箱 iframe + 声明式 CSP,通信全程可审计
- 渐进增强:不支持 UI 的宿主自动降级为纯文本工具,服务器不需要维护多套适配器
- 功能更强:新增设备权限声明、流式工具参数、自动尺寸上报等 OpenAI SDK 没有的能力
交互式界面就是 MCP Apps 的核心价值,比如下面这个预算分配器,用户可以直接拖动滑块重新分配各部门预算:
架构细节可阅读 docs/overview.md,协议规范见 specification/2026-01-26/apps.mdx。
核心概念映射:30秒看懂两套 SDK 的差异
迁移的本质可以概括为一句话:OpenAI 用"隐式全局对象 + 扁平元数据",MCP Apps 用"显式 App 实例 + 嵌套元数据"。
| 维度 | OpenAI Apps SDK | MCP Apps SDK |
|---|---|---|
| 客户端入口 | 隐式全局window.openai | 显式实例new App(...)+await app.connect() |
| 工具注册 | server.registerTool()+openai/...元数据 | registerAppTool()+_meta.ui.*元数据 |
| UI 资源注册 | server.registerResource() | registerAppResource() |
| UI 资源 MIME 类型 | text/html+skybridge | text/html;profile=mcp-app |
| 数据获取方式 | 加载时属性预填充(同步读取) | 异步事件回调(ontoolinput/ontoolresult) |
服务端迁移:元数据与注册函数对照表
工具元数据映射
| OpenAI | MCP Apps | 说明 |
|---|---|---|
_meta["openai/outputTemplate"] | _meta.ui.resourceUri | 指向 UI 资源的 URI |
_meta["openai/widgetAccessible"](布尔值) | _meta.ui.visibility(字符串数组) | true/false→ 数组中包含/排除"app" |
_meta["openai/visibility"](字符串) | _meta.ui.visibility(字符串数组) | "public"/"private"→ 包含/排除"model" |
_meta["openai/toolInvocation/invoking"] | — | 尚未实现 |
_meta["openai/toolInvocation/invoked"] | — | 尚未实现 |
资源元数据与 CSP 字段映射
| OpenAI | MCP Apps | 说明 |
|---|---|---|
_meta["openai/widgetCSP"] | _meta.ui.csp | 字段名从 snake_case 改为 camelCase |
_meta["openai/widgetDomain"] | _meta.ui.domain | 专属沙箱源 |
resource_domains | resourceDomains | 静态资源来源 |
connect_domains | connectDomains | fetch/XHR/WebSocket 请求来源 |
frame_domains | frameDomains | 嵌套 iframe 来源 |
| — | baseUriDomains | MCP 新增:base-uri指令 |
| — | _meta.ui.permissions | MCP 新增:摄像头、麦克风、定位、剪贴板权限 |
⚠️易踩的坑:CSP 字段是驼峰命名(connect_domains→connectDomains),且每一个网络来源都必须声明,包括你自己托管 JS/CSS 的源(开发环境的localhost、生产环境的 CDN),漏写会静默失败。详见 docs/csp-cors.md。
RESOURCE_MIME_TYPE常量定义在 src/constants.ts,服务端辅助函数registerAppTool()/registerAppResource()实现于 src/server/index.ts。
客户端迁移:从 window.openai 到 App 实例
这是迁移中概念变化最大的一步:从"读属性"变成"注册事件"。所有事件处理器必须在connect()之前注册,因为连接建立后事件可能立即触发。
| 场景 | OpenAI 写法 | MCP Apps 写法 |
|---|---|---|
| 主题/语言/展示模式 | window.openai.theme | app.getHostContext()?.theme |
| 工具入参 | window.openai.toolInput | app.ontoolinput = (params) => { ... } |
| 工具结果 | window.openai.toolOutput | app.ontoolresult = (params) => { ... } |
| 调用其他工具 | window.openai.callTool(name, args) | app.callServerTool({ name, arguments: args }) |
| 发送聊天消息 | window.openai.sendFollowUpMessage({ prompt }) | app.sendMessage({ role: "user", content: [...] }) |
| 打开外部链接 | window.openai.openExternal({ href }) | app.openLink({ url })(注意参数名变化) |
| 上报高度 | window.openai.notifyIntrinsicHeight(h) | app.sendSizeChanged({ width, height }),默认自动上报 |
| 上下文变化 | addEventListener("openai:set_globals") | app.onhostcontextchanged = (ctx) => {...} |
| 结构化日志 | console.log(...) | app.sendLog({ level, data }) |
App类的完整实现见 src/app.ts。React 项目无需手写生命周期——useApp钩子会自动管理连接与事件,参考 examples/basic-server-react/src/mcp-app.tsx:
四步完成迁移的最快流程
第 1 步:安装 SDK
npm install -S @modelcontextprotocol/ext-apps @modelcontextprotocol/server@2.0.0-beta.5 @modelcontextprotocol/core@2.0.0-beta.5 zod@^4.2.0第 2 步:替换服务端注册方式— 把server.registerTool()/server.registerResource()换成registerAppTool()/registerAppResource(),元数据从openai/...扁平键改写到_meta.ui.*,MIME 类型改用RESOURCE_MIME_TYPE常量。
第 3 步:改写客户端入口— 全局搜索window.openai,按上一节对照表替换为App实例方法;把toolInput/toolOutput的同步读取改为ontoolinput/ontoolresult回调,并在await app.connect()之前完成注册。
第 4 步:全面排查遗留模式— 搜索以下关键字确认没有遗漏:"openai/(旧元数据键)、text/html+skybridge(旧 MIME)、_domains"(snake_case CSP)、window.openai(旧全局对象)。
官方入门示例 examples/quickstart/ 演示了"工具 + UI 资源"的核心模式,工具输入与结果通过通知实时传递给界面:
尚未支持的功能与替代方案
迁移前请先确认你依赖的功能是否可用,这些 OpenAI 能力目前尚无 MCP 对应实现:
| 缺失功能 | 替代方案 |
|---|---|
widgetState/setWidgetState()状态持久化 | 使用localStorage或服务端状态 |
uploadFile()/getFileDownloadUrl()文件操作 | 暂不可用,待协议更新 |
requestModal()/requestClose()弹窗管理 | 暂不可用 |
toolInvocation/invoking进度提示 | 暂不可用 |
widgetDescription | 用app.updateModelContext()提供动态上下文 |
好消息是:渐进增强机制保证不支持 UI 的宿主仍会收到纯文本结果,迁移不会让你的服务器"失效"。
让 AI Agent 帮你自动完成迁移
官方仓库内置了 migrate-oai-app 迁移技能,AI 编码智能体(Claude Code、VS Code 等)安装后可自动执行整套流程:克隆参考代码、按映射表改写服务端与客户端代码、排查 CSP 来源、并用内置宿主验证运行结果。技能总览见 docs/agent-skills.md。
类似的真实案例还能做什么?下图是一个 SaaS 业务预测器,参数滑块调整会实时驱动 12 个月 MRR 曲线重算,全部交互发生在聊天界面内:
本地验证:用 basic-host 跑通迁移结果
无需连接真实聊天客户端,仓库自带的参考宿主 examples/basic-host/ 即可验证迁移后的应用。克隆仓库(git clone https://gitcode.com/GitHub_Trending/ex/ext-apps)后执行npm install && npm start,打开http://localhost:8080/,即可在宿主中调用你的工具、检查 UI 渲染、事件回调与主题适配。
迁移自查清单:
- ✅ 全局搜索确认无
window.openai、openai/、skybridge残留 - ✅ CSP 中声明了开发/生产环境的所有来源
- ✅ 事件处理器在
connect()之前注册 - ✅ 在 basic-host 中:无控制台报错、
ontoolinput与ontoolresult均正常触发
总结:MCP Apps 迁移的核心就是三张表——服务端元数据表、客户端 API 表、CSP 字段表。跟着 docs/migrate_from_openai_apps.md 的对照关系逐项替换,再让 AI Agent 兜底排查,大多数应用都能在半天内完成从 OpenAI Apps SDK 到开放标准 MCP Apps 的平滑迁移。
【免费下载链接】ext-appsOfficial repo for spec & SDK of MCP Apps protocol - standard for UIs embedded AI chatbots, served by MCP servers项目地址: https://gitcode.com/GitHub_Trending/ex/ext-apps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考