SuperAPI AI 工具集

ui-testing-harness

测试与质量

查看项目

更新于 10-16 06:08

技能介绍

用途

这是一个用于在本地测试或调试智能体 UI(Agent UI)的技能,核心场景是排查 MCP 应用(如 ui:// 资源、iframe 组件)在宿主中不显示、渲染异常或行为不符预期的问题。它强调“四个层级、按需攀爬”,即只在 bug 需要时才上升到更高的验证层级。

主要能力

1. 协议层 —— MCP Inspector

在任何渲染问题之前,先确认服务器发出的结构是否正确。使用命令:

npx @modelcontextprotocol/inspector

按顺序检查:

  • resources/list 中包含你的 ui://… URI。
  • 该资源的 mimeType 必须精确为 text/html;profile=mcp-app。
  • 资源 contents[0]._meta.ui.csp 存在且范围收窄。
  • tools/list 中,渲染工具带有 _meta.ui.resourceUri,而数据工具不带。
  • 调用工具时同时返回 content(文本)和 structuredContent。

大多数“组件不显示”的问题都在这一层就被发现。如果 Inspector 中没有显示 _meta.ui.resourceUri,任何宿主都不会渲染。

2. 渲染层 —— basic-host

ext-apps 仓库提供了一个最小宿主,能挂载 iframe 并说真实的 bridge 协议。

# 你的服务器
npm run build && npm run serve            # → http://localhost:3001/mcp

# 宿主,从 ext-apps 检出目录运行
cd examples/basic-host && npm install
SERVERS='["http://localhost:3001/mcp"]' npm start   # → http://localhost:8080

Windows PowerShell:

$env:SERVERS='["http://localhost:3001/mcp"]'; npm start

从下拉菜单中选择你的工具,调用它,观察 View 是否挂载。这一层可以捕获 bridge bug、CSP 拦截和生命周期顺序错误。

每次修改 UI 后都要重新构建——服务器从磁盘读取 dist/mcp-app.html,过期的 bundle 会静默地提供旧 View。

3. 真实宿主 —— 隧道接入

npx cloudflared tunnel --url http://localhost:3001

拿到生成的 https://<name>.trycloudflare.com URL 后进行注册:

  • Claude —— Settings → Connectors → Add custom connector。需要付费计划(Pro、Max 或 Team)。
  • ChatGPT —— 在开发者模式下连接 MCP 服务器。
  • M365 Copilot —— VS Code 中的 Agents Toolkit(6.12.0+),然后访问 https://m365.cloud.microsoft/chat。需要先添加 CORS 与重定向 URI 白名单,参见 m365-copilot-packaging。

只有真实宿主才能暴露宿主特有的缺口,例如 window.openai API 未定义、frameDomains 条目被忽略、显示模式未被授予等。

4. 埋点

iframe 的控制台往往不在你正在看的位置,在某些宿主中甚至完全不可达。

app.sendLog({ level: "info", data: { phase: "tool-result", keys: Object.keys(sc) } });

sendLog 在 M365 Copilot 中不受支持,需要保留回退:

function log(level: string, data: unknown) {
  try { app.sendLog?.({ level, data }); } catch { /* noop */ }
  if (new URLSearchParams(location.search).has("debug")) console.log(level, data);
}

一个 ?debug 查询参数可以显示屏幕上的日志面板,在无法使用 devtools 的宿主中调试时非常值得。

值得自动化的断言

无需宿主即可进行单元测试:

  • 服务器结构:直接调用工具处理函数,断言 structuredContent 符合其 schema,且 content[0].text 非空(纯文本回退)。
  • 资源结构:断言 mimeType、ui:// 协议,且 csp 只列出预期来源。
  • 工具/资源接线:断言只有渲染工具带有 resourceUri,且每个被引用的 URI 都解析到已注册资源。
  • 载荷校验:向 View 的解析器输入畸形和超大 structuredContent,断言它渲染错误状态而非崩溃。
  • 能力降级:把 window.openai 打桩为 {},断言不渲染任何依赖宿主的交互元素。

本插件中的 scripts/validate-mcp-app.mjs 会对服务器源码树静态执行前三项,可在 CI 中运行。

桥接层集成测试:驱动无头 iframe,向它发送 ui/notifications/tool-result,断言 DOM。当组件超过一个状态后就值得做。

排查对照表

症状 可能原因 检查项
完全没有组件 工具缺少 _meta.ui.resourceUri Inspector tools/list
没有组件但工具带该字段 URI 不匹配任何已注册资源 Inspector resources/list
iframe 空白 资源未内联,或不在 resourceDomains Network 面板 / CSP 违规
能加载但没数据 处理函数在 connect() 之后注册 把处理函数移到 connect() 之前
所有请求失败 CSP 写在配置参数里,而非 contents 的 _meta 在 Inspector 中读取资源
组件不断重挂载 数据工具带有 resourceUri 解耦数据/渲染工具
本地可用,Copilot 中空白 组件宿主 URL 未被 CORS 允许 Widget Host URL Generator
按钮无反应 宿主 API 未定义 getHostCapabilities() / 真值守卫
全屏被忽略 模式不在 availableDisplayModes 中 从被授予的模式渲染
活跃会话中仍是旧 UI 破坏性变更后复用了资源 URI 发布新的 ui:// URI
serve 时 import 语法错误 缺少 "type": "module" package.json
嵌套嵌入空白 宿主不支持 frameDomains 内联或降级为链接

相关内容

  • mcp-apps-sdk —— 构建配置与失败模式清单。
  • host-capability-matrix —— 各宿主的预期能力。
  • m365-copilot-packaging —— Copilot 的前置条件。

适用场景与限制

该技能适用于在本地调试 MCP 应用 UI、排查组件不显示或渲染异常、验证服务器协议结构、以及在真实宿主中定位宿主特有缺口。限制在于:需要已构建的 MCP 服务器与相应工具链;部分宿主(如 Claude 添加自定义连接器)需要付费计划;M365 Copilot 需要特定版本的工具包并配置 CORS 与重定向 URI 白名单;sendLog 在 M365 Copilot 中不可用。