← 返回列表
未验证
在沙箱 iframe 中渲染 MCP 交互卡片并桥接工具调用
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/11 · 已提供中文文档
DeepSeek Harness 的 MCP Apps Host 插件:在沙盒 iframe 中从 MCP _meta.ui 渲染交互式 HTML 卡片,将 postMessage 桥接到 MCP tools/call 和 resources/read
综合分
30.3
GitHub 分
30.3
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add oriliz/dsh-mcp-apps-host该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-invariants@deepseek-ai/dsh-tools@deepseek-ai/dsh-util-values@deepseek-ai/dsh-subprocess@deepseek-ai/dsh-timeout@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-client-ui-chat@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-tool@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-client-locale@deepseek-ai/cordis用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
DSH MCP Apps Host
DeepSeek Harness 的 MCP Apps Host 插件。连接到声明了 io.modelcontextprotocol/ui 扩展的 MCP 服务器,在工具结果中保留 _meta.ui,在沙箱化 iframe 中渲染交互式 HTML 卡片,并在卡片与 MCP 服务器之间桥接 postMessage。
功能特性
- 保留 _meta 的工具发现 —— 注册的 MCP 工具完整保留 _meta.ui 载荷
- 交互式 HTML 卡片 —— 沙箱化 iframe 渲染,每张卡片独立 CSP
- postMessage 桥接 —— ui/initialize、tools/call、resources/read、ui/update-model-context、ui/message
- 结果重放通知 —— 在 ui/initialize 回复之后,宿主按 FIFO 顺序发送 ui/notifications/tool-input 和 ui/notifications/tool-result;新规范卡片忽略 lastToolResult,仅订阅这些通知,因此延迟挂载的卡片(重放 / 注入会话)仍能恢复工具结果
- 会话 ID 注入 —— 自动将 session_id 注入卡片发起的 tools/call
- 不可见上下文注入 —— ui/update-model-context 上下文通过 agent.inject() 作为插件来源消息注入,归类为折叠的上下文行(而非可见的用户消息气泡)
- HTTP 桥接端点 —— /mcp-apps//bridge,用于安全的 iframe 到 MCP 服务器代理(为直接请求它的沙箱化卡片启用 CORS)
- 桥接调试日志 —— GET /mcp-apps//debug 返回最近 64 次桥接交换;桥接调用绕过 agent 管道,永远不会到达会话 JSONL,因此此端点是唯一可观察卡片发起的 tools/call 的地方
- 多实例安全 —— 每个插件实例注册自己的按服务器桥接路由,因此多个 MCP Apps 服务器可以在一个 DSH 配置中共存
- stdio + streamable-http —— 支持两种 MCP 传输类型
演示
对话中携带嵌入式卡片的工具结果如下所示:
MCP Apps 演示卡片
截图展示了捆绑演示服务器(demo/server.mjs —— 零依赖,仅 Node stdio)的两张卡片:
- demo_interactive(内联形式):工具结果携带 _meta.ui.resource.text,因此卡片 HTML 随结果一起传输。其按钮演练了完整的桥接往返:一次刷新卡片的 tools/call(宿主自动注入 session_id),以及 ui/update-model-context + ui/message 回传给模型。
- demo_referenced(引用形式):工具定义携带 _meta.ui.resourceUri(ui://demo/referenced-card);宿主通过 resources/read 解析一次 HTML 并将其内联。该卡片还演示了桥接的 ui:// 安全门 —— 对 file:///etc/passwd 的读取会被拒绝。
试一试:
Protocol-level self-check: spawns the demo server over stdio and asserts
the handshake, both card forms, session_id echo, and the ui:// resource
table(8 项检查,无需 DSH)。
node demo/selftest.mjs
完整 E2E:启动带 demo overlay 的 dsh web,然后让模型调用
demo_interactive 和 demo_referenced。从本仓库的父目录运行
(overlay 的 server 路径相对于 cwd);或者调整 overlay 中的 !!js 路径
以匹配你的目录结构。
dsh web --patch dsh-mcp-apps-host/demo/mcp-apps-demo.cordis.yml
安装
尚未发布到 npm —— 请从 GitHub 安装。DSH 宿主在运行时提供所有 @deepseek-ai/dsh- peer 包,因此无需安装 peer:
npm install github:oriliz/dsh-mcp-apps-host
从源码构建
所有 dsh peer 包都在 deepseek-harness pnpm workspace 内解析,因此请在那里构建(这也与打包的 lib/ 的构建目录结构一致):
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
git clone https://github.com/oriliz/dsh-mcp-apps-host.git packages/mcp/mcp-apps-host
pnpm install
npx tsc -b packages/mcp/mcp-apps-host
pnpm --filter @deepseek-ai/dsh-mcp-apps-host bundle
用法
1. 配置连接
在 overlay 中为每个 MCP Apps 服务器声明一个插件实例(serverName 同时决定工具前缀 mcp____ 和桥接路径 /mcp-apps//bridge)。可直接编辑的模板位于 examples/connect-server.patch.yml:
- insert:
- id: mcp-apps-host-my-server
name: '@deepseek-ai/dsh-mcp-apps-host'
config:
transport: stdio
serverName: my-server
command: my-apps-server
args: []
env: {}
cwd: ''
toolCallTimeoutMs: 60000
也支持带 url 字段的 transport: streamable-http。
2. 启动 DSH
dsh --profile web --patch ./examples/connect-server.patch.yml
3. 验证
让 agent 调用你服务器上的某个工具。工具结果会在对话中渲染为交互式卡片,而不是普通的结果行 —— 并且卡片自身的按钮会通过桥接回连到你的服务器(tools/call、resources/read、ui/message)。手头没有服务器?先用打包的 demo。
架构
架构
工具结果从左到右流动(服务器 → 工具注册表 → 对话 → 卡片),卡片交互则通过 HTTP 桥接回环到服务器。卡片 HTML 永远不会进入模型上下文,桥接只允许 iframe 调用该服务器上注册的工具并读取 ui:// 资源。
文件
| 文件 | 作用 |
|------|------|
| src/index.ts | 服务端:MCP 连接、工具注册、HTTP 桥接 |
| src/client/McpAppCard.tsx | 卡片组件:iframe、postMessage 处理 |
| src/client/index.ts | 客户端插件:slot 注册、sendUserMessage |
| src/invariant.ts | Cordis 配套文件(无运行时 invariant) |
| demo/ | 零依赖 demo 服务器 + 协议自测 + overlay |
| examples/ | 连接覆盖模板 |
开发
构建
npx tsc -b packages/mcp/mcp-apps-host/tsconfig.json
pnpm --filter @deepseek-ai/dsh-mcp-apps-host bundle
使用插件运行 DSH
dsh --profile web --patch ./examples/connect-server.patch.yml --port 8089
已修复的陷阱
| # | 问题 | 修复 |
|---|-------|-----|
| P0 | 服务器剥离 _meta.ui | 在客户端能力中声明 mimeTypes |
| P1 | 卡片渲染但不显示工具数据 | presentationMeta() 将结果包装为 CallToolResult 形状的对象 |
| P2 | session_id 注入失败 | readSessionId() 优先使用 meta.lastToolResult.structuredContent |
| P3 | 外部图片被 CSP 阻止 | buildCsp() 将 https: 添加到默认的 img-src |
| P4 | ui/update-model-context 是 TODO | _stagedContext Map 存储并前置上下文 |
| P5 | 上下文作为用户消息文本可见 | ui/inject-context 桥接通过 agent.inject() 以插件来源消息注入 |
有关详细的根本原因分析,请参阅 FINDINGS.md。
许可证
MIT扫码进群