全新操作系统?ChatGPT 应用与 Apps SDK(基于 MCP):开启新平台

作者:Boxu Li at Macaron


引言:

ChatGPT 应用现在允许第三方开发者构建在聊天界面内运行的交互式迷你应用程序。这些应用不会将用户重定向到网站或移动应用,而是在对话中运行,利用模型的推理能力来驱动操作。早期合作伙伴如 Canva、Coursera、Expedia 和 Zillow 展示了用户如何在不离开 ChatGPT 的情况下请求播放列表、设计海报或搜索房地产[1]。新的 Apps SDK 基于 **模型上下文协议(MCP)**构建,这是一个开放标准,让模型能够与外部工具和用户界面交互[2]。本博客深入探讨基于 MCP 的应用架构,解释 SDK 的功能,逐步指导如何构建应用,探索用户如何发现和使用应用,并讨论隐私和安全考虑。在整个过程中,我们引用官方文档和权威新闻报道,确保分析基于可信来源。

理解模型上下文协议(MCP)

开放标准的重要性

模型上下文协议是 Apps SDK 的基础。根据开发者文档,每个 Apps SDK 集成都使用 MCP 服务器来暴露工具、处理身份验证,并打包在 ChatGPT 中渲染的结构化数据和 HTML[2]。MCP 是一个开放标准——任何人都可以用任何语言实现服务器,并连接 GPT-4 或 Codex 等模型。开源特性意味着没有供应商锁定;同一个应用理论上可以在任何实现该协议的 AI 平台上运行。这种开放性鼓励社区贡献,并培育类似于早期网络的生态系统,其中 HTTP 等标准实现了可互操作的网站。

服务器、工具和资源

MCP 服务器暴露一个或多个工具。工具定义了模型可能调用的操作,如"创建看板"、"搜索房屋"或"生成播放列表"。每个工具由机器名称、人性化标题和告诉模型接受什么参数的JSON 模式来描述。当 ChatGPT 决定应该调用工具时,它会向服务器发送结构化调用。服务器执行逻辑——无论是查询 API、执行计算还是与数据库交互——然后返回工具响应。此响应包括三个字段:

  • structuredContent – 模型可见的描述当前状态的数据。例如,看板可能包括列和任务的数组[3]

  • content – 助手向用户回应的可选文本。这可以总结结果或指导用户。

  • _meta – 模型不可见的隐藏元数据。开发者使用此字段存储 ID 或 UI 组件中使用的列表。例如,看板示例在 _meta 中使用 tasksById 映射来维护任务详情,而不向模型暴露[4]

工具还可以通过引用 ui:// URL 来引用资源,如 HTML 模板或图像。服务器在启动时注册这些资源。文档警告说,由于资源被 OpenAI 的基础设施缓存,开发者应该通过在文件名中包含构建哈希来对它们进行版本控制[5]。否则,用户在部署后可能会看到过时的 UI。

结构化内容与元数据

structuredContent 和 _meta 之间的区别至关重要。根据文档,structuredContent 对模型可见,用于水合 UI 组件;_meta 对模型隐藏,可能包含 UI 的额外数据,如下拉菜单的列表[3]。通过分离可见和隐藏数据,开发者可以保护敏感信息不被模型看到,同时仍能渲染丰富的界面。这种设计也鼓励最小化数据共享;只暴露完成任务所需的内容,符合隐私原则。

身份验证和会话

当用户首次调用应用时,服务器可能需要对其进行身份验证。Apps SDK 支持 OAuth 2.1 流程;开发者指定作用域并将用户重定向到身份提供商。一旦用户授予同意,应用获得令牌并可以访问用户的数据。服务器的工作是管理会话状态,通常通过将令牌存储在按用户 ChatGPT 账户键控的数据库中。这确保后续的工具调用可以重用会话,而无需再次提示用户。

安全原则

OpenAI 强调最小权限明确用户同意深度防御[6]。应用应该只请求所需的最小权限,用户必须明确授权数据共享;模型本身永远不应该猜测凭据。数据保留是有限的:结构化内容仅在用户提示活跃时保留,日志在与开发者共享之前会被编辑[6]。应用组件的网络访问受到内容安全策略的限制;iframe 无法访问任意浏览器 API,所有 HTTP 请求必须来自服务器而不是客户端[7]。这防止了跨站脚本和令牌泄露。

Apps SDK:在 ChatGPT 中构建真实应用

开发者体验

