内容
# UI调试器MCP
> 一个自主调试UI的MCP服务器 —— 让编写应用程序的AI也能测试它,无需人工逐一点击每个流程。
## 问题
AI编码代理(Claude等)非常擅长编写代码,但它们不擅长**判断UI是否实际工作**。对于后端代码,有单元测试和集成测试;对于UI,仍然需要人工打开应用程序,登录,点击操作,并报告问题。这种人工介入的流程很慢,很枯燥,并且在整个产品由AI构建时成为主要的瓶颈。
## 想法
通过MCP服务器消除UI调试循环中的人工干预。
- 一个**智能代理**(Claude Code,Cursor等)完成拉取请求(PR)并希望验证UI。
- 它向此服务器提交一个**任务**:"在网页上,登录并执行X、Y、Z —— 告诉我是否出现问题。"
- 一个**小型快速代理**在该服务器内运行(通过Vercel AI SDK)。它驱动浏览器或桌面,监控控制台和网络,拍摄截图。
- 它将**结构化的发现结果**反馈回去:通过/失败,哪里出现问题,证据。
- 智能代理修复代码并再次请求。**循环直到UI工作正常。**
与[playwright-mcp](https://github.com/microsoft/playwright-mcp)的区别在于 —— 在那里,智能模型自己发出每一个点击操作 —— 而在这里,智能模型保持在高层次,并将整个点击循环委托给小型代理。
## 与playwright-mcp的区别
| | playwright-mcp | UI调试器MCP |
|---|---|---|
| 点击操作 | 智能模型,每个操作一次调用 | 小型代理,独立操作 |
| 暴露的工具 | 许多(点击,输入,截图……) | 少数(提供任务,获取结果) |
| 智能模型成本 | 高(频繁交互) | 低(高层次交互) |
| 输出 | 原始页面状态 | 结构化的发现结果 + 证据 |
## 架构 —— 三个参与者
想象一个**老板**,一个**快速盲驱动员**,和一个**带有眼睛的描述者**:
```
┌─────────────┐ MCP对话 ┌──────────────────────────────────────┐
│ 智能代理 │ start_debug ───────▶ │ UI调试器MCP服务器 │
│ (Claude) │ send_message (live) │ │
│ │ ◀─────── get_findings │ ┌────────────┐ ┌────────────┐ │
│ 设置目标 │ │ │ 快速代理 │ 看│ 视觉描述者 │ │
│ 修复代码 │ │ │ (驱动员) │────▶│ (眼睛) │ │
│ 循环 │ │ │ deepseek │◀────│ glm 5v │ │
└─────────────┘ │ │ 文本·盲 │ 描述│ 图片 │ │
▲ │ └─────┬──────┘ └────────────┘ │
│ "有效 + 看起来不错" │ 观察 / 操作 (SQL-like) │
│ 发现结果 + 截图 │ │ 共享适配器合约 │
└──────────────────────────────│─────────┼─────────────────────────────│
└─────────┼─────────────────────────────┘
▼
┌──────────────┬──────────────┬──────────────┐
│ 网页(CDP) │ 桌面 │ 安卓 │
│ 浏览器 │ X11/Wayland │ ADB │
└──────────────┴──────────────┴──────────────┘
```
- **智能代理** —— 老板(Claude/调用者)。发送目标,读取发现结果,**修复代码**,循环。保持高层次 —— 从不点击。
- **快速代理** —— 驱动员。快速,便宜,**仅限文本和盲操作**。在结构上运行点击循环(DOM / 无障碍树 / 视图层次)。默认:deepseek。
- **视觉描述者** —— 眼睛。**多模态**。驱动员调用`look`询问 *"看起来是否正确?按钮是否居中?"* 并获得描述。默认:glm。只有在需要视觉判断时才会花费。
一个目标:**UI有效且看起来不错。** 完整设计见[`docs/idea/`](docs/idea/)。
每次运行都保留截图并将它们缝合成一个短的**带字幕的重播视频** —— Claude将其附加到PR上,以便审查者在约10秒内看到流程正常运行([`docs/idea/workspace.md`](docs/idea/workspace.md#pr-replay-video))。
## 目标
一个项目可以暴露多个调试目标。一个大型应用程序可以拥有这三个目标:
| 目标 | 协议 / 如何驱动 | 读取 |
|---------|--------------------------------------------------|-------|
| 网页 | **CDP** (Chrome DevTools协议),默认无头 | DOM |
| 桌面 | **X11 / Wayland** 输入 + AT-SPI | 无障碍树 / 视觉 |
| 移动 | **ADB** (uiautomator + screencap),安卓 | 视图层次 / 视觉 |
三个适配器,一个共享合约。每个运行**托管**(服务器启动目标)或**附加**(通过`cdpUrl` / `adbSerial`连接到正在运行的目标)。
Linux优先。iOS在Linux上超出范围(macOS专用工具)。
## 设置
像任何本地MCP服务器一样安装 —— 在`.mcp.json`中添加一个条目:
```jsonc
{
"mcpServers": {
"ui-debugger": {
"command": "npx",
"args": ["-y", "@developerz.ai/ui-debugger-mcp"],
"env": {
"OPENAI_API_KEY": "sk-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1"
}
}
}
}
```
然后添加一个项目特定的`.ui-debugger-mcp.json`,描述要调试的应用程序(模型,目标,网址)。最快的方法是`init`命令:
```bash
npx @developerz.ai/ui-debugger-mcp init # 在项目根目录中
```
**`ui-debugger-mcp init`** 为调试搭建项目(在[`docs/idea/config.md`](docs/idea/config.md)中描述):
- 创建工作空间目录`./tmp/ui-debugger-mcp/`
- 如果不存在,写入一个起始`.ui-debugger-mcp.json`(默认deepseek/glm模型,一个`web`目标存根)
- 将`tmp/`添加到`.gitignore`
- 打印`.mcp.json`片段以粘贴(它从不写入API密钥)
配置文件:
- `.mcp.json` → **如何启动**服务器(命令 + 秘密密钥)。Gitignored。
- `.ui-debugger-mcp.json` → **如何调试此应用程序**(模型,目标)。已提交。
服务器读取**当前目录**以选择项目会话 —— 在您的仓库中打开它,它会调试该仓库。
## 快速入门
```bash
# 1. 搭建项目(在应用程序根目录中运行一次)
npx @developerz.ai/ui-debugger-mcp init
```
这会创建`./tmp/ui-debugger-mcp/`,写入起始`.ui-debugger-mcp.json`,并打印`.mcp.json`片段以粘贴。
```jsonc
// 2. 粘贴到项目的.mcp.json中(添加您的API密钥)
{
"mcpServers": {
"ui-debugger": {
"command": "npx",
"args": ["-y", "@developerz.ai/ui-debugger-mcp"],
"env": {
"OPENAI_API_KEY": "sk-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1"
}
}
}
}
```
```jsonc
// 3. 编辑.ui-debugger-mcp.json —— 设置应用程序的URL
{
"targets": {
"web": { "adapter": "browser", "url": "http://localhost:3000" }
}
}
```
```text
// 4. 在Claude Code(或任何MCP客户端)中:
start_debug { target: "web", goal: "登录并将项目3添加到购物车" }
// 5. 轮询直到完成:
get_findings { session_id: "...", wait: true }
// 6. 读取bugs[] + visual[] + summary。修复代码,重复。
```
## 使用它
这是一个**对话**,不是远程控制 —— 五个工具,不是一个点击:
| 工具 | 它做什么 |
|------|--------------|
| `start_debug` | 打开运行:`{ target, goal, criteria?, timeout? }`。小型代理自主驱动。返回`{ session_id }`。 |
| `get_findings` | 轮询状态 + 结构化发现结果(功能性错误 + 视觉问题)+ 证据。长轮询`wait`。 |
| `send_message` | 在运行中与代理对话 —— 添加工作,重定向或回答问题。 |
| `describe` | 列出为此项目配置的目标 + 模型。 |
| `end_session` | 关闭运行,释放浏览器/配置文件。 |
运行**总是有限时**:`start_debug`的`timeout`(秒)覆盖默认300秒,因此会话永远不会挂起太久 —— 当上限触发时,它会自动结束并释放配置文件锁定。
智能代理的典型循环:
```text
start_debug { target: "web", goal: "登录并将项目3添加到购物车" }
→ 轮询get_findings(wait)直到状态为passed | failed
→ 读取bugs[] + visual[] + summary,修复代码,start_debug再次
```
您也可以使用`claude -p`从脚本驱动它无头模式 —— 请参阅[`docs/claude/SKILL.md`](docs/claude/SKILL.md)获取CLI配方(MCP配置,允许的工具,输出格式)。
### CLI — 检查或停止运行
`ui-debugger-mcp`二进制文件兼作活动运行的控制CLI(读取`state.json`,无需API密钥):
```bash
ui-debugger-mcp status # 哪个运行活动,服务器pid,判决,查找计数
ui-debugger-mcp stop # 正常结束运行(释放浏览器 + 配置文件)
```
## 故障排除
**找不到Chrome**
Web适配器通过系统PATH启动Chrome。安装Chrome/Chromium,或在`.ui-debugger-mcp.json`中设置`executablePath`:
```jsonc
"web": { "adapter": "browser", "url": "...", "executablePath": "/usr/bin/chromium-browser" }
```
**会话锁定 — "另一个运行活动"**
一个Chrome配置文件 = 一个运行。如果以前的运行崩溃且未清理:
```bash
npx @developerz.ai/ui-debugger-mcp stop # 正常关闭
```
或删除`./tmp/ui-debugger-mcp/state.json`并重启MCP服务器。
**运行超时且无发现结果**
默认上限为300秒。提高每次调用:
```text
start_debug { target: "web", goal: "...", timeout: 600 }
```
如果代理在登录处卡住,请在应用程序的登录路由中添加`?debug-ai=true`(由`ALLOW_AI_DEBUG_LOGIN`控制)以跳过验证码 —— 请参阅`CLAUDE.md`获取模式。
**`get_findings`返回空`bugs[]` / `visual[]`**
运行可能仍在进行中 —— 使用`wait: true`:
```text
get_findings { session_id: "...", wait: true }
```
检查`./tmp/ui-debugger-mcp/<project>/logs/agent.log`获取代理的跟踪。
**未生成`replay.mp4`**
ffmpeg是可选的。安装它并重试,否则忽略 —— 发现结果和截图仍然可用。
## 技术栈
- **Bun** + **TypeScript** (作为npm发布,运行via `npx`/`bunx`)
- **Vercel AI SDK** —— 代理循环(快速驱动器 + 视觉描述器)
- **任何OpenAI兼容路由器** (OpenRouter默认)—— 按角色交换模型。默认值:**deepseek** (文本)驱动,**glm** (图像)查看。
- **CDP** 网页,**X11/Wayland** 桌面,**ADB** 安卓
- stdio MCP传输
## 状态
所有三个适配器都已在v1中发布:
| 目标 | 状态 |
|---------|-------|
| 网页 | ✅ 已发布(CDP,无头 + 附加) |
| 桌面 | ✅ 已发布(X11/Wayland,AT-SPI + xdotool) |
| 安卓 | ✅ 已发布(ADB,uiautomator) |
重播视频(`replay.mp4`,带字幕的静态图像 → ffmpeg生成mp4)与网页适配器一起发布。ffmpeg是可选的 —— 如果没有,它会正常退出,但发现结果仍然可用。
参见[`docs/idea/`](docs/idea/)获取设计笔记。
## 文档
- [`docs/idea/overview.md`](docs/idea/overview.md) —— 问题 + 想法
- [`docs/idea/architecture.md`](docs/idea/architecture.md) —— 系统设计
- [`docs/idea/adapters.md`](docs/idea/adapters.md) —— 适配器合约 + 目标
- [`docs/idea/desktop-control.md`](docs/idea/desktop-control.md) —— Linux控制工具(X11/Wayland/移动)
- [`docs/idea/agent-loop.md`](docs/idea/agent-loop.md) —— 故事 → 发现结果循环
- [`docs/idea/mcp-tools.md`](docs/idea/mcp-tools.md) —— 两层工具,SQL-like参数,存储库内提示
- [`docs/idea/models.md`](docs/idea/models.md) —— 三个参与者(智能代理 / 快速代理 / 视觉描述器)
- [`docs/idea/config.md`](docs/idea/config.md) —— 配置文件
- [`docs/idea/workspace.md`](docs/idea/workspace.md) —— 项目特定空间 + 日志
- [`docs/claude/SKILL.md`](docs/claude/SKILL.md) —— 将`claude`用作无头CLI工具(通用)
- [`CLAUDE.md`](CLAUDE.md) —— 使用此存储库工作的AI代理的说明
## 致谢 / 影响
- [`ai-task-master`](../ai-task-master) —— 构建模板(编排器 + 子代理)
- [`gold-standards-in-ai`](../gold-standards-in-ai) —— MCP和代码约定
- [`claude-code-bible`](../../sebyx07/claude-code-bible) —— 代理优先模式
- [模型上下文协议](https://modelcontextprotocol.io/docs/develop/connect-local-servers)