概述
ChatGPT 支持用于嵌入式应用 UI 的 MCP Apps 开放标准。
MCP Apps UI 在 iframe 内运行,并通过标准桥接(基于 postMessage 的 ui/* JSON-RPC)与宿主进行通信。ChatGPT 实现了这一相同的 iframe 与桥接模型,因此您可以构建一次 UI,并在 ChatGPT 及其他支持 MCP Apps 的宿主中运行。
现有的 Apps SDK API 继续受支持,新的实验性功能将首先在 Apps SDK 中发布。OpenAI 协助塑造了基于 ChatGPT Apps 的 MCP Apps 标准,新功能在经过形态和功能验证后会纳入 MCP 规范中。
默认使用 MCP Apps 标准键(keys)和桥接进行构建。当需要 ChatGPT 特有功能时,请使用 window.openai。
推荐方案
对于新应用(以及现有应用内的新 UI 界面),请从 MCP Apps 标准入手
- 声明您的 UI:使用
_meta.ui.resourceUri。 - 使用标准宿主桥接(基于
postMessage的ui/*JSON-RPC)进行初始化、通知和宿主交互。
可选
- 分层添加 ChatGPT 扩展:仅当需要共享规范未涵盖的功能时,通过
window.openai进行添加。
MCP Apps 宿主桥接 (ui/*)
MCP Apps 定义了一个标准的 iframe 桥接
- 传输:基于
window.postMessage的 JSON-RPC 2.0 消息 - 命名空间:用于 UI 与宿主交互的
ui/*方法和通知 - 工具调用:使用 MCP 工具界面(例如
tools/call),而不是宿主特定的 UI 全局变量
这与 Apps SDK 的关系
Apps SDK 是构建和分发 ChatGPT Apps 的受支持方式。ChatGPT 同时实现了 MCP Apps UI 标准,因此您的 UI 可以跨支持 MCP Apps 的宿主运行。
在实践中
- 当存在等效项时,使用 MCP Apps 标准键和桥接方法(
_meta.ui.resourceUri,ui/*)。 - 仅在需要 ChatGPT 特有功能时使用 OpenAI 扩展。
这类似于 Web 平台:厂商特定的 API 有助于尽早发布,但一旦标准存在,文档应优先引导使用标准格式。这是为了实现可移植性,而非弃用。
通过 window.openai 提供的可选 ChatGPT 扩展
某些功能是 ChatGPT 特有的。当使用它们时,请将其视为可选扩展,它们在 ChatGPT 中增强了功能,且不会妨碍您的 UI 在其他 MCP Apps 宿主中运行。
示例包括
- 即时结账 (
window.openai.requestCheckout) - 文件处理 (
window.openai.uploadFile,window.openai.selectFiles,window.openai.getFileDownloadUrl) - 宿主模态框 (
window.openai.requestModal)
迁移与映射指南
本节将常见的 Apps SDK 模式映射为对应的 MCP Apps 标准等效项。
工具元数据
| 目标 | MCP Apps 标准 | ChatGPT 兼容性别名 |
|---|---|---|
| 将工具链接到 UI 资源 | _meta.ui.resourceUri | _meta["openai/outputTemplate"] |
宿主桥接
| 目标 | MCP Apps 标准 | ChatGPT 扩展(可选) |
|---|---|---|
| 接收工具输入 | ui/initialize + ui/notifications/tool-input | window.openai.toolInput |
| 接收工具结果 | ui/notifications/tool-result | window.openai.toolOutput |
| 从 UI 调用工具 | tools/call | window.openai.callTool |
| 发送后续消息 | ui/message | window.openai.sendFollowUpMessage |
| 更新模型可见的 UI 上下文 | ui/update-model-context | window.openai.setWidgetState |
围绕 MCP Apps 标准进行构建以实现可移植性,然后在需要提升 ChatGPT 体验的地方分层添加 ChatGPT 扩展。
扩展最佳实践
- 功能检测:在调用扩展之前进行检测。
- 优雅降级:当扩展不可用时进行优雅降级。
const openai = typeof window !== "undefined" ? window.openai : undefined;
if (openai?.requestModal) {
await openai.requestModal({
/* ... */
});
} else {
// Fallback behavior for hosts without this extension.
}