Claude Code + chrome-devtools MCP:安装部署与实战全记录
实测环境快照:
chrome-devtools-mcpv1.7.0,Chrome 151.0.7922.172,Node v25.8.2,npm 11.11.1。CLI 参数表按npx chrome-devtools-mcp@latest --help实测输出整理,非凭记忆罗列。该包高频迭代,引用前请复核--help。
一句话结论
chrome-devtools MCP 把一个真实的 Chrome交给 Claude Code:能导航、能在页面里执行任意 JS、能截图、能改视口、能读控制台和网络。它同时解决两类问题——联网取资料(替代不可靠的搜索工具)和前端调试闭环(本机真机验证,不用人肉点浏览器)。
1. 为什么需要它:web-search 的真实失败形态
先把数据摆出来。扫本机全部 Claude Code transcript(~/.claude/projects/**/*.jsonl)统计联网类工具调用:
| 工具 | 调用次数 | 硬失败(is_error) | 返回体含错误信号 |
|---|---|---|---|
mcp__web-search__web_search | 2 | 2 | — |
mcp__web-search__web_page | 1 | 0 | — |
内置WebSearch | 49 | 0 | 11(403 / timed out / failed 等) |
内置WebFetch | 25 | 0 | 0 |
两次web-search硬失败的报错完全一样:
Error performing web search after 3 attempts: No search results parsed for query "ARM64 branch out of range 128MB ___clang_call_terminate libGameAssembly il2cpp 解决".Error performing web search after 3 attempts: No search results parsed for query ""branch out of range" arm64 "clang_call_terminate" Unity il2cpp order_file fix".这里有个容易搞错的因果。直觉上会归因于「代理不稳 / 网络抖动」——全局配置确实给 web-search 挂了HTTPS_PROXY=http://127.0.0.1:7897。但错误不是ECONNREFUSED、不是ETIMEDOUT,是No search results parsed:HTTP 请求走通了,拿回了页面,解析器在返回的 HTML 里没找到结果节点。重试 3 次全一样。典型成因是搜索引擎返回了反爬页 / 同意页 / 改版后的 DOM,scraper 的选择器失效。
所以真正的痛点不是"经常连不上",而是:
搜索链路会在长尾技术查询上静默返回空,且失败点恰好是最需要联网的时刻——
__clang_call_terminate、branch out of range这种带下划线符号名与引号精确匹配的查询,正是 Unity IL2CPP 出包排障(libGameAssembly 超 ARM64 分支寻址上限)的核心线索。
内置WebSearch的 49 次调用虽然没有硬失败,但 11 次返回体里带 403 / timed out / failed 字样——它返回的是搜索结果摘要 + 链接列表,摘要往往是几十字的截断片段。要读user_manual.md全文、要看 GitHub 仓库的 stars 与最后提交时间、要抓 CSDN 正文,摘要给不了。
chrome-devtools 凭什么绕过这些
| 维度 | 搜索类 MCP / WebSearch | chrome-devtools MCP |
|---|---|---|
| 取数方式 | 第三方 scraper 解析搜索结果页 | 真实 Chrome 渲染真实 URL |
| 反爬 / 同意页 | scraper 选择器一失效就返回空 | 用你的登录态与 profile,人能打开它就能打开 |
| JS 渲染页 | 拿不到(SPA 内容在 JS 里) | 等 JS 跑完再取 DOM |
| 内容粒度 | 摘要片段 + 链接 | document.body.innerText全文,或 CSS 选择器精确切片 |
| 登录墙内资料 | 无解 | 复用已登录 profile(内网 wiki / DevOps 平台) |
| 私有地址 | 无解 | http://localhost:5173也能开 |
| 前端调试 | 不具备 | 截图 / 视口 / 控制台 / 网络 / 性能全都有 |
关键认知:它不是"更好的搜索",它是"跳过搜索"。已知 URL 时直接navigate_page到raw.githubusercontent.com/...,拿到的是原始 Markdown 全文,零解析损耗、零摘要截断。我的几篇技术梳理笔记都是这么产出的。
补充:不必二选一。实际工作流是
WebSearch找 URL → chrome-devtools 读全文。搜索负责发现,浏览器负责取证。
2. 安装部署
2.1 前置
| 项 | 要求 | 实测 |
|---|---|---|
| Node.js | ≥ 22(npx拉包) | v25.8.2 ✅ |
| Chrome | 装了就行;--autoConnect需144+ | 151.0.7922.172 ✅ |
| 包 | 无需全局装,npx -y每次拉 | v1.7.0(未全局安装,npm ls -g为空) |
2.2 配置写法
~/.claude.json→projects["<你的项目绝对路径>"].mcpServers:
"chrome-devtools":{"type":"stdio","command":"npx","args":["-y","chrome-devtools-mcp@latest","--autoConnect"],"env":{}}我在两个前端项目下各放了一份。都是项目级,全局没配——经验是"全局只放所有项目都要用的"。
命令行等价写法(更省事,不用手改 JSON):
claude mcpaddchrome-devtools--scopeproject -- npx-ychrome-devtools-mcp@latest--autoConnect⚠️文档漂移提醒:早期我用的是
--wsEndpoint ws://127.0.0.1:9222/devtools/browser/<id>,后来换成了--autoConnect。原因很实在:--wsEndpoint的 browser id 每次重启 Chrome 都会变,写死在配置里必然失效。网上的老教程多半还是--wsEndpoint写法,照抄会踩坑。
2.3 三种连接模式怎么选
这是部署时唯一需要想清楚的决策。
① 默认(不加连接参数)——服务器自己起一个干净 Chrome
"args":["-y","chrome-devtools-mcp@latest"]独立 profile($HOME/.cache/chrome-devtools-mcp/chrome-profile),不碰你日常浏览器。适合 CI、跑自动化。缺点:没有你的登录态。
②--autoConnect——接管已在跑的日常 Chrome(推荐)
需 Chrome 144+,且要在chrome://inspect/#remote-debugging里把远程调试开关打开一次。好处:
- 复用日常 profile 的登录态,内网 DevOps / 私有 wiki 直接能读
- 复用你已经开着的那些标签页,
list_pages+select_page直接切过去 - 不用管 debugging port 和会变的 browser id
③--browserUrl/--wsEndpoint——手动指定调试端点
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"\--remote-debugging-port=9222--user-data-dir=/tmp/cdp-profile"args":["-y","chrome-devtools-mcp@latest","--browserUrl","http://127.0.0.1:9222"]--browserUrl比--wsEndpoint稳(前者固定端口,后者的 browser id 每次重启都变)。适合远程 / 容器里的 Chrome。
选择建议:日常开发用
--autoConnect,需要干净环境或 CI 用默认模式,只有跨机器 / 容器才动--browserUrl。
2.4 验证
claude mcp list# 看到 chrome-devtools 且状态 connectednpx-ychrome-devtools-mcp@latest--help# 单独跑,确认包能拉起进 Claude Code 后让它list_pages,能列出标签页即通。
2.5 常用 CLI 参数(v1.7.0 实测)
按重要性排序,不是全表:
| 参数 | 作用 |
|---|---|
--autoConnect | 连本机已运行的 Chrome(144+) |
--browserUrl/-u | 连指定调试端点,如http://127.0.0.1:9222 |
--headless | 无 UI 模式,CI 用 |
--isolated | 临时 profile,关闭即清理 |
--channel | stable/beta/dev/canary |
--viewport 1280x720 | 初始视口 |
--proxyServer | 给 Chrome 挂代理(等价--proxy-server) |
--slim | 只暴露 3 个工具(导航 / 执行 JS / 截图),省 context |
--screenshotFormat webp--screenshotMaxWidth | 截图压缩降尺寸,显著省 context(JPEG/WebP 比 PNG 小 3-5 倍) |
--no-category-performance--no-category-network--no-category-emulation | 按类关掉不用的工具组,省 context |
--blockedUrlPattern/--allowedUrlPattern | 限制浏览器能访问的 URL(安全护栏) |
--redactNetworkHeaders | 脱敏网络请求头里的敏感字段 |
--no-usage-statistics | 关掉 Google 用量统计(默认开) |
--logFile /tmp/cdp.log | 配DEBUG=*出详细日志,报 bug 用 |
省 context 提示:29 个工具的 schema 会占掉可观的 context。只用来抓资料的话,
--slim+--screenshotFormat webp是性价比最高的两个开关。隐私提示:
--usageStatistics默认为true,Google 会收集用量数据(独立于 Chrome 自身的 metrics)。介意就加--no-usage-statistics,或设CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS环境变量。
3. 工具全表(v1.7.0,29 个)
| 分类 | 工具 |
|---|---|
| 页面/导航 | list_pagesselect_pagenew_pageclose_pagenavigate_pagewait_for |
| 观察 | take_snapshot(a11y 树,带 uid)take_screenshotevaluate_script |
| 输入交互 | clickhoverdragfillfill_formtype_textpress_keyupload_filehandle_dialog |
| 网络 | list_network_requestsget_network_request |
| 控制台 | list_console_messagesget_console_message |
| 模拟 | emulate(深色模式/地理位置/网络限速/CPU 降频/UA/额外请求头)resize_page |
| 性能/内存 | performance_start_traceperformance_stop_traceperformance_analyze_insighttake_heapsnapshotlighthouse_audit |
交互两步法
改页面状态要先take_snapshot拿uid,再把uid传给click/fill:
take_snapshot → 得到 uid=1_23 → click(uid: "1_23")take_snapshot返回 a11y 树(文本),比截图省 context 且能直接定位元素。优先 snapshot,不要习惯性截图。
实际调用分布
transcript 统计(全部项目累计):
| 工具 | 次数 |
|---|---|
evaluate_script | 34 |
navigate_page | 15 |
take_screenshot | 13 |
new_page | 6 |
resize_page | 5 |
list_pages | 5 |
take_snapshot | 2 |
select_page | 1 |
evaluate_script一家独大,是navigate_page的两倍多。说明主力用法不是"模拟用户点点点",而是"把浏览器当带 DOM 和渲染引擎的 REPL"——进页面里直接取数、算数、调 API。click/fill/fill_form一次没用过。这个分布值得记住:它决定了--slim模式(导航 + 执行 JS + 截图)几乎正好覆盖全部真实需求。
4. 实战场景
以下四个都是真实调用记录,不是构造示例。
4.1 抓官方文档全文
// 1) 先看仓库结构(这里用了 take_snapshot 读 a11y 树)navigate_page({url:"https://github.com/Tencent/InjectFix"})// 2) 直奔 raw 文件,拿原始 Markdown 全文——不走搜索、不要摘要navigate_page({url:"https://raw.githubusercontent.com/Tencent/InjectFix/master/Doc/user_manual.md",timeout:20000})evaluate_script({function:"() => document.body.innerText"})// 3) 同法取 faq.md / README.mdCSDN 这类正文外包着大量导航和广告的站,用选择器精确切片:
evaluate_script({function:`() => { const article = document.querySelector('#article_content, .article_content, #content_views, .markdown_views'); if (article) return article.innerText; return document.body.innerText.slice(0, 50000); }`})腾讯云文档(cloud.tencent.com/document/product/654/30316)是 JS 渲染的 SPA,WebFetch抓下来是空壳,浏览器里innerText一取就有。
要点:--slim就够;timeout: 20000给 raw.githubusercontent 留余量;先slice限长,避免一次灌爆 context。
4.2 PixiJS游戏 文本截断:在真实渲染引擎里复现测量
一个 PixiJS v8 的 H5 页面(本地localhost:5173)里,几处中文文案被截断。根因涉及CanvasTextMetrics的宽度测量与padding/stroke外扩——这是纯运行时数值问题,读代码看不出来。
做法是把 PixiJS 本体 import 进页面,直接构造TextStyle反复试参:
evaluate_script({function:`async () => { const m = await import('/node_modules/pixi.js/dist/pixi.mjs'); const { TextStyle, CanvasTextMetrics } = m; await document.fonts.ready; const msg = '提交失败,本次记录未计入榜单。'; const base = { fontFamily: 'MyCustomFont', fontSize: 48, fontWeight: '900', padding: 72, stroke: { color: '#4a4a8a', width: 5 } }; const metrics = CanvasTextMetrics.measureText(msg, new TextStyle(base)); return { width: metrics.width, height: metrics.height }; }`})还顺手用原生 CanvasmeasureText交叉验证 PixiJS 的测量值(ctx.font = '900 46px sans-serif'),确认 padding 该给多少。改完navigate_page({type:"reload"})+take_screenshot看结果。
要点:
await document.fonts.ready必须等——自定义字体没加载完,测出来的宽度是 fallback 字体的,全错。document.fonts.check('900 46px "MyCustomFont"')可显式确认。- 走 Vite 的
/node_modules/.vite/deps/...路径可能带 hash 失效,直连/node_modules/pixi.js/dist/pixi.mjs更稳。 - 项目里预留了一个
window.__appDev调试钩子(暴露getApp()/showPanel()之类入口),让 AI 能直接驱动页面状态。为 AI 调试留一个 dev hook,收益极高。
4.3 内嵌 WebView 关闭按钮多机型适配
用resize_page扫真机尺寸,逐个量按钮位置:
resize_page({width:390,height:844})// iPhone 12/13 竖屏resize_page({width:430,height:932})// iPhone 14 Pro Max 竖屏resize_page({width:932,height:430})// 横屏evaluate_script({function:`() => { const btn = document.querySelector('.webview-close-button'); if (!btn) return { found: false }; const r = btn.getBoundingClientRect(); const shell = document.querySelector('.app-shell'); const cs = getComputedStyle(shell); return { rect: r.toJSON(), shellTransform: cs.transform, shellW: cs.width }; }`})take_screenshot({filePath:"/tmp/close-btn-portrait.png",format:"png"})要点:截图落盘用filePath而不是回传 inline,能省大量 context——一张 PNG inline 回来动辄上万 token。
⚠️ 默认情况下,若 MCP client 没协商 roots 能力,写文件的工具被限制在系统临时目录。所以
/tmp/xxx.png一定能写,项目内相对路径可能被拒。真要写到项目里得加--allowUnrestrictedPaths(放宽了沙箱,谨慎)。
4.4 技术选型:抓仓库元数据做横评
做开源库横评时,stars / forks / 语言构成 / 最后提交时间这些动态渲染的数字,搜索摘要给不了,必须真浏览器渲染完再读。过程中还发现某个仓库从旧账号重定向到了新组织——这种重定向只有真实导航才会暴露。
5. 它还能干但我还没用上的
evaluate_script占了 8 成调用,说明这些能力基本闲置,而前端项目恰好用得上:
list_console_messages— 抓 JS 报错。比让用户手动开 DevTools 复制粘贴快得多,排 WebView 白屏 / WebGL 黑屏这类问题时尤其值。list_network_requests/get_network_request— 看接口实际请求响应,排"提交失败"这类问题直接得多。emulate—networkConditions: "Slow 3G"模拟弱网、cpuThrottlingRate模拟低端机、extraHttpHeaders注入测试 header。低端机卡顿类问题可以先在浏览器里复现。performance_start_trace+performance_analyze_insight— Core Web Vitals 与加载瀑布,首屏优化可用。take_heapsnapshot— 查 JS 内存泄漏。lighthouse_audit— 可访问性 / SEO / best practices 打分。
6. 坑与最佳实践
Context 消耗是首要问题。29 个工具的 schema + 截图 inline 回传能吃掉惊人的 context。对策:--slim、--screenshotFormat webp+--screenshotMaxWidth、截图用filePath落盘、优先take_snapshot而非take_screenshot、--no-category-*关掉不用的组。
--wsEndpoint的 browser id 会变。每次重启 Chrome 都换,写死在配置里必然失效。要手动指定就用--browserUrl http://127.0.0.1:9222。
--autoConnect要先手动开一次远程调试开关(chrome://inspect/#remote-debugging),且 Chrome 需 144+。
JS 里等异步。await document.fonts.ready、必要时wait_for({text: [...]})。§4.2 的字体测量踩过这个坑——字体没加载完,测量值全是 fallback 字体的。
evaluate_script返回值必须 JSON 可序列化。返 DOM 节点会失败,用rect.toJSON()/ 只挑字段返。
给项目留 dev hook。在window上挂一个 dev 命名空间,暴露几个驱动页面状态的入口,AI 就不用猜内部结构,调试效率差一个量级。
安全边界。接管日常 profile 意味着把你的全部登录态交给了 agent。敏感场景用--isolated起干净 profile,或用--allowedUrlPattern/--blockedUrlPattern限制可访问范围,--redactNetworkHeaders脱敏请求头(默认关)。别让它带着你的 SSO 会话去访问不该访问的内网系统。
别把它当搜索引擎。它没有"搜"的能力,只有"打开"的能力。正确工作流:WebSearch找 URL → chrome-devtools 读全文。