Apps SDK 将 MCP 包装在惯用的客户端库(目前是 Python 和 TypeScript)和脚手架工具中。当你创建应用时,你定义工具、注册 UI 模板并实现服务器逻辑。服务器可以在你自己的基础设施上运行,使用任何框架(FastAPI、Express 等),但它必须实现 MCP 端点。OpenAI 提供开发服务器和MCP 检查器来本地测试调用。

开发者设计逻辑和用户界面。UI 通常用 React 编写并编译成静态资源。它们在 ChatGPT 中的沙盒 iframe 内提供。在此 iframe 内,开发者可以访问全局 window.openai 对象来与主机交互。根据构建自定义 UX指南,此 API 提供:

  • 全局变量 – displayMode、maxHeight、theme 和 locale 告知组件布局和样式[8]

  • 工具载荷 – toolInput、toolOutput 和 widgetState 允许读取参数、结果和跨渲染的持久状态[8]

  • 操作 – setWidgetState() 保存跨消息持久的状态;callTool() 触发服务器操作;sendFollowupTurn() 向模型发送后续提示;requestDisplayMode() 请求全屏或画中画[8]

  • 事件 – 组件可以订阅 openai:set_globals 当主机更新布局或主题时,以及 openai:tool_response 当工具调用解析时[8]

这些 API 让开发者构建丰富的交互式组件,与模型的推理保持同步。例如,如果用户在看板中将任务拖拽到新列,组件可以发送 callTool 来更新服务器,持久化新状态,然后返回新的 structuredContent。同时模型只看到高级看板状态;UI 处理拖拽等细节。

注册工具和模板

在服务器代码中,你注册一个工具及其模板。例如,在 TypeScript 服务器中,你可能这样写:

import { Tool, StructuredToolResponse } from "@openai/apps";

// Register UI template
server.registerResource("ui://kanban-board/abc123", buildHtml());

// Define tool schema
const createBoard: Tool = {
  name: "createKanbanBoard",
  description: "Create a new kanban board with given tasks and columns",
  inputSchema: z.object({
    title: z.string(),
    columns: z.array(z.object({ name: z.string() })),
    tasks: z.array(z.object({ name: z.string(), columnIndex: z.number() }))
  }),
  async execute(input, ctx): Promise<StructuredToolResponse> {
    // compute board state
    const columns = input.columns.map((col, i) => ({
      id: i,
      title: col.name,
      taskIds: input.tasks.filter(t => t.columnIndex === i).map((_t, idx) => idx)
    }));
    const tasksById = input.tasks.map((task, id) => ({ id, name: task.name }));
    return {
      content: `Created board '${input.title}'`,
      structuredContent: { title: input.title, columns },
      _meta: { tasksById, uiTemplate: "ui://kanban-board/abc123" }
    };
  }
};

_meta 字段包含用于隐藏元数据的 tasksById 和引用已注册 HTML 的 uiTemplate。当 ChatGPT 收到此响应时,它将使用结构化内容渲染模板。组件中的 window.openai.toolOutput 对象然后可以读取看板数据并显示它。

版本控制和缓存

由于 UI 模板等资源在 OpenAI 的服务器上被缓存,开发者应该在 ui:// 标识符中包含唯一哈希或版本。文档警告说,如果你部署新版本而不更新路径,由于缓存,用户可能继续看到旧的 UI[5]。最佳实践是在 URL 中嵌入提交 SHA 或构建 ID。这确保每次部署都会产生新的资源。

持久化状态和后续操作

组件通常需要持久化状态。例如,播放列表应用可能让用户收藏歌曲;这些收藏应该在用户问另一个问题时仍然保留。setWidgetState() 方法在 structuredContent 之外存储数据,并在轮次间持久化[8]。模型看不到此状态,确保隐私。

有时应用需要向用户询问澄清问题。sendFollowupTurn() 方法允许组件向 ChatGPT 发送新提示,然后会出现在转录中,就像模型问了问题一样[8]。这对多步骤工作流很有用:例如,旅行预订应用在用户选择酒店后可能会问"你要住几晚?"

构建你的第一个应用:分步指南

在本节中,我们将构建一个简单的任务跟踪器应用,演示 Apps SDK 的核心概念。该应用将让用户创建任务并将它们组织到类别中。我们选择这个例子是因为它是通用的、易于扩展的,并展示了结构化内容、元数据、自定义 UI 和工具调用。

  1. 设置 MCP 服务器

首先安装 TypeScript SDK 和脚手架工具:

npm install -g @openai/apps-generator
apps init task-tracker
cd task-tracker
npm install

