返回博客2026年3月6日

MCP Apps:让 AI 对话里长出交互界面

MCPMCP AppsAI Agent交互界面

MCP 协议解决了 AI 模型和外部工具之间的连接问题 - 数据库、API、文件系统,统统可以通过标准协议接入。但有一个根本限制一直没被解决:工具只能返回文本。

你让 Agent 查销售数据,它返回一堆数字。你让它画个图,它只能用 ASCII art 凑合。你让它配置一个有几十个参数的部署方案,只能一问一答地来回确认。

MCP Apps 就是来解决这个问题的。它是 MCP 协议的第一个官方扩展,让工具可以返回完整的交互式 HTML 界面,直接渲染在对话窗口里。

核心机制

MCP Apps 的架构建立在两个 MCP 原语之上 - ui:// 协议和 iframe 沙箱。

带 UI 元数据的工具声明:工具在定义时通过 _meta.ui.resourceUri 字段指向一个 UI 资源。

{
  name: "visualize_data",
  description: "Visualize data as an interactive chart",
  inputSchema: { /* ... */ },
  _meta: {
    ui: {
      resourceUri: "ui://charts/interactive"
    }
  }
}

UI 资源:通过 ui:// 协议提供的 HTML/JavaScript/CSS 页面,由 MCP 服务器托管。

当 LLM 决定调用一个支持 MCP Apps 的工具时,流程是这样的:

  1. UI 预加载:Host 读到工具描述里的 _meta.ui.resourceUri,可以在工具被调用之前就预加载 UI 资源,甚至支持流式输入。
  2. 资源获取:Host 从 MCP 服务器拉取 UI 资源 - 一个自包含的 HTML 页面。
  3. 沙箱渲染:UI 在沙箱化的 iframe 中渲染,无法访问父页面的 DOM、cookie 或存储。
  4. 双向通信:UI 和 Host 之间通过 postMessage 上的 JSON-RPC 协议通信。
sequenceDiagram
    participant 用户
    participant Agent
    participant MCP服务器

    用户->>Agent: 发起请求
    Agent->>MCP服务器: 调用工具
    MCP服务器-->>Agent: 返回工具结果 + UI 资源
    Agent-->>用户: Host 渲染 iframe
    用户->>用户: 直接在界面上交互
    用户->>MCP服务器: UI 通过 postMessage 调用更多工具

这里最关键的设计决策是:UI 跑在 iframe 沙箱里,所有通信走 JSON-RPC over postMessage。这意味着 MCP Apps 不需要信任第三方代码 - Host 完全控制 UI 能访问什么、能调用什么工具。

App SDK

理解了底层机制,再来看开发者怎么用。官方提供了 @modelcontextprotocol/ext-apps 包,用它的 App 类来构建 UI:

import { App } from "@modelcontextprotocol/ext-apps";

const app = new App();
await app.connect();

// 接收工具返回的结果
app.ontoolresult = (result) => {
  renderChart(result.data);
};

// 从 UI 调用服务器上的工具
const response = await app.callServerTool({
  name: "fetch_details",
  arguments: { id: "123" },
});

// 更新模型的上下文
await app.updateModelContext({
  content: [{ type: "text", text: "用户选择了方案 B" }],
});

三个核心能力:

  • 接收数据:工具返回结果时自动推送到 UI
  • 调用工具:UI 可以反向调用 MCP 服务器上的任何工具(需用户授权)
  • 更新上下文:UI 可以把用户的交互结果反馈给模型

你可以用任何前端框架 - React、Vue、Svelte、纯 JavaScript - 只要最终输出是标准的 HTML/CSS/JS。官方仓库提供了 React、Vue、Svelte、Preact、Solid 和原生 JS 的模板。

安全模型

在第三方代码跑在 AI 对话窗口里的场景下,安全自然是核心考量。MCP Apps 设计了四层防护:

  1. iframe 沙箱:所有 UI 在受限权限的沙箱 iframe 中运行,无法访问父页面
  2. 预声明模板:Host 在渲染前审查 HTML 内容,防止动态代码注入
  3. 可审计消息:所有 UI 和 Host 之间的通信都走 JSON-RPC,可以记录和审查
  4. 用户授权:UI 发起的工具调用需要用户明确同意

_meta.ui 对象还可以包含 permissions(请求麦克风、摄像头等能力)和 csp(控制可以加载哪些外部资源的来源),这些都由 Host 决定是否批准。

适用场景

MCP Apps 不是要替代所有 Web 应用。它适合那些和 AI 对话紧密结合的场景:

复杂数据探索:用户问"展示各地区的销售数据",不再是一堆数字,而是一个交互式地图 - 点击区域下钻,悬停查看详情,切换指标。

多参数配置:部署方案有几十个互相依赖的选项。与其一问一答,不如直接展示一个表单,所有选项一目了然,带校验和默认值。

富媒体查看:PDF 预览、3D 模型旋转、图片标注 - 这些光靠文字描述无法完成的任务。

实时监控:系统指标、日志流、构建状态 - 需要持续更新的数据,不用反复问"现在状态怎样"。

多步骤工作流:审批流程、代码审查、问题分类 - 需要逐项处理、有状态的操作。

客户端支持

MCP Apps 作为 MCP 协议扩展,需要 Host 端支持。目前已支持的客户端:

  • Claude(Web 和桌面端)
  • ChatGPT(Web 端)
  • VS Code GitHub Copilot
  • Goose
  • Postman
  • MCPJam

如果你在构建自己的 MCP 客户端,有两种集成方式:使用 @mcp-ui/client React 组件库,或者直接使用 App Bridge 模块处理 iframe 渲染和消息传递。

官方示例

官方 ext-apps 仓库包含了大量示例,覆盖面很广:

  • 3D 和可视化:CesiumJS 地球仪、Three.js 场景、着色器效果
  • 数据探索:群组热力图、客户细分、Wiki 浏览器
  • 商业应用:情景建模、预算分配
  • 媒体:PDF 查看器、视频资源、乐谱、文字转语音
  • 工具:QR 码生成、系统监控、语音转文字

和 ChatGPT Apps 的区别

你可能会问:这和 ChatGPT Apps 有什么区别?

核心区别在于可移植性。ChatGPT Apps 只能在 ChatGPT 里运行。MCP Apps 是一个开放标准(托管在 Linux Foundation 下),同一个 App 不需要任何修改就能在 Claude、ChatGPT、VS Code、Goose 等所有支持的客户端里运行。

用官方的说法:MCP Apps 是"provider-agnostic open standard for embedded UIs" - 一个不依赖特定平台的嵌入式 UI 开放标准。

MCP 协议解决了 AI 模型和外部工具的连接问题,MCP Apps 则解决了交互问题。从纯文本到交互式界面,这是 MCP 生态的一次质变。对开发者来说,关键信息是:你写的 MCP App 是一个标准的 Web 页面,用标准的 Web 技术构建,通过标准的协议通信。没有新的框架需要学,没有平台锁定。这个设计选择比任何具体的技术实现都重要。

相关文章

2026年2月17日

Next.js 正在为 AI Agent 重新设计自己

Next.js 团队发布了一篇博客,讲述他们如何从 Agent 的视角重新思考框架设计。从一个被放弃的浏览器内 Agent,到 MCP 集成,再到 agents.md - 这篇是我的阅读笔记。

Next.jsAI AgentMCP

合作伙伴

CompeteMap — 英国及爱尔兰学生竞赛一站式搜索

数学、编程、科学、写作等各类竞赛信息汇总,支持按年龄和科目筛选,再也不错过报名截止日。

准备开始了吗?

先简单说明目标,我会给出最合适的沟通方式。