qwen_agent/docs/mcp-app-training.md
2026-05-23 13:53:10 +08:00

1064 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 AppsIframe 沙盒模式):
┌──────────────────────┐
│ 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. **灵活度优先**:我们的场景需要渲染各种复杂 UIECharts 图表、自定义表单、任意 HTMLMCP 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": "<html>...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
<!DOCTYPE html>
<html>
<head>
<!-- 样式 + 依赖库(如 ECharts CDN -->
</head>
<body>
<div id="root"></div>
<script>
(function () {
// 1. 定义渲染函数
function render(payload) {
// 根据 payload 数据渲染 UI
}
// 2. 监听来自 Host 的数据消息
window.addEventListener('message', function (event) {
var msg = event.data;
if (msg && msg.type === 'mcp-app-data') {
render(msg.payload);
}
});
// 3. 发送就绪信号
window.parent.postMessage({ type: 'mcp-app-ready' }, '*');
})();
</script>
</body>
</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 ServerPython
```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
#### 场景 1OA 审批流程
请假、采购、出差等审批在对话中一键完成。
```
员工: "帮我请三天年假"
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 展示恢复后的指标
```
#### 场景 3CI/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 作为工具调用结果传回 AgentAgent 可以据此继续对话。
### 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)