Chrome-devtools-mcp:闭环Agent的自我验证
一、背景:AI 会写代码,但看不见自己的产物
用 AI 写代码(前端/后端)有一个长期的尴尬:它能生成几千行 Vue/Java/Python,却无法通过浏览器确认是否符合要求。
这就是缺口的本质:Agent 需要一个可以自己调用的浏览器。
二、选型:为什么不自己写,而用官方 MCP
有三条路:
| 方案 | 形态 | 代价 | 适合 |
|---|---|---|---|
| Playwright | 库 / MCP | 本体 ~50 MB + 浏览器 ~300 MB | 稳定的端到端测试、跨浏览器 |
| 自己写 CDP 驱动 | 脚本 | 零依赖,但功能要自己长 | 轻量验证(“打开看一眼”) |
| chrome-devtools-mcp | MCP server | 13.6 MB,复用本机 Chrome | Agent 的日常排查 |
三条都试过。先自己写了一个零依赖的 CDP 驱动(约 120 行,只用 Node 内置的fetch/WebSocket),它解决了"截图 + 量像素差异",但控制台和网络这两个最关键的证据它拿不到——因为那需要订阅 CDP 事件流并缓存消息,工作量和收益不成比例。
而chrome-devtools-mcp 是 Google Chrome 团队官方维护的 MCP server,把这些能力都做成了工具。它复用本机已装的 Chrome,不需要再下载一个浏览器。
结论:轻量验证继续用自己那 120 行;深度排查交给官方 MCP。两者互补,不冲突。
三、它给 Agent 的是什么:30 个工具
连接后,工具以mcp__chrome__<tool>的形式出现——和原生工具一样可直接调用。30 个工具分七类:
| 类别 | 工具 | 对 Agent 的意义 |
|---|---|---|
| 输入自动化 | clickfillfill_formhoverdragtype_textpress_keyupload_filehandle_dialog | 真的能操作页面:提交表单、走完整交互流程 |
| 导航 | new_pagenavigate_pagelist_pagesselect_pageclose_pagewait_for | 多标签页、wait_for文本出现(抗 flaky 的关键) |
| 调试 | take_snapshotevaluate_scripttake_screenshotlist_console_messagesget_console_messageget_css_styleslighthouse_auditscreencast_* | 无障碍快照 + 控制台 + CSS 级联 + Lighthouse |
| 网络 | list_network_requestsget_network_request | 请求清单、状态码、请求头、响应体(含 Cookie) |
| 性能 | performance_start_traceperformance_stop_traceperformance_analyze_insight | Core Web Vitals(LCP / INP / CLS)与瓶颈洞察 |
| 模拟 | emulateresize_page | 暗色模式、CPU/网络限速、地理位置、移动端视口 |
| 内存 | 14 个堆快照工具 | 内存泄漏:支配树、保留路径、重复字符串(需--memoryDebugging=true) |
其中真正改变工作方式的是这三个
1.list_console_messages—— 把"猜"变成"读"
以前页面出问题,Agent 只能列一堆可能原因让你去试。现在它直接告诉你第几行报了什么错。
2.take_snapshot—— 给 Agent 的"结构化页面"
它不是截图,而是无障碍树的文本快照,每个可交互元素带一个uid。这是给模型看的格式:token 消耗远低于截图,而且元素定位是稳定的(不像坐标会随布局变化)。
它的工具描述里写得很直白:“Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot.”
3.list_network_requests—— 接口层的唯一真相
"接口通了吗"不该靠猜。这一条列出来,状态码、请求头、响应体一清二楚。
四、接入:DSH 的 MCP 配置
安装只需要一步:
npminstall--globalchrome-devtools-mcpDSH 的 MCP 由@deepseek-ai/dsh-mcp-client提供(随 DSH 自带,不需要额外安装),配置文件是 profile 的 patch 层:
~/.dsh/profiles/desktop/cordis.patch.yml它接受一个YAML 数组,每条是一个 loader patch entry。追加这一条:
-insert:-id:mcp-chrome-devtoolsname:"@deepseek-ai/dsh-mcp-client"config:serverName:chrometransport:stdiocommand:"D:\\Installed\\Nodejs\\node.exe"args:-"C:\\Users\\xxx\\AppData\\Roaming\\npm\\node_modules\\chrome-devtools-mcp\\build\\src\\bin\\chrome-devtools-mcp.js"-"--headless=true"-"--userDataDir=D:\\ZHUWEI\\AppData\\.tmp\\chrome-devtools-mcp-profile"-"--executablePath=C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"-"--performanceCrux=false"-"--usageStatistics=false"# 首次接通期用 true:连接失败会让该插件激活报错、错误可见;harness 仍能启动# (app-boot 允许可选 MCP 配置项失败)。确认稳定后可改回 false。failOnStartupError:true字段含义:
| 字段 | 说明 |
|---|---|
serverName | namespace,工具名变成mcp__chrome__*。只能[A-Za-z0-9_-]{1,32},同一作用域内唯一 |
transport | stdio(本地程序)或streamable-http(远端服务) |
command | 必须是绝对路径 |
args | 传给 server 的旗标与路径 |
failOnStartupError | false:连不上只表现为"工具缺失",不阻塞 DSH 启动 |
五、成果:上线十分钟抓到两个真实缺陷
配置验证通过后,立刻拿它扫了一遍自己的页面。它当场报出两条此前完全不知道的消息:
msgid=1 [issue] A form field element should have an id or name attribute (count: 2) msgid=2 [error] Failed to load resource: the server responded with a status of 404 (Not Found) reqid=16 GET http://localhost:4173/favicon.ico [404]顺着get_console_message拿到的violatingNodeId: 4, 5,定位到两个表单控件(一个复选框、一个选择器)既没有id也没有name。
这两条都不影响功能,但:
favicon.ico的 404 是每个访客的控制台都会出现的瑕疵;- 表单控件缺
id/name会影响浏览器自动填充,也是无障碍审计会扣分的地方。
关键在于"发现成本":在这之前,要发现它们必须手动打开 DevTools、切到 Console 面板、自己看。而现在 Agent 每次验证都会顺带看到——这类问题再也不会默默攒着。
六、最后
- 只有 Chromium 系。要测 Safari / Firefox,得用 Playwright。
- 不是测试框架。它给的是"操作与证据",不含断言、重试、报告。要写稳定的端到端测试,仍应使用 Playwright Test 之类。
- 无法替人判断"好不好看"。它能证明"渲染在动、数值在变、布局正确、控制台干净",不能证明"设计得好"。汇报时必须说清是脚本测的,不能暗示"看过了"。
- 需要重启 DSH 生效。profile 的 patch 层是 Loader 自己读的入口清单,只在启动或下次组合时判定——当前会话拿不到新工具。
- 此后可以添加一个skill。通过skill让ai使用chrome-devtools-mcp工具验证结果,避免每次给ai用文字描述。
还有一条跨方案的盲区,与具体工具无关:
WebGL 默认
preserveDrawingBuffer: false。此时用drawImage(webglCanvas)读回的是已被清空的缓冲区——量出来"画面完全没动"是假阴性,比漏报更危险(会得出与事实相反的结论)。
任何浏览器自动化工具都有这个盲区,包括本文这个。读回全空白时必须报"无法测量",绝不要报"没动"。
愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!