MCP Apps:让 AI 对话里的工具带上交互界面

TL;DR

介绍 MCP Apps 的 ui:// 资源、工具与 UI 绑定、沙箱 iframe、权限可见性和不支持客户端的文本回退策略。

MCP Apps 通过 ui:// 资源、工具元数据和沙箱 iframe,让 MCP 服务器可以向宿主提供交互式 HTML 界面。本文解释工具与 UI 的关联、权限边界、文本回退和安全模型。

MCP Apps:让 AI 对话里的工具带上交互界面

传统 MCP 工具的结果通常是一段文字或一组结构化数据。对于查询天气、读取订单状态这类任务已经够用,但有些工具天然需要界面:地图要能缩放,表格要能筛选,审批单要能勾选,图表要能展示多个维度。如果每个 MCP 客户端都自己设计一套渲染方式,同一个工具就会被迫维护多套前端实现。

MCP Apps 试图给这件事建立一个可协商的标准。服务器可以声明一个可交互的 HTML UI 资源,宿主在工具执行后把它呈现在对话界面里;如果宿主不支持 MCP Apps,工具仍然可以退化成普通的文本或结构化结果。

工具和界面如何关联

MCP Apps 引入了 ui:// URI,用来标识由服务器提供的 UI 资源。工具通过 _meta.ui.resourceUri 指向这份资源,宿主在发现工具时就能知道:这个工具除了返回结果,还可能有一个适合人类操作的视图。

这和“让模型生成一段 HTML”不同。UI 资源是服务器预先声明、可以被宿主检查和缓存的内容;动态数据仍然通过工具调用结果传入。模板和数据分离后,宿主可以提前加载模板,也能在工具执行前明确它会使用哪些界面资源。

它不是把网页直接塞进聊天窗口

安全边界是 MCP Apps 的核心。对于 Web 宿主,规范要求通过不同源的 Sandbox Proxy 包裹 UI,并使用限制性的 CSP。默认情况下,资源不能随意加载对象、脚本来源或嵌套 iframe;如果应用确实需要访问某些域名、摄像头、麦克风或剪贴板,也要通过元数据明确声明。

UI 与宿主之间不应该依赖某个客户端私有的全局对象,而是通过 postMessage 上的 MCP 风格 JSON-RPC 消息通信。UI 可以接收工具输入和工具结果,也可以请求宿主调用工具;宿主则负责决定哪些调用被允许,不能因为 UI 中出现一个按钮,就自动把高风险操作直接放行。

这也是为什么工具可见性被拆成 modelapp 两种范围。一个用于查询数据的工具可以同时对模型和 UI 可见;一个只用于刷新局部组件的工具则可以只对 UI 可见,避免它被模型当成普通工具误用。宿主还必须拒绝不符合可见性规则的调用。

交互式 UI 仍然需要文本回退

协议扩展不会让所有客户端突然具备渲染 HTML 的能力。MCP Apps 明确要求保持渐进增强:支持扩展的宿主可以展示交互式视图,不支持的宿主继续使用普通工具结果。服务器应该确保文本结果本身仍然有意义,而不是把关键结论全部藏在 UI 里。

这条回退路径也有助于可访问性、日志审计和自动化测试。人类可以在界面里筛选数据,模型可以读取结构化结果,审计系统则可以记录工具输入、工具输出和 UI 触发的后续调用。三者不必共享同一种展示方式,但必须共享同一条可验证的调用链。

适合用在什么地方

MCP Apps 适合把“工具结果”和“下一步操作”放在一起的场景:数据分析面板、旅行规划、订单审批、代码变更预览、文件选择和多步骤表单。它不适合把任意网页当作 iframe 嵌入,也不应该成为绕过宿主权限模型的后门。

真正成熟的实现需要同时考虑资源版本、CSP、权限策略、工具幂等、取消操作和文本回退。MCP Apps 的意义,是让 Agent 工具不再只有“调用后吐一段文字”这一种形态,但交互界面越丰富,宿主越需要把渲染权限与业务权限分开管理。

来源:MCP Apps 官方规范

KEEP READING