此命令搭建一个包含服务器、React 前端和构建脚本的项目。服务器使用 Express 和 @openai/apps 库。运行 npm run dev 启动开发服务器;项目包含一个MCP 检查器,在浏览器中打开并模拟 ChatGPT 调用你的应用。

  • 定义工具

打开 src/server.ts 并定义一个名为 createTasks 的工具。该工具接受任务数组并返回按类别分组的结构化内容。它还在 content 字段中提供摘要。

import { Tool, StructuredToolResponse } from "@openai/apps";

export const createTasks: Tool = {
  name: "createTasks",
  description: "Create a list of tasks grouped by category",
  inputSchema: z.object({ tasks: z.array(z.object({ name: z.string(), category: z.string() })) }),
  async execute({ tasks }): Promise<StructuredToolResponse> {
    const categories = Array.from(new Set(tasks.map(t => t.category)));
    const grouped = categories.map(category => ({
      name: category,
      taskIds: tasks.filter(t => t.category === category).map((_, i) => i)
    }));
    const tasksById = tasks.map((task, id) => ({ id, name: task.name, category: task.category }));
    return {
      content: `Created ${tasks.length} tasks in ${categories.length} categories`,
      structuredContent: { categories: grouped },
      _meta: { tasksById, uiTemplate: "ui://task-tracker/1.0.0" }
    };
  }
};

在使用之前注册模板:

server.registerResource("ui://task-tracker/1.0.0", fs.readFileSync(path.join(__dirname, "../dist/index.html"), "utf8"));
server.registerTool(createTasks);
  • 构建自定义 UI

接下来打开 src/frontend/App.tsx。这个 React 组件将读取 structuredContent 并显示类别和任务。它还将允许用户将任务标记为完成,并使用 setWidgetState 持久化该状态。

import { useEffect, useState } from "react";

declare global {
  interface Window {
    openai: any;
  }
}

