关于 ui-debugger-mcp
ui-debugger-mcp 是用于自动测试 Web、桌面和 Android 界面的 MCP 服务,面向希望让编码 Agent 验证应用流程的开发者。它把完整交互流程交给内部 Agent 执行,并返回结构化问题与证据,而非逐次控制点击。
主要功能
- 01按自然语言目标自主执行界面流程
- 02监控控制台和网络并截取画面
- 03报告功能缺陷与视觉问题
- 04支持 Web、桌面和 Android 目标
- 05保存截图及回放视频
适用场景
- 01验证登录后的应用操作流程
- 02检查页面渲染和视觉布局
- 03在提交代码前发现界面回归
- 04为代码审查提供流程回放证据
MCP 相关
MCP 服务向客户端提供启动调试、获取发现、发送消息、查看配置目标和结束会话等工具。测试证据通过结果和资源链接返回。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @developerz.ai/ui-debugger-mcpOPENAI_API_KEY密钥API key for the LLM provider (OpenRouter default)OPENAI_BASE_URLBase URL for the LLM provider (defaults to OpenRouter)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
UI 调试器 MCP
一个可自主调试 UI 的 MCP 服务,让编写应用的 AI 也能测试应用,无需人类逐个流程点击验证。
问题
AI 编码 Agent(Claude 等)很擅长编写代码,却不擅长 判断 UI 是否真的可用。对于后端代码,有单元测试和 集成测试。对于 UI,仍然需要人类打开应用、登录、四处点击, 再报告问题。产品完全由 AI 构建时,这种人工参与的流程既慢又枯燥, 也是主要瓶颈。
思路
通过 MCP 服务消除 UI 调试循环中的人工参与。
- 一个智能 Agent(Claude Code、Cursor,……)完成 PR 后,想要验证 UI。
- 它将一个故事交给此服务:“在 Web 上登录并执行 X、Y、Z——告诉我是否会出问题。”
- 一个小型快速 Agent 在此服务内部运行(通过 Vercel AI SDK)。它驱动 浏览器或桌面应用,监控控制台和网络,并截取屏幕截图。
- 它将结构化发现反馈回来:通过/失败、出错之处、证据。
- 智能 Agent 修复代码后再次请求。持续循环,直到 UI 正常工作。
与 playwright-mcp 不同——智能模型需要亲自发出每一次点击——在这里,智能模型只负责设定高层目标,并将整个点击循环交给小型 Agent。
与 playwright-mcp 的区别
| playwright-mcp | UI Debugger MCP | |
|---|---|---|
| 谁来点击 | 智能模型,每次调用执行一个操作 | 小型 Agent,自主执行 |
| 暴露的工具 | 很多(点击、输入、快照……) | 很少(提供故事,获取发现) |
| 智能模型成本 | 高(频繁交互) | 低(高层操作) |
| 输出 | 原始页面状态 | 结构化发现 + 证据 |
架构——三个角色
可以把它想象成一个老板、一个快速的盲人驾驶员,以及一个能看见的描述者:
┌─────────────┐ MCP conversation ┌──────────────────────────────────────┐
│ smart agent │ start_debug ───────▶ │ UI Debugger MCP server │
│ (Claude) │ send_message (live) │ │
│ │ ◀─────── get_findings │ ┌────────────┐ ┌────────────┐ │
│ sets goals │ │ │ fast guy │ look│ vision guy │ │
│ fixes code │ │ │ (driver) │────▶│ (eyes) │ │
│ loops │ │ │ deepseek │◀────│ glm 5v │ │
└─────────────┘ │ │ text·blind │ desc│ image │ │
▲ │ └─────┬──────┘ └────────────┘ │
│ "works + looks nice" │ observe / act (SQL-like) │
│ findings + screenshots │ │ shared adapter contract │
└──────────────────────────────│─────────┼─────────────────────────────│
└─────────┼─────────────────────────────┘
▼
┌──────────────┬──────────────┬──────────────┐
│ web (CDP) │ desktop │ android │
│ browser │ X11/Wayland │ ADB │
└──────────────┴──────────────┴──────────────┘
- 智能 Agent——老板(Claude/调用方)。发送目标、读取发现、修复代码,并继续循环。只负责高层操作——从不点击。
- 快速驾驶员——驾驶员。快速、廉价、仅处理文本且看不见。根据结构(DOM / a11y 树 / 视图层级)执行点击循环。默认使用 deepseek。
- 视觉助手——眼睛。具备多模态能力。驾驶员调用
look来询问*“这样看起来对吗?按钮居中吗?”*,并获取描述。默认使用 glm。仅在需要视觉判断时调用。
只有一个目标:**UI 既能正常工作,也足够美观。**完整设计见 docs/idea/。
每次运行都会保留屏幕截图,并将它们拼接成一段简短的带字幕回放视频——Claude 会将它附加到 PR 上,让审查者在约 10 秒内看到流程正常运行(docs/idea/workspace.md)。
目标
一个项目可以公开多个调试目标。大型应用可以包含以下全部三种目标:
| 目标 | 协议 / 驱动方式 | 读取内容 |
|---|---|---|
| Web | CDP(Chrome DevTools Protocol),默认无头运行 | DOM |
| 桌面应用 | X11 / Wayland 输入 + AT-SPI | a11y 树 / 视觉 |
| 移动端 | ADB(uiautomator + screencap),Android,默认无头运行 | 视图层级 / 视觉 |
三种适配器,共用一个契约。每种适配器都可采用托管模式(服务启动目标)或附加模式(通过 cdpUrl / adbSerial 连接到正在运行的目标)。
优先支持 Linux。Linux 上不支持 iOS(仅限 macOS 的工具)。
托管的 Android 运行会以无窗口模式启动模拟器——使用 -no-window 并搭配
-gpu swiftshader_indirect -no-audio,因为仅使用 -no-window 仍会打开主机 GL 上下文,并在没有显示器的机器上崩溃。在目标上设置 "headless": false,即可在窗口中查看运行过程;如需添加其他参数,请使用 emulatorArgs。
配置
像任何本地 MCP 服务一样安装——在 .mcp.json 中添加一项:
{
"mcpServers": {
"ui-debugger": {
"command": "npx",
"args": ["-y", "@developerz.ai/ui-debugger-mcp@latest"],
"env": {
"OPENAI_API_KEY": "sk-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1"
}
}
}
}
要接入多个仓库?.mcp.json 通常会提交到版本库,因此不要在每个仓库中粘贴密钥——在 shell 中导出一次并引用它,这样每个仓库的配置项都相同且不含密钥:
"env": {
"OPENAI_API_KEY": "${UI_DEBUGGER_API_KEY}",
"OPENAI_BASE_URL": "${UI_DEBUGGER_BASE_URL:-https://openrouter.ai/api/v1}"
}
它也已发布到官方 MCP Registry,名称为
io.github.developerz-ai/ui-debugger-mcp——任何会浏览注册表(而非手写 .mcp.json 配置项)的客户端,都可以通过该名称找到并安装它。
然后添加项目级配置,描述要调试的应用(模型、目标、网址)——如果仓库将 Agent 配置放在 .dz/ 下,则使用 .dz/ui-debugger/ui-debugger-mcp.json(优先检查);否则使用根目录下的 .ui-debugger-mcp.json(旧版)。
最快的方法是使用 init 命令:
npx @developerz.ai/ui-debugger-mcp@latest init # in your project root
ui-debugger-mcp init 会创建用于调试的项目框架(详见
docs/idea/config.md):
- 创建工作区目录
./tmp/ui-debugger-mcp/ - 写入初始配置(默认使用 deepseek/glm 模型,并包含
web目标占位配置),前提是该配置尚不存在——如果仓库已有.dz/目录,则写入.dz/ui-debugger/ui-debugger-mcp.json;否则写入根目录下的.ui-debugger-mcp.json - 将
tmp/添加到.gitignore - 输出供粘贴的
.mcp.json代码段(绝不会写入你的 API 密钥)
配置文件:
.mcp.json→ 如何启动服务(命令 + 密钥)。已加入 Git 忽略规则。.dz/ui-debugger/ui-debugger-mcp.json(或根目录下的.ui-debugger-mcp.json)→ 如何调试此应用(模型、目标)。会提交到版本库。如果两者都存在,则优先使用.dz/下的副本,工具会提示被忽略的根目录文件名称。
两个文件中的每个键都记录在 docs/idea/config.md 中;
每个工具的准确输入/输出格式都记录在 docs/idea/mcp-tools.md 中。
服务会读取当前目录来选择项目会话——在仓库中打开它,它就会调试该仓库。
快速入门
# 1. Scaffold the project (run once in your app's root)
npx @developerz.ai/ui-debugger-mcp@latest init
这会创建 ./tmp/ui-debugger-mcp/,写入初始配置(位于 .dz/… 或根目录),并输出供粘贴的 .mcp.json 代码段。
// 2. Paste into your project's .mcp.json (add your API key)
{
"mcpServers": {
"ui-debugger": {
"command": "npx",
"args": ["-y", "@developerz.ai/ui-debugger-mcp@latest"],
"env": {
"OPENAI_API_KEY": "sk-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1"
}
}
}
}
// 3. Edit the project config (.dz/ui-debugger/ui-debugger-mcp.json or root
// .ui-debugger-mcp.json) — set your app's URL
{
"targets": {
"web": { "adapter": "browser", "url": "http://localhost:3000" }
}
}
// 4. In Claude Code (or any MCP client):
start_debug { target: "web", goal: "log in and add item 3 to the cart", url: "http://localhost:3000" }
// 5. Poll until done:
get_findings { session_id: "...", wait: 30000 }
// 6. Read bugs[] + visual[] + summary. Fix code, repeat.
使用方法
这是一次对话,不是遥控器——提供五个功能全面的工具,而不是每次点击都用一个工具:
| 工具 | 功能 |
|---|---|
start_debug | 开始一次运行:{ target, goal, url?, as?, replace?, criteria?, timeout? }。当目标未配置网址时,必须提供 url;as 用于指定登录身份;replace: true 会接管已有运行的项目。小型 Agent 会自主执行。返回 { session_id }。 |
get_findings | 轮询状态、结构化发现结果(功能性错误 + 视觉问题)和证据。使用 wait 进行长轮询。读取整个对象时,每个列表最多返回 20 项,并在 truncated 中说明(每个字段包含 {returned, total})——传入 fields 可获取完整列表。 |
send_message | 在运行过程中与 Agent 对话——添加工作、调整方向或回答问题。 |
describe | 列出此项目配置的目标和模型——包括每个目标的身份验证 personas[] 和 notes——以及 session:此项目当前持有的运行会话。 |
end_session | 结束运行,释放浏览器/配置文件。 |
运行始终有时间上限:start_debug 的 timeout(秒)会覆盖默认值 300s,因此会话不会无限期挂起——达到上限时会自动结束并释放配置文件锁。
登录——命名身份
几乎所有有意思的界面都需要登录,而且每次都在 goal 字符串中重新解释登录流程,会在真正的目标开始前消耗驱动步骤。只需在目标中说明一次:
"targets": {
"dashboard": {
"adapter": "browser",
"url": "http://localhost:5173",
"auth": {
"admin": { "path": "/login", "fields": { "email": "[email protected]", "password": "admin" }, "submit": "Sign in" },
"user": { "path": "/login", "fields": { "email": "[email protected]", "password": "user" }, "submit": "Sign in" }
}
}
}
start_debug { target: "dashboard", as: "admin", goal: "open Audit and check the table renders" }
运行会在驱动程序执行第一步之前在带外完成登录:不消耗任何驱动步骤,凭据也不会进入模型的上下文——提示词只会得知*“你已以 admin 身份登录”*。运行写入的所有日志都会对凭据值进行脱敏;describe 只会报告身份名称。as 中的名称拼写错误时会明确报错并列出有效名称;如果登录失败,运行也会失败,而不会返回一个会把所有页面都报告为空的会话。请使用开发环境/种子凭据——此文件已提交。详情见
docs/idea/config.md。
说明预期——notes
刚完成迁移且没有种子数据的应用,到处都会显示空状态,而驱动程序会将*“表格为空”*报告为运行的主要错误。它说得没错,但毫无用处。只需在目标中说明一次预期:
"targets": {
"dashboard": {
"adapter": "browser",
"url": "http://localhost:5173",
"notes": "needs seeded data — empty tables are expected on /new\nfirst load shows an onboarding modal; dismiss it\ndark mode is the default theme"
}
}
每行一条事实,可用于任何目标(web、desktop、android)。与每次运行的 goal 不同,notes 是配置:它会作为单独的*“关于此应用的已知信息”*部分,仅组合进驱动程序的提示词一次——将这些内容视为预期结果,绝不要将其报告为缺陷;但与其矛盾的屏幕仍值得报告。
相同的前置条件也会传给独立的视觉模型,用于判断屏幕截图,因此已配置的预期空状态不会被归类为视觉缺陷——但与其矛盾的屏幕仍值得报告。
上限为 1000 个字符,加载配置时强制执行(每一步都会将包含这些内容的提示词重新发送给模型,因此在此处写长篇内容会按步骤付费)。
如果运行已处于打开状态
每个项目(cwd)只能运行一个会话,因此之前忘记调用 end_session 会导致会话卡住。现在不会了:describe 会报告此项目持有的运行(session: { id, status, goal }),因此丢失了 session_id 的调用方——例如上下文被压缩,或客户端重启——可以读取并关闭会话,也可以通过 start_debug({ …, replace: true }) 接管会话。
默认情况下仍会拒绝接管,拒绝信息会明确列出所有三个调用;若静默接管,会终止其他人正在查看的正常运行。
每个工具结果都同时包含格式化文本块和经过声明的 outputSchema 验证的类型化 structuredContent 载荷——请解析结构化内容,不要从文本中提取。工具还声明了 MCP 注解(readOnlyHint、destructiveHint、idempotentHint、openWorldHint),以便客户端正确渲染或控制调用;证据路径(截图、replay.mp4、日志)则以 resource_link 内容项的形式传递,而不是内联字符串。完整结构见
docs/reference.md。
智能 Agent 的典型工作循环:
start_debug { target: "web", goal: "log in and add item 3 to the cart" }
→ poll get_findings (wait) until status is passed | failed
→ read bugs[] + visual[] + summary, fix the code, start_debug again
你也可以通过 claude -p 从脚本以无头模式驱动它——命令行配置示例(MCP 配置、允许的工具、输出格式)见
docs/claude/SKILL.md。
一次运行会捕获的内容(Web)
你会获得发现结果,但 Agent 提供的证据才是让这些结果变得可执行的关键:
| HTTP | 完整的请求与响应——方法、url、状态、durationMs,以及 fetch/xhr 的请求和响应正文与标头。4xx 会附带服务器给出的具体原因({"error":"password too short"}),而不只是状态码。凭据标头值会被隐藏为 <redacted, N chars>:其存在仍可用于诊断,但密钥绝不会进入模型、日志或对话记录。 |
| DOM | 角色、名称、边界、表单控件的实时 value/checked、data-testid,以及每个文本节点的 WCAG 对比度——因此,“复选框是否已勾选?”和“这段文本是否清晰可读?”都能通过结构化信息得到解答,无需消耗视觉资源。 |
| iframes | 也会读取嵌入式文档。节点带有 frame,其边界使用页面坐标,因此点击操作与其他位置的点击操作相同。 |
| Tabs | 会检测到点击 target="_blank" 后打开的新标签页,并可继续跟进,而不是将其识别为“什么也没发生”。 |
| Console | 错误和未捕获的异常,以及源代码位置。 |
| Frames | 每项操作都会截取一张有序的屏幕截图,并拼接成 replay.mp4。 |
静态资源不会显示在默认的网络读取结果中——在 Vite 开发服务器上,静态资源的数量约为真实 API 调用的 15 倍——同时会显示隐藏资源的数量,并提供查看它们的筛选条件。无论请求类型如何,失败的请求都不会被隐藏。
CLI — 检查或停止一次运行
ui-debugger-mcp 二进制文件也可用作当前运行的控制 CLI(读取 state.json,无需 API 密钥):
ui-debugger-mcp status # which run is active, server pid, verdict, finding counts
ui-debugger-mcp stop # gracefully end the run (frees the browser + profile)
故障排除
未找到 Chrome
Web 适配器通过系统 PATH 启动 Chrome。请安装 Chrome/Chromium,或在项目配置(.dz/… 或根目录)中设置 executablePath:
"web": { "adapter": "browser", "url": "...", "executablePath": "/usr/bin/chromium-browser" }
会话已锁定 — “another run is active” 一个 Chrome 配置文件只能运行一个任务。如果之前的运行崩溃且未清理:
npx @developerz.ai/ui-debugger-mcp@latest stop # graceful teardown
或者删除 ./tmp/ui-debugger-mcp/<project>/state.json 并重启 MCP 服务。
运行超时且没有发现 默认上限为 300 s。可针对单次调用调高:
start_debug { target: "web", goal: "...", timeout: 600 }
如果 Agent 卡在登录页面,请在应用的登录路由中添加 ?debug-ai=true(由 ALLOW_AI_DEBUG_LOGIN 控制),以跳过验证码 — 请参阅 CLAUDE.md 中的实现模式。
get_findings 返回空的 bugs[] / visual[]
运行可能仍在进行中 — 使用 wait(ms)进行长轮询:
get_findings { session_id: "...", wait: 30000 }
查看 ./tmp/ui-debugger-mcp/<project>/sessions/<id>/logs/agent.log 中 Agent 的执行记录。
会话 ID 是本地时间戳(2026-07-27_14-30-05-0001),因此最新的一次运行排在最后。只保留最近 5 个会话 — 每次新运行都会清理其余会话,因此按设计,六次之前运行的证据会被删除。
运行立即失败:“… is not a valid model ID”
项目配置中的模型字符串不是目录 ID。OpenRouter 使用 provider/model,可选路由后缀为 :floor / :nitro — #… 后缀会被直接拒绝。请使用纯 ID(deepseek/deepseek-v4-flash)。
升级后仍在运行旧版本
npx -y <pkg> 在存在缓存安装时会重用它,因此 .mcp.json 中仅写 "@developerz.ai/ui-debugger-mcp" 会继续启动最初安装到 ~/.npm/_npx 的版本 — 且不会提示版本已过时。没有自动更新:服务不会检查软件包注册表。请在 args 中指定 @latest(现在 init 会输出此配置),这样每次冷启动都会重新解析版本:
"args": ["-y", "@developerz.ai/ui-debugger-mcp@latest"]
已经卡住了?运行 rm -rf ~/.npm/_npx,然后重新连接服务(在 Claude Code 中输入 /mcp)。运行 npx @developerz.ai/ui-debugger-mcp@latest --version 查看当前版本。
修改配置似乎没有生效
MCP 服务启动时只读取一次配置,因此修改不会影响正在运行的服务。从 v1.3 开始,如果文件已更改,服务会拒绝启动新运行,并提示你重新连接服务(在 Claude Code 中:/mcp → 重新连接 ui-debugger),而不是悄悄沿用旧设置。
“Another server already has a session”,但你看不到该会话
该运行属于同一项目中的另一个 MCP 服务进程。现在你可以读取它 — get_findings { session_id: "<the id in the error>" } 会提供其磁盘上的发现结果 — 因此你可以判断它是仍在运行,还是已结束、仅等待关闭。要接管该项目:ui-debugger-mcp stop。
运行以 failed 结束,没有错误且没有说明
这表示驱动程序从未调用 report — 它耗尽了全部步骤预算。摘要会明确说明这一点;这不是崩溃,也不是成功通过。请缩小目标范围,或调高 timeout。查看 logs/agent.log 和屏幕截图,了解它实际执行了什么。
未生成 replay.mp4
ffmpeg 是可选的。安装后重试,或忽略 — 没有它仍会生成发现结果和屏幕截图。
技术栈
- Bun + TypeScript(以 npm 包形式发布,通过
npx/bunx运行) - Vercel AI SDK — Agent 循环(快速驱动程序 + 视觉描述器)
- 任何兼容 OpenAI 的路由器(默认使用 OpenRouter)— 可按角色切换模型。 默认值:deepseek(文本)负责驱动,glm(图像)负责识别。
- Web 使用 CDP,桌面使用 X11/Wayland,Android 使用 ADB
- stdio MCP 传输
状态
三个适配器均已随 v1 发布:
| 目标 | 状态 |
|---|---|
| web | ✅ 已发布(CDP,无头 + 附加) |
| desktop | ✅ 已发布(X11/Wayland、AT-SPI + xdotool) |
| android | ✅ 已发布(ADB、uiautomator) |
Web 适配器附带回放视频(replay.mp4,带字幕的静态画面 → 通过 ffmpeg 合成为 mp4)。
ffmpeg 是可选的 — 缺少时会优雅处理,发现结果仍会生成。
设计说明请参阅 docs/idea/。
文档
docs/idea/overview.md— 问题 + 想法docs/idea/architecture.md— 系统设计docs/idea/adapters.md— 适配器契约 + 目标docs/idea/desktop-control.md— Linux 控制工具(X11/Wayland/mobile)docs/idea/agent-loop.md— 故事 → 发现的循环docs/idea/mcp-tools.md— 两层工具、类 SQL 参数、仓库内提示词docs/idea/models.md— 三个角色(智能 Agent / 快速助手 / 视觉助手)docs/idea/config.md— 配置文件docs/idea/workspace.md— 每个项目的空间 + 日志docs/claude/SKILL.md— 将claude作为无头命令行工具来驱动(通用)CLAUDE.md— 面向在此仓库中工作的 AI Agent 的说明
致谢 / 影响
ai-task-master— 构建模板(编排器 + 子 Agent)、参考仓库,未发布gold-standards-in-ai— MCP 和代码约定、参考仓库,未发布claude-code-bible— Agent 优先模式(sebyx07/claude-code-bible)- 模型上下文协议
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。