1064 lines
41 KiB
Markdown
1064 lines
41 KiB
Markdown
# 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": "<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 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)
|