# MCP App 协议培训文档 > 面向团队的技术培训材料,帮助理解 MCP App 协议的核心机制、实现方式与应用场景。 --- ## 目录 1. [为什么需要 MCP App](#1-为什么需要-mcp-app) 2. [MCP Apps vs A2UI 对比](#2-mcp-apps-vs-a2ui-对比) 3. [核心概念:三层分离架构](#3-核心概念三层分离架构) 4. [协议通信机制详解](#4-协议通信机制详解) 5. [代码实现走读](#5-代码实现走读) 6. [现有实现案例分析](#6-现有实现案例分析) 7. [如何开发一个新的 MCP App Skill](#7-如何开发一个新的-mcp-app-skill) 8. [实际应用场景](#8-实际应用场景) 9. [FAQ](#9-faq) --- ## 1. 为什么需要 MCP App ### 传统 Agent 的局限 传统的 AI Agent 只能输出文本(Markdown、代码块等),无法直接在对话中呈现**可交互的 UI**。用户看到的永远是静态文字。 ### MCP App 解决的问题 MCP App 协议让 Agent 的工具调用(tool call)能够返回**富交互组件**——图表、表单、按钮、嵌入页面等——直接渲染在聊天窗口中,用户可以点击、选择、输入,结果再传回 Agent 继续对话。 ``` 用户提问 → Agent 思考 → 调用 MCP Tool → 返回 UI 组件 → 用户交互 → 结果回传 Agent ``` **核心价值:让 Agent 从"只会说话"变成"能展示、能交互"。** --- ## 2. MCP Apps vs A2UI 对比 > 参考:[hia2ui.com - MCP Apps vs A2UI](https://hia2ui.com/zh-cn/blog/mcp-apps-vs-a2ui/) 在 Agent UI 领域,目前存在两种主流协议方案。了解它们的差异有助于我们做出更好的技术选型。 ### 2.1 两种哲学 | | MCP Apps (Anthropic) | A2UI (Google) | |---|---|---| | **核心理念** | **UI 即资源** — 将 UI 视为不透明的、外部获取的黑盒资源 | **UI 即协议** — 通过只具有声明语义的强类型 JSON 蓝图传输 | | **传输内容** | 完整的 HTML/CSS/JavaScript 代码包 | 纯 JSON 声明式数据,**绝对不包含可执行代码** | | **URI 格式** | `ui://server-name/resource` | N/A(通过 JSON schema 定义组件类型) | | **宿主角色** | 被动容器 — 将 HTML 丢进 iframe 渲染 | 主动绘制者 — 用本地原生组件树渲染 JSON 蓝图 | 用一句话概括差异: - **MCP Apps**:服务端说"这是我画好的 UI 界面,你直接嵌进去展示" - **A2UI**:服务端说"这是我要展示的数据结构,你用你自己的 UI 组件来画" ### 2.2 四大维度详细对比 #### 维度一:核心架构 ``` MCP Apps(Iframe 沙盒模式): ┌──────────────────────┐ │ Host(聊天界面) │ │ ┌──────────────────┐ │ │ │ Iframe (sandbox) │ │ ← 将服务端返回的 HTML 代码 │ │ ┌──────────────┐ │ │ "盲目地"丢进 iframe 沙盒 │ │ │ 完整 HTML/JS │ │ │ │ │ └──────────────┘ │ │ │ └──────────────────┘ │ └──────────────────────┘ A2UI(原生声明式蓝图): ┌──────────────────────┐ │ Host(聊天界面) │ │ │ │ ┌─────┐ ┌─────┐ │ ← Host 拿到 JSON 蓝图后 │ │Button│ │Card │ │ 用自己本地的原生组件渲染 │ └─────┘ └─────┘ │ │ ┌─────┐ ┌─────┐ │ │ │Chart│ │List │ │ │ └─────┘ └─────┘ │ └──────────────────────┘ ``` #### 维度二:跨平台可移植性 | 平台 | MCP Apps | A2UI | |------|---------|------| | Web 浏览器 | 原生支持,表现优秀 | 映射为 React/Web 组件 | | iOS | 需启动 WebView 内核,体验较重 | 映射为原生 UIButton 等 iOS 组件 | | Android | 需启动 WebView 内核,体验较重 | 映射为 Material Design 组件 | | 桌面端 | Electron 等框架可支持 | 映射为对应平台原生组件 | **结论**:A2UI 在跨平台一致性上优势明显。同一份 JSON 负载可以在各平台渲染为原生体验,而 MCP Apps 在非 Web 平台需要依赖 WebView,体验较重。 #### 维度三:样式控制权与设计一致性 | 维度 | MCP Apps | A2UI | |------|---------|------| | 样式由谁决定 | **服务端**决定(HTML/CSS 自带样式) | **宿主应用**决定(本地组件库样式) | | 品牌一致性 | 较难保证,第三方 HTML 样式难以覆盖 | 自动继承宿主的 Design Tokens | | 深色模式 | 需要 HTML App 自行适配 | 自动继承宿主的主题设置 | | 定制能力 | 需要 CSS overrides 强行覆盖 | 天然支持,AI 只决定"展示什么",不决定"长什么样" | **结论**:A2UI 在设计一致性上完胜。MCP Apps 的 HTML 自带样式可能与宿主应用的设计规范冲突。 #### 维度四:安全性与信任边界 | 维度 | MCP Apps | A2UI | |------|---------|------| | 可执行代码 | 包含(HTML 中可嵌入 JS) | **绝对禁止**(纯 JSON 数据) | | 隔离方式 | 浏览器 Iframe 沙盒 | 在协议层面从根本上阻断代码注入 | | 攻击面 | Iframe 沙盒逃逸是已知攻击面 | 无可执行代码 = 无 UI 注入攻击面 | | LLM 生成风险 | HTML 可能由 LLM 实时生成,存在幻觉风险 | 仅传输声明式数据,组件由预审批目录提供 | **结论**:A2UI 从架构层面更安全(无可执行代码传输)。MCP Apps 依赖 Iframe 沙盒隔离,安全性取决于浏览器实现。 ### 2.3 各自适用场景 #### 选择 MCP Apps 的场景 适合需要展示**完整独立应用**或**重度定制 UI** 的场景: - 包含复杂交互逻辑的独立工具(如 3D WebGL 可视化、代码编辑器) - 需要嵌入的遗留系统界面(老旧的内部报表系统等) - 有特殊渲染需求的第三方工具(终端模拟器、地图引擎等) - 全屏弹窗类的沉浸式体验 > 特点:Agent 将它们作为**独立的全屏应用**召唤出来,自成一体。 #### 选择 A2UI 的场景 适合需要在聊天流中**深度内联嵌入**富交互微件的场景: - 聊天流中的原生交互卡片(商品卡片、审批卡片等) - 数据驱动的动态仪表盘 - 需要完美匹配宿主品牌设计规范的组件 - 需要跨 Web + Mobile 统一体验的场景 > 特点:AI 生成的卡片与前端手写组件**无法分辨真假**。 ### 2.4 对比总结 ``` MCP Apps A2UI ┌─────────────────┐ ┌─────────────────┐ 灵活度 │ ★★★★★ 极高 │ │ ★★★☆☆ 受组件库约束│ 跨平台 │ ★★★☆☆ Web 为主 │ │ ★★★★★ 全平台原生 │ 设计一致性 │ ★★☆☆☆ 需手动适配│ │ ★★★★★ 自动继承 │ 安全性 │ ★★★☆☆ 依赖沙盒 │ │ ★★★★★ 架构级安全 │ 开发门槛 │ ★★★★☆ 写 HTML 即可│ │ ★★★☆☆ 需组件库支持│ 复杂 UI 能力 │ ★★★★★ 无限制 │ │ ★★★☆☆ 受限于组件集│ └─────────────────┘ └─────────────────┘ ``` ### 2.5 我们的选择与思考 **我们当前采用 MCP Apps 协议**,原因: 1. **灵活度优先**:我们的场景需要渲染各种复杂 UI(ECharts 图表、自定义表单、任意 HTML),MCP Apps 的"传 HTML"模式给了我们最大的自由度 2. **Web 优先**:我们的宿主环境是 Web 聊天界面,MCP Apps 的 iframe 方案天然契合 3. **开发效率**:写一个 HTML 模板 + 一个 MCP Server 就能实现一个新组件,门槛低 4. **生态兼容**:MCP 协议本身已有广泛的社区和工具链支持 **未来可能的演进**: - 对于需要深度内联到聊天流、强调品牌一致性的轻量卡片(如通知卡片、状态标签),可以考虑引入 A2UI - 两种协议**并不互斥**,未来可能在同一应用中混合使用:重度工具用 MCP Apps,轻量卡片用 A2UI - 关注 CopilotKit 等框架的双协议支持进展 --- ## 3. 核心概念:三层分离架构 MCP App 协议的精髓是 **数据与 UI 分离**: ``` ┌─────────────────────────────────────────────────┐ │ Host (宿主) │ │ 即聊天界面,负责 iframe 管理和消息路由 │ │ │ │ ┌─────────────────┐ ┌─────────────────────┐ │ │ │ MCP Server │ │ HTML App (iframe) │ │ │ │ (数据层) │ │ (渲染层) │ │ │ │ │ │ │ │ │ │ tools/call │ │ 接收 postMessage │ │ │ │ → 返回纯数据 │ │ → 渲染成可交互 UI │ │ │ │ │ │ │ │ │ │ resources/read │ │ 用户操作 │ │ │ │ → 返回静态 HTML │ │ → postMessage 回传 │ │ │ └─────────────────┘ └─────────────────────┘ │ └─────────────────────────────────────────────────┘ ``` ### 三个角色 | 角色 | 职责 | 对应代码 | |------|------|----------| | **MCP Server** | 处理 `tools/call` 返回结构化数据;处理 `resources/read` 返回 HTML 模板 | `*_server.py` | | **HTML App** | 静态 HTML 文件,监听 `postMessage` 接收数据后渲染 UI | `apps/*.html` | | **Host** | 聊天界面,负责创建 iframe、加载 HTML App、通过 postMessage 传递数据 | 前端聊天框架 | ### 为什么要分离? - **安全**:HTML App 运行在 sandboxed iframe 中,与主页面隔离 - **复用**:同一个 HTML App 模板可以渲染不同数据 - **解耦**:MCP Server 不需要关心渲染细节,只负责产出数据 --- ## 4. 协议通信机制详解 ### 3.1 完整通信流程 以 `render_chart` 工具调用为例,完整流程如下: ``` 步骤 1: Agent 决定调用 render_chart 工具 ↓ 步骤 2: Host 发送 tools/call 请求到 MCP Server → {"method": "tools/call", "params": {"name": "render_chart", "arguments": {...}}} ↓ 步骤 3: MCP Server 返回 App Response(纯数据 + 资源引用) ← {"type": "app", "resourceUri": "ui://data-dashboard/chart", "data": {...}} ↓ 步骤 4: Host 解析到 resourceUri,发送 resources/read 请求 → {"method": "resources/read", "params": {"uri": "ui://data-dashboard/chart"}} ↓ 步骤 5: MCP Server 返回静态 HTML 模板 ← {"mimeType": "text/html;profile=mcp-app", "text": "...chart.html内容..."} ↓ 步骤 6: Host 将 HTML 加载到 sandboxed iframe ↓ 步骤 7: iframe 内 HTML App 发送就绪信号 → window.parent.postMessage({type: 'mcp-app-ready'}, '*') ↓ 步骤 8: Host 收到就绪信号后,通过 postMessage 发送数据 → iframe.postMessage({type: 'mcp-app-data', payload: {...}}, '*') ↓ 步骤 9: HTML App 接收数据并渲染 UI ↓ 步骤 10: (可选)用户交互后,HTML App 通过 postMessage 回传结果 → window.parent.postMessage({type: 'mcp-app-response', payload: {...}}, '*') ``` ### 3.2 三种关键消息类型 | 消息类型 | 方向 | 用途 | |----------|------|------| | `mcp-app-ready` | iframe → Host | HTML App 加载完毕,请求数据 | | `mcp-app-data` | Host → iframe | 向 HTML App 传递工具调用返回的数据 | | `mcp-app-response` | iframe → Host | 用户交互结果回传给 Agent | ### 3.3 App Response 数据结构 MCP Server 的 `tools/call` 返回的核心结构: ```json { "type": "app", "resourceUri": "ui://data-dashboard/chart", "data": { "title": "Monthly Revenue", "chart_type": "line", "data": { "categories": ["Jan", "Feb", "Mar"], "series": [{"name": "Revenue", "data": [820, 932, 901]}] } }, "_meta": { "mcpui.dev/ui-preferred-frame-size": ["100%", "400px"] } } ``` 关键字段: - `type: "app"` — 告诉 Host 这是一个需要渲染的 App 类型结果 - `resourceUri` — 指向要加载的 HTML App 模板的 URI - `data` — 传递给 HTML App 的业务数据 - `_meta` — 元信息,如建议的 iframe 尺寸 ### 3.4 Resource URI 协议 资源 URI 使用 `ui://` scheme: ``` ui://data-dashboard/chart → chart.html ui://data-dashboard/metrics → metrics.html ui://mcp-ui/html → html.html (通用 HTML 渲染器) ui://mcp-ui/ask-user → ask-user.html (交互式问答) ``` MIME Type 约定: - `text/html;profile=mcp-app` — 标准 MCP App HTML - `text/uri-list` — 外部 URL 嵌入 --- ## 5. 代码实现走读 ### 5.1 目录结构(以 data-dashboard 为例) ``` skills/common/data-dashboard/ ├── .claude-plugin/ │ └── plugin.json # 插件注册配置 ├── hooks/ │ ├── pre_prompt.py # PrePrompt 钩子:注入工具使用指南 │ └── dashboard_guide.md # Agent 使用指南(注入到 system prompt) ├── apps/ │ ├── chart.html # 单图表渲染器 │ ├── metrics.html # KPI 指标卡渲染器 │ └── multi-chart.html # 多图表网格渲染器 ├── dashboard_server.py # MCP Server 主体 ├── dashboard_tools.json # 工具定义(JSON Schema) └── mcp_common.py # 共享工具函数 ``` ### 5.2 plugin.json — 插件注册 ```json { "name": "data-dashboard", "description": "Renders data as interactive dashboard card UI", "hooks": { "PrePrompt": [{"type": "command", "command": "python hooks/pre_prompt.py"}] }, "mcpServers": { "data_dashboard": { "transport": "stdio", "command": "python", "args": ["./dashboard_server.py", "{bot_id}"] } } } ``` 要点: - `mcpServers` 注册 MCP Server,使用 stdio 传输 - `hooks.PrePrompt` 在对话开始前注入工具使用指南,让 Agent 知道何时/如何调用这些工具 - `{bot_id}` 是动态参数,运行时替换为实际的 bot ID ### 5.3 MCP Server 核心逻辑 Server 需要处理 5 种 MCP 方法: ```python # 1. initialize — 握手,声明 capabilities if method == "initialize": return {"capabilities": {"tools": {}, "resources": {}}} # 2. tools/list — 返回可用工具列表(含 _meta.ui.resourceUri) elif method == "tools/list": tools = load_tools_from_json("dashboard_tools.json") return {"tools": tools} # 3. resources/list — 返回可用资源列表 elif method == "resources/list": return {"resources": RESOURCE_DEFINITIONS} # 4. resources/read — 返回 HTML App 文件内容 elif method == "resources/read": html = _load_app_html(uri) return {"contents": [{"uri": uri, "mimeType": "text/html;profile=mcp-app", "text": html}]} # 5. tools/call — 执行工具,返回 App Response elif method == "tools/call": result = handler(arguments) return result ``` ### 5.4 工具定义中的 `_meta` 字段 工具定义(`dashboard_tools.json`)中的 `_meta.ui.resourceUri` 是关键: ```json { "name": "render_chart", "description": "Render a single ECharts chart", "inputSchema": { ... }, "_meta": { "ui": { "resourceUri": "ui://data-dashboard/chart" } } } ``` 这个字段告诉 Host:调用这个工具的结果需要使用 `ui://data-dashboard/chart` 对应的 HTML App 来渲染。 ### 5.5 HTML App 模板的标准写法 每个 HTML App 都遵循同一个模式: ```html
``` 如果需要**回传用户交互结果**(如 ask-user),额外添加: ```javascript // 用户点击提交后 window.parent.postMessage({ type: 'mcp-app-response', payload: { /* 用户选择的数据 */ } }, '*'); ``` --- ## 6. 现有实现案例分析 ### 6.1 mcp-ui — 基础 UI 组件库 提供三个通用工具: | 工具 | 功能 | HTML App | |------|------|----------| | `render_html` | 渲染任意 HTML/CSS/JS | `html.html` — 通用 HTML 注入渲染器 | | `render_url` | 嵌入外部 URL | `url.html` — iframe 嵌套器 | | `ask_user` | 交互式问答(单选/多选) | `ask-user.html` — 选项卡界面 | **特点**:`render_html` 是万能的——Agent 可以生成任意 HTML 内容直接渲染,灵活度最高。 ### 6.2 data-dashboard — 数据可视化 提供三个专用图表工具: | 工具 | 功能 | HTML App | |------|------|----------| | `render_metrics` | KPI 指标卡 | `metrics.html` — 网格卡片布局 | | `render_chart` | 单图表(6种类型) | `chart.html` — ECharts 渲染器 | | `render_multi_chart` | 多图表网格 | `multi-chart.html` — 网格 ECharts | **特点**:Agent 只需提供结构化数据(类型、分类、数值),HTML App 负责用 ECharts 渲染出专业图表。 ### 6.3 static-hosting — 静态文件托管 与前两者不同,static-hosting 不走 MCP App 协议,而是: - Agent 将生成的 HTML/CSS/JS 写入文件系统 - 通过 FastAPI 静态文件服务提供公开 URL - 适用于需要**持久化访问**的场景(生成报告、网页等) **与 MCP App 的区别**: - MCP App → 嵌入在聊天窗口内,临时性 - static-hosting → 独立 URL,持久化,可分享 --- ## 7. 如何开发一个新的 MCP App Skill ### 步骤总结 ``` 1. 创建目录结构 skills/common/my-skill/ ├── .claude-plugin/plugin.json ├── hooks/ │ ├── pre_prompt.py │ └── usage_guide.md ├── apps/ │ └── my-widget.html ├── my_server.py ├── my_tools.json └── mcp_common.py (symlink 或 copy) 2. 定义工具 (my_tools.json) - name, description, inputSchema - _meta.ui.resourceUri 指向你的 HTML App 3. 编写 HTML App (apps/my-widget.html) - 监听 mcp-app-data - 发送 mcp-app-ready - (可选)发送 mcp-app-response 4. 编写 MCP Server (my_server.py) - 实现 initialize / tools/list / resources/list / resources/read / tools/call - tools/call 中将参数转为 App Response 5. 编写 Agent 使用指南 (hooks/usage_guide.md) - 告诉 Agent 什么时候用、怎么用这个工具 6. 注册插件 (.claude-plugin/plugin.json) - 配置 mcpServers 和 hooks ``` ### 快速模板 一个最小的 MCP App Server(Python): ```python import asyncio, json, os from mcp_common import (create_error_response, create_ping_response, create_tools_list_response, load_tools_from_json, handle_mcp_streaming) RESOURCE_MIME_TYPE = "text/html;profile=mcp-app" APPS_DIR = os.path.join(os.path.dirname(__file__), "apps") RESOURCE_MAP = {"ui://my-skill/widget": "widget.html"} def _load_app_html(uri): filename = RESOURCE_MAP.get(uri) if not filename: raise ValueError(f"Unknown resource URI: {uri}") with open(os.path.join(APPS_DIR, filename), "r") as f: return f.read() def _create_app_response(resource_uri, data, width="100%", height="auto"): return {"content": [{"type": "text", "text": json.dumps({ "type": "app", "resourceUri": resource_uri, "data": data, "_meta": {"mcpui.dev/ui-preferred-frame-size": [width, height]}, }, ensure_ascii=False)}]} async def handle_request(request): method = request.get("method") params = request.get("params", {}) rid = request.get("id") if method == "initialize": return {"jsonrpc": "2.0", "id": rid, "result": { "protocolVersion": "2024-11-05", "capabilities": {"tools": {}, "resources": {}}, "serverInfo": {"name": "my-skill", "version": "1.0.0"}}} elif method == "tools/list": return create_tools_list_response(rid, load_tools_from_json("my_tools.json")) elif method == "resources/list": return {"jsonrpc": "2.0", "id": rid, "result": {"resources": [ {"uri": "ui://my-skill/widget", "name": "widget", "mimeType": RESOURCE_MIME_TYPE}]}} elif method == "resources/read": html = _load_app_html(params.get("uri", "")) return {"jsonrpc": "2.0", "id": rid, "result": {"contents": [ {"uri": params["uri"], "mimeType": RESOURCE_MIME_TYPE, "text": html}]}} elif method == "tools/call": # 在这里处理你的业务逻辑 return {"jsonrpc": "2.0", "id": rid, "result": _create_app_response( "ui://my-skill/widget", params.get("arguments", {}))} return create_error_response(rid, -32601, f"Unknown method: {method}") if __name__ == "__main__": asyncio.run(handle_mcp_streaming(handle_request)) ``` --- ## 8. 实际应用场景 ### 8.1 已实现的场景 | 场景 | 使用的 Skill | 说明 | |------|-------------|------| | 数据可视化 | data-dashboard | 将查询结果渲染为图表(折线图、饼图、KPI 卡片等) | | 通用 HTML 渲染 | mcp-ui / render_html | Agent 生成任意 HTML 内容直接展示 | | 交互式问答 | mcp-ui / ask_user | 让用户通过点击选项来回答问题 | | 外部页面嵌入 | mcp-ui / render_url | 在聊天中嵌入外部网页 | | 报告生成 | static-hosting | 生成独立 HTML 报告,提供持久化 URL | --- ### 8.2 电商 & 零售行业 #### 场景 1:商品浏览与选购 Agent 作为导购,在对话中展示可交互的商品卡片,用户直接点选下单。 ``` 用户: "我想买一杯咖啡" Agent: 查询商品 → render_html 展示商品卡片列表(图片、价格、规格选择按钮) 用户: 点击"大杯拿铁" → mcp-app-response 回传选择 Agent: 生成订单 → render_html 展示订单确认页(含二维码/支付链接) 用户: 点击"确认支付" → 跳转支付或内嵌支付页 ``` #### 场景 2:订单追踪可视化 用户查询订单后,Agent 用图表和时间轴展示物流进度。 ``` 用户: "我的订单到哪了?" Agent: 查询物流 API → render_html 渲染物流时间轴(已下单→已发货→运输中→派送中) render_url 嵌入地图展示快递实时位置 ``` #### 场景 3:智能比价与推荐 Agent 搜索多平台价格,用图表对比展示,用户点击心仪商品直接购买。 ``` 用户: "帮我比较一下 AirPods Pro 各平台价格" Agent: 调用多个 API → render_chart(chart_type="bar") 展示各平台价格柱状图 render_html 渲染商品对比卡片(含"去购买"按钮) 用户: 点击最低价平台的"去购买" → render_url 嵌入购买页面 ``` #### 场景 4:营销数据看板 商家用 Agent 查看店铺运营数据,实时图表展示 GMV、转化率、流量来源等。 ``` 店主: "看看这周的店铺数据" Agent: 查询后台 API → render_metrics 展示 KPI 卡片(GMV、订单数、客单价、退货率) → render_multi_chart 展示趋势图 + 流量来源饼图 + 热销品排行柱状图 ``` #### 场景 5:退换货自助流程 用户在对话中完成退换货的完整流程,无需跳出。 ``` 用户: "我想退货" Agent: ask_user 选择订单 → ask_user 选择退货原因 → render_html 展示退货信息确认页(商品图、退款金额、退货地址) 用户: 点击"确认退货" → Agent 调用退货 API → 展示退货单号和进度 ``` --- ### 8.3 教育 & 培训行业 #### 场景 1:交互式测验 Agent 出题后用选项卡 UI 让学生作答,即时批改并展示成绩图表。 ``` 老师: "给学生出一套 10 道英语选择题" Agent: 生成题目 → ask_user 逐题展示选项(支持单选/多选) 学生: 逐题点击选项并提交 Agent: 批改 → render_chart(chart_type="gauge") 展示总分 → render_multi_chart 展示各知识点得分雷达图 + 错题分布 ``` #### 场景 2:学习进度仪表盘 学生查看自己的学习数据,Agent 用图表展示进度和薄弱环节。 ``` 学生: "我的学习情况怎么样?" Agent: 查询学习记录 → render_metrics 展示关键指标(完成率、连续学习天数、总学时) → render_chart(chart_type="radar") 展示各科目能力雷达图 → render_chart(chart_type="line") 展示近 30 天学习时长趋势 ``` #### 场景 3:代码 Playground 编程教学中,Agent 在对话内嵌入可运行的代码编辑器,学生即学即练。 ``` 老师: "教学生用 Python 写一个冒泡排序" Agent: 讲解算法 → render_html 渲染一个内嵌的代码编辑器 + 运行按钮 + 输出区 学生: 修改代码 → 点击运行 → 实时看到排序过程动画 ``` #### 场景 4:课程安排与选课 用交互式日历展示课表,学生直接点选空闲时段报名课程。 ``` 学生: "我想报名下周的课程" Agent: 查询可选课程 → render_html 渲染交互式周历(已有课程标灰,可选课程高亮) 学生: 点击某个时段的课程 → mcp-app-response 回传选课信息 Agent: 确认选课 → 更新课表 ``` #### 场景 5:知识图谱可视化 复杂知识点之间的关系用交互式图谱展示,点击节点展开详情。 ``` 学生: "帮我梳理一下机器学习的知识体系" Agent: render_html 渲染交互式知识图谱(D3.js 力导向图) 节点:监督学习、无监督学习、强化学习... 学生: 点击"监督学习" → 回传节点 ID → Agent 展开子图谱(回归、分类、SVM、决策树...) ``` --- ### 8.4 金融 & 财务行业 #### 场景 1:投资组合分析 Agent 查询持仓数据后,用图表展示资产配置和收益走势。 ``` 用户: "看看我的投资组合表现" Agent: → render_chart(chart_type="pie") 展示资产配置比例(股票/债券/基金/现金) → render_chart(chart_type="line") 展示近一年收益率走势(vs 沪深300) → render_metrics 展示关键指标(总资产、日收益、年化收益率、最大回撤) ``` #### 场景 2:财务报表可视化 企业财务数据自动生成专业图表,支持钻取查看明细。 ``` CFO: "展示 Q2 的财务概况" Agent: 查询 ERP → render_multi_chart 四宫格展示: - 收入趋势(折线图) - 成本结构(饼图) - 各部门预算执行(堆叠柱状图) - 现金流仪表盘(gauge) 用户: 点击"销售部"柱子 → Agent 展开销售部详细费用明细 ``` #### 场景 3:风险评估与审批 贷款/保险审核场景,Agent 渲染评估报告和审批按钮。 ``` 风控: "审核这笔贷款申请" Agent: 查询征信 → render_html 渲染风险评估报告(信用评分、负债率、历史逾期) → render_chart(chart_type="gauge") 展示综合风险分数 → render_html 底部渲染"批准 / 拒绝 / 补充材料"操作按钮 风控: 点击"批准" → Agent 调用审批 API → 流程完成 ``` #### 场景 4:账单与报销管理 员工在对话中完成报销申请的完整流程。 ``` 员工: "我要提交上周出差的报销" Agent: ask_user 选择出差项目和费用类型 → render_html 渲染报销单表单(日期、金额、发票上传区) 员工: 填写并提交 → Agent 校验金额 → 提交审批流 → render_html 展示审批进度时间轴 ``` --- ### 8.5 医疗 & 健康行业 #### 场景 1:健康数据可视化 患者查看自己的健康指标趋势,Agent 用图表直观展示。 ``` 患者: "看看我最近的血压数据" Agent: 查询健康记录 → render_chart(chart_type="line") 展示近 30 天血压趋势(收缩压/舒张压双线) → render_metrics 展示平均值、最高值、异常次数 → render_html 底部展示健康建议卡片 ``` #### 场景 2:在线问诊引导 Agent 用交互式问答收集症状,辅助分诊。 ``` 患者: "我最近头疼" Agent: ask_user 收集症状细节: Q1: "头疼持续多久?" → [1-3天, 一周以上, 反复发作] Q2: "伴随哪些症状?" → [恶心, 视力模糊, 发热, 无其他] (multi_select) Q3: "疼痛位置?" → render_html 展示头部示意图,用户点击标记位置 Agent: 综合分析 → render_html 展示初步评估结果 + 推荐科室 + 预约按钮 ``` #### 场景 3:预约挂号 在对话中展示医生排班表,患者点选预约。 ``` 患者: "帮我挂神经内科的号" Agent: 查询排班 → render_html 渲染医生列表卡片(照片、职称、擅长、可约时段) 患者: 点击某医生 → ask_user 选择具体时间段 Agent: 确认预约 → 展示预约成功信息和就诊提醒 ``` --- ### 8.6 企业办公 & HR #### 场景 1:OA 审批流程 请假、采购、出差等审批在对话中一键完成。 ``` 员工: "帮我请三天年假" Agent: ask_user 选择请假类型和日期范围 → render_html 渲染请假申请预览(含剩余年假天数) 员工: 确认 → Agent 提交 OA 系统 → render_html 展示审批链进度(直属经理→HR→完成) ``` #### 场景 2:团队数据看板 管理者查看团队运营指标,图表一目了然。 ``` 经理: "看看我们团队这个月的情况" Agent: → render_metrics 展示 KPI(项目完成率、工时利用率、bug 数、客户满意度) → render_multi_chart 展示: - 各成员工时分布(堆叠柱状图) - 项目进度甘特图(render_html 自定义) - 本月 vs 上月对比(折线图) ``` #### 场景 3:招聘面试管理 HR 用 Agent 管理候选人,在对话中查看面试安排和评估。 ``` HR: "今天有哪些面试?" Agent: 查询日程 → render_html 渲染今日面试时间轴(候选人、岗位、面试官、时间) HR: 点击某候选人 → Agent 展示简历摘要 + 前几轮面评 → ask_user 选择面试结论(通过/待定/淘汰) ``` #### 场景 4:会议纪要与投票 会议中实时收集决策投票,即时展示结果。 ``` 主持人: "大家投票选择 Q3 的主推方案" Agent: ask_user 展示方案选项(方案A/方案B/方案C),支持多人投票 → 汇总结果 → render_chart(chart_type="pie") 展示投票比例 → render_html 展示会议结论摘要 + 行动项清单 ``` --- ### 8.7 房产 & 本地生活 #### 场景 1:房源浏览与对比 在对话中展示房源卡片,支持对比和地图查看。 ``` 用户: "帮我找朝阳区两居室,预算 500 万以内" Agent: 搜索房源 → render_html 渲染房源卡片列表(图片轮播、价格、面积、户型图) 用户: 选中 3 套 → Agent → render_html 渲染对比表格(价格/面积/楼层/朝向/学区) 用户: 点击"查看位置" → render_html 渲染地图标注(3 套房源 + 周边配套) ``` #### 场景 2:餐厅推荐与订位 Agent 推荐餐厅,用户在对话中直接预约座位。 ``` 用户: "今晚想吃日料,帮我推荐" Agent: 搜索附近餐厅 → render_html 渲染餐厅卡片(评分、人均、距离、招牌菜图片) 用户: 点击某餐厅 → Agent 展示详情 + 可用时段 → ask_user 选择用餐时间和人数 Agent: 调用预约 API → 展示预约确认信息 ``` #### 场景 3:装修进度管理 业主用 Agent 追踪装修进度,图文结合展示。 ``` 业主: "装修到哪一步了?" Agent: 查询工程系统 → render_html 渲染装修进度时间轴(水电→瓦工→木工→油漆→软装) 每个节点可展开查看现场照片 → render_chart(chart_type="pie") 展示费用分配 → render_metrics 展示预算执行(总预算、已花费、剩余) ``` --- ### 8.8 物流 & 供应链 #### 场景 1:运输追踪大屏 在对话中展示车队/货物的实时状态。 ``` 调度员: "看看今天所有在途车辆" Agent: 查询 TMS → render_html 渲染地图(标注所有在途车辆位置和状态) → render_metrics 展示概览(在途 23 辆、已到达 15 辆、异常 2 辆) 调度员: 点击异常车辆标注 → Agent 展示异常详情 + 处理选项按钮 ``` #### 场景 2:库存预警与补货 Agent 监控库存,低于阈值时主动展示预警图表和补货建议。 ``` 仓管: "哪些商品快缺货了?" Agent: 查询 WMS → render_html 渲染库存预警表格(红/黄/绿三色标注) → render_chart(chart_type="bar") 展示 Top 10 紧缺商品及预计断货天数 → render_html 底部渲染"一键生成补货单"按钮 仓管: 点击按钮 → Agent 自动生成采购单 → ask_user 确认供应商和数量 ``` --- ### 8.9 旅游 & 酒店行业 #### 场景 1:行程规划助手 Agent 生成交互式行程表,用户拖拽调整。 ``` 用户: "帮我规划 5 天东京自由行" Agent: 生成行程 → render_html 渲染交互式日程表(每天的景点、交通、餐厅、住宿) 每个景点卡片含图片、预计时长、门票价格 用户: 拖拽调整顺序 / 删除某景点 → mcp-app-response 回传新顺序 Agent: 重新优化路线 → render_html 更新地图路线图 ``` #### 场景 2:酒店预订对比 Agent 搜索多个平台,在对话中渲染对比界面。 ``` 用户: "帮我找东京新宿的酒店,2 晚" Agent: 搜索多平台 → render_html 渲染酒店对比卡片(图片轮播、评分、价格、设施标签) → render_chart(chart_type="scatter") 展示价格 vs 评分散点图 用户: 点击心仪酒店 → render_url 嵌入预订页面 ``` #### 场景 3:景区实时信息 展示景区客流量、天气、开放状态等实时信息。 ``` 用户: "迪士尼现在人多吗?" Agent: → render_metrics 展示实时数据(当前客流 12,000、各区域排队时长) → render_chart(chart_type="line") 展示今日客流量趋势(预测下午 3 点高峰) → render_html 展示热门项目排队时间排行(红绿标注) ``` --- ### 8.10 制造 & 工业行业 #### 场景 1:生产监控大屏 Agent 实时展示产线状态和异常告警。 ``` 厂长: "1 号产线今天的情况怎么样?" Agent: → render_metrics 展示 KPI(产量、良品率、设备 OEE、停机次数) → render_multi_chart 展示: - 每小时产量趋势(折线图) - 不良品分类(饼图) - 各工位效率对比(柱状图) - 设备温度仪表盘(gauge) ``` #### 场景 2:设备维保管理 展示设备健康状态,支持一键报修。 ``` 维保工程师: "哪些设备需要保养了?" Agent: 查询设备系统 → render_html 渲染设备列表(状态灯:绿/黄/红) → render_chart(chart_type="bar") 展示各设备距下次保养的剩余天数 工程师: 点击某设备 → Agent 展示维保记录 + 零件清单 → render_html 渲染"创建工单"按钮 → 点击后自动创建维保工单 ``` #### 场景 3:质检报告可视化 质检数据自动生成可视化报告,支持导出。 ``` 质检员: "生成今天的质检报告" Agent: 查询质检数据 → render_multi_chart 展示各检测项合格率、SPC 控制图 → render_html 渲染质检报告摘要(含不合格批次明细表格) → static-hosting 生成 PDF 格式报告,提供下载 URL ``` --- ### 8.11 IT & 运维行业 #### 场景 1:服务监控仪表盘 在对话中实时展示系统运行状态。 ``` 运维: "生产环境现在状态怎么样?" Agent: → render_metrics 展示关键指标(在线实例 12/12、P99: 230ms、错误率 0.02%) → render_multi_chart 展示 CPU/内存/QPS/错误率四宫格图表 → render_url 嵌入 Grafana 面板查看更多细节 ``` #### 场景 2:故障排查向导 Agent 引导运维人员逐步排查问题。 ``` 运维: "用户反馈页面加载很慢" Agent: Step 1 → ask_user 选择受影响的服务(API/Web/DB) Step 2 → Agent 查询日志 → render_chart 展示该服务近 1 小时响应时间 Step 3 → 发现 DB 慢查询 → render_html 渲染慢查询 Top 10 表格 Step 4 → ask_user 选择处理方式(添加索引 / 重启连接池 / 扩容) Step 5 → Agent 执行 → render_metrics 展示恢复后的指标 ``` #### 场景 3:CI/CD 流水线管理 在对话中创建和监控部署流水线。 ``` 开发者: "帮我配一个新的部署流水线" Agent: → ask_user 选择代码仓库和分支策略 → ask_user 选择构建环境(Node 20 / Python 3.12 / Go 1.22) → ask_user 选择部署目标(dev / staging / prod) → render_html 展示生成的 YAML 配置预览 → 用户确认 → Agent 调 API 创建 → render_html 展示流水线状态时间轴 ``` --- ### 8.12 场景速查表 | 行业 | 典型场景 | 核心工具组合 | |------|---------|-------------| | 电商零售 | 商品浏览、比价、订单追踪、营销看板、退换货 | render_html + ask_user + render_chart | | 教育培训 | 在线测验、学习看板、代码练习、选课、知识图谱 | ask_user + render_chart + render_html | | 金融财务 | 投资分析、财报可视化、风控审批、报销管理 | render_multi_chart + render_metrics + render_html | | 医疗健康 | 健康趋势、问诊引导、预约挂号 | render_chart + ask_user + render_html | | 企业办公 | OA 审批、团队看板、招聘管理、会议投票 | ask_user + render_metrics + render_chart | | 房产生活 | 房源对比、餐厅预约、装修追踪 | render_html + render_chart + ask_user | | 物流供应链 | 运输追踪、库存预警、补货管理 | render_html + render_metrics + render_chart | | 旅游酒店 | 行程规划、酒店对比、景区实时信息 | render_html + render_chart + render_url | | 制造工业 | 产线监控、设备维保、质检报告 | render_multi_chart + render_metrics + render_html | | IT 运维 | 服务监控、故障排查、CI/CD 管理 | render_metrics + render_multi_chart + ask_user | ## 9. FAQ ### Q: MCP App 和 static-hosting 有什么区别? | 维度 | MCP App | static-hosting | |------|---------|----------------| | 渲染位置 | 聊天窗口内(iframe) | 独立浏览器 Tab | | 生命周期 | 临时,随对话存在 | 持久化,有独立 URL | | 交互能力 | 双向(postMessage) | 单向(只展示) | | 适用场景 | 对话内交互组件 | 报告、网页、可分享内容 | ### Q: HTML App 是每次重新加载还是缓存的? HTML App 模板是通过 `resources/read` 获取的静态文件,Host 可以缓存。但每次 `tools/call` 的数据是动态的,通过 postMessage 实时传入。 ### Q: 用户交互结果如何回传给 Agent? HTML App 通过 `window.parent.postMessage({type: 'mcp-app-response', payload: ...})` 发送,Host 接收后将 payload 作为工具调用结果传回 Agent,Agent 可以据此继续对话。 ### Q: 安全性如何保证? - HTML App 运行在 **sandboxed iframe** 中,无法访问主页面 DOM - 使用 `postMessage` 通信,有明确的消息协议 - 不执行任意远程代码,HTML 模板是预定义的静态文件 ### Q: 我能用 React/Vue 来写 HTML App 吗? 可以,但建议将构建产物打包为单个 HTML 文件(inline CSS/JS)。因为 `resources/read` 返回的是一个完整的 HTML 字符串,不支持多文件加载。也可以用 CDN 引入框架(如示例中 ECharts 用了 CDN)。 ### Q: PrePrompt Hook 是做什么的? PrePrompt 钩子在每次对话开始前执行,将 `usage_guide.md` 的内容注入到 Agent 的 system prompt 中。这让 Agent 知道有哪些工具可用,以及什么时候应该调用它们。**这是让 Agent "学会"使用 UI 工具的关键。** --- ## 附录:参考资源 - 项目内 mcp-ui 源码:`skills/common/mcp-ui/` - 项目内 data-dashboard 源码:`skills/common/data-dashboard/` - 项目内 static-hosting 定义:`skills/support/static-hosting/SKILL.md` - MCP UI 社区项目:[github.com/idosal/mcp-ui](https://github.com/idosal/mcp-ui) - MCP 协议规范:[modelcontextprotocol.io](https://modelcontextprotocol.io)