export default function App() {
  const [complete, setComplete] = useState<{ [id: string]: boolean }>(() => window.openai.widgetState?.complete || {});
  const output = window.openai.toolOutput;
  const tasksById = output?._meta?.tasksById || [];
  const categories = output?.structuredContent?.categories || [];

  // persist completion state
  useEffect(() => {
    window.openai.setWidgetState({ complete });
  }, [complete]);

  return (
    <div className="task-tracker">
      {categories.map((cat: any, ci: number) => (
        <div key={ci} className="category">
          <h3>{cat.name}</h3>
          <ul>
            {cat.taskIds.map((tid: number) => (
              <li key={tid}>
                <label>
                  <input type="checkbox" checked={complete[tid]} onChange={() => setComplete(prev => ({ ...prev, [tid]: !prev[tid] }))} />
                  {tasksById[tid].name}
                </label>
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

此组件使用 window.openai.toolOutput 访问 structuredContent 和 _meta 字段。它将完成状态存储在 widgetState 中,这样即使当用户继续对话时,勾选复选框也会持久化。在后续的工具调用中,组件可以获取新任务或更新现有任务。这演示了如何将模型推理与客户端交互相结合。

  • 测试和迭代

再次运行 npm run dev 并打开 MCP 检查器。在提示区域中,输入:

@task‑tracker create a list of tasks: buy milk in shopping, finish report in work, call mom in personal

检查器将显示结构化内容并渲染任务列表 UI。你可以勾选任务;状态在轮次间持久化。然后你可以问 ChatGPT:"稍后提醒我的任务。"因为模型保留上下文,它可以再次调用工具,显示 UI 并总结你的进度。

用户如何发现和使用应用

命名提及和对话内发现

ChatGPT 在认为应用可以帮助用户时会展示应用。有两种主要的发现模式。命名提及发生在用户在提示开头明确提及应用名称时;在这种情况下,应用将自动展示[9]。例如,"@Spotify 创建锻炼播放列表"立即调用 Spotify 集成。用户必须将应用名称放在开头;否则助手可能将其视为对话的一部分。

对话内发现发生在模型推断应用可能基于上下文提供帮助时。文档解释说,模型评估对话上下文、先前的工具结果和用户链接的应用,以确定哪个应用可能相关[9]。例如,如果你在讨论旅行计划,ChatGPT 可能会建议 Expedia 应用来预订航班。算法使用工具描述和关键词等元数据来匹配对话与潜在操作[10]。开发者可以通过编写面向操作的描述和清晰的 UI 组件名称来提高可发现性。

目录和启动器

OpenAI 计划发布一个应用目录,用户可以浏览和发现新应用[10]。每个列表将包括应用名称、描述、支持的提示和任何入门说明。用户还可以通过聊天中的"+"按钮访问启动器;这显示基于上下文的可用应用菜单。这些入口点将帮助技术性较低的用户找到并启用应用,而无需记住名称。

入门和同意

用户首次激活应用时,ChatGPT 启动入门流程。模型要求用户连接他们的账户(如果需要)并解释应用需要什么数据。开发者指南强调应用必须尊重用户隐私、行为可预测并具有明确的政策[11]。用户必须明确授予或拒绝权限;没有静默数据访问。一旦连接,应用可以在后续交互中保持链接,但用户始终有能力断开连接并撤销权限。

隐私、安全和负责任的设计

可信应用的原则

OpenAI 的应用开发者指南定义了几个原则,以确保生态系统保持安全和可信。应用必须提供合法服务、有明确的隐私政策和数据保留做法,并遵守使用政策[11]。它们应该最小化数据收集,避免存储敏感个人信息,并在没有同意的情况下不共享用户数据[12]。应用必须行为可预测;它们不能操纵模型产生有害或误导性内容。

数据边界和最小化

指南强调应用应该只收集其功能必需的数据,不得请求或存储健康记录或政府 ID 等敏感数据[12]。发送给模型的结构化内容不应包含秘密;隐藏元数据不应存储用户令牌或私人详情。开发者必须为 OAuth 期间获得的任何令牌实施强加密和安全存储。服务器应在用户会话之间保持严格边界;一个用户的数据绝不能泄露到另一个用户的上下文中。

SDK 中的安全措施

安全和隐私指南概述了平台内置的防御机制。它强调最小权限和明确用户同意作为核心原则[6]。数据保留是有限的;开发者可访问的日志被编辑以删除个人身份信息,结构化内容仅在提示需要时保留[6]。iframe 内的网络访问受到内容安全策略的限制;外部获取必须通过服务器,防止未经授权的跨源请求[7]。身份验证使用行业标准 OAuth 流程和短期令牌。开发者需要实施安全审查、错误报告渠道和事件监控以保持操作准备状态[7]

公平性和适当性

应用必须适合广泛的受众。指南禁止提供长篇内容、复杂自动化或广告的应用[13]。例如,应用不应尝试提供 30 分钟的视频或在 ChatGPT 内复制整个社交网络。平台鼓励简洁的交互,补充对话流程。违规可能导致拒绝或移除。

机遇和考虑

开发者的新分发渠道

通过向第三方应用开放 ChatGPT,OpenAI 将自己定位为用户和服务之间的"意图层"。开发者现在可以通过聊天界面触达数百万用户,而无需构建单独的网站或移动应用。应用有潜力降低摩擦:用户只需在对话中提及服务,而不是下载应用或访问网站。这可能使工具访问民主化,为小开发者创造公平的竞争环境。

早期合作伙伴展示了可能性:用户可以观看 Coursera 讲座同时问 ChatGPT 问题;在 Canva 中设计海报;浏览 Expedia 旅行选项或 Zillow 房地产列表;生成 Spotify 播放列表;或用 Figma 绘制想法图表[14][13]。由于应用在聊天内运行,模型可以总结、分析和生成推荐,将静态内容转化为交互式课程。应用还提供多种显示模式——内联卡片、全屏或画中画——为不同任务提供灵活性[15]

改变用户期望

在不切换上下文的情况下使用应用的能力可能重塑人们与服务交互的方式。ChatGPT 不仅成为聊天机器人,而且成为意图的通用操作系统。正如 Casey Newton 观察到的,这让我们从启动离散应用转向简单地陈述我们想要什么[16]。一些分析师将这种转变比作 App Store 或浏览器的推出:一个聚合功能和竞争的单平台。

然而,这种转变引发了关于控制和权力的问题。如果 ChatGPT 决定展示哪些应用,它可能成为守门人。Newton 警告说,基于用户偏好构建的"AI 图"可能创造比社交网络更严重的隐私风险[16]。经济激励可能导致付费播放或应用排名。开发者可能感到压力,为 ChatGPT 设计而不是拥有与用户的关系。平台保持透明和公平以维持信任至关重要。

监管和伦理影响

由于应用可以访问个人数据——位置、联系人、支付方式——监管机构可能会审查数据如何通过 ChatGPT 流动。开发者必须遵守 GDPR 等隐私法律,即使该平台尚未在欧盟提供[17]。OpenAI 承诺更细粒度的隐私控制和货币化选项,包括允许在聊天中进行即时结账的代理商务协议[18]。这个生态系统的成功将取决于强大的安全性、明确的用户同意和公平的经济模式。

未来方向和研究

Apps SDK 仍在预览中,许多功能仍有待完善。开发者路线图包括:

  • 提交和审查工作流 – 目前开发者可以构建应用但无法公开列出它们。正式的审查流程将确保符合指南和信任。

  • 收入分享和货币化 – OpenAI 暗示了一个代理商务协议,可以让用户在聊天中直接购买商品[18]。这为电子商务创造了机会,但也引发了关于费用、排名和竞争的问题。

  • 开发者工具 – 更多语言和框架、改进的调试工具和更简单的部署管道将降低进入门槛。MCP 的开放标准性质可能导致社区驱动的实现和托管提供商。

  • 互操作性 – 由于 MCP 是开放的,其他平台或模型可以采用它。这可能实现跨模型应用生态系统,开发者编写一次,在任何地方运行。标准化代理协议和上下文共享的研究将很重要。

  • 安全研究 – 评估如何防止提示注入、恶意代码或滥用用户数据仍然是一个主要研究领域。关于对 LLM 集成应用的对抗性攻击的论文将为最佳实践和指南提供信息。

结论:正在形成的新操作系统

ChatGPT 应用基于 MCP 的 Apps SDK的引入标志着我们与软件交互方式的重大转变。通过将第三方应用程序直接带入聊天界面,OpenAI 创建了一个融合自然语言、推理和交互式 UI 的新平台。模型上下文协议为模型调用工具和渲染组件提供了开放、标准化的方式;Apps SDK通过处理服务器通信、UI 集成和状态管理简化了开发。像任务跟踪器这样的分步示例演示了在保持严格数据边界和隐私的同时构建有用应用是多么容易。

然而,这种创新伴随着责任。开发者必须遵循优先考虑用户隐私、安全和公平的指南[11][12]。最小权限和明确同意等安全机制保护用户[6]。同时,行业观察者警告说,该平台可能创造新形式的守门和隐私风险[16]。随着生态系统的成熟,透明度、开放标准和社区参与将决定 ChatGPT 的应用平台是否成为日常任务的变革性、可信层。


[1] AI 军备竞赛最新消息:ChatGPT 现在让用户在聊天中连接 Spotify 和 Zillow

https://www.forbes.com/sites/antoniopequenoiv/2025/10/06/openais-chatgpt-now-connects-with-third-party-apps-like-spotify-and-zillow-heres-the-latest-in-the-ai-arms-race/

[2] [3] [4] [5] 设置你的服务器

https://developers.openai.com/apps-sdk/build/mcp-server

[6] [7] 安全与隐私

https://developers.openai.com/apps-sdk/guides/security-privacy

[8] 构建自定义用户体验

https://developers.openai.com/apps-sdk/build/custom-ux

[9] [10] 用户交互

https://developers.openai.com/apps-sdk/concepts/user-interaction

[11] [12] 应用开发者指南

https://developers.openai.com/apps-sdk/app-developer-guidelines/

[13] ChatGPT 应用已上线:以下是你可以尝试的第一批应用 | The Verge

https://www.theverge.com/news/793081/chagpt-apps-sdk-spotify-zillow-openai

[14] OpenAI DevDay 2025:ChatGPT 获得应用、开发者的 AgentKit 和更便宜的 GPT 模型

https://indianexpress.com/article/technology/artificial-intelligence/openai-devday-2025-chatgpt-gets-apps-agentkit-for-developers-and-cheaper-gpt-models-10292443/

[15] OpenAI 宣布 Apps SDK 允许 ChatGPT 启动和运行第三方应用,如 Zillow、Canva、Spotify | VentureBeat

https://venturebeat.com/ai/openai-announces-apps-sdk-allowing-chatgpt-to-launch-and-run-third-party

[16] 新平台,熟悉的风险:Zillow 和 Expedia 押注 OpenAI 的 ChatGPT 应用推出 – GeekWire

https://www.geekwire.com/2025/new-platform-familiar-risks-zillow-and-expedia-bet-on-openais-chatgpt-apps-rollout/

[17] OpenAI DevDay:ChatGPT 应用、AgentKit 和 Codex 的正式发布 - SD Times

https://sdtimes.com/ai/openai-devday-chatgpt-apps-agentkit-and-ga-release-of-codex/

[18] OpenAI 希望将 ChatGPT 打造成通用应用前端 - Ars Technica

https://arstechnica.com/ai/2025/10/openai-wants-to-make-chatgpt-into-a-universal-app-frontend/

相关文章

Loading related articles...

申请成为 Macaron 的首批朋友