跳到主要内容

数据截至 (上游 commit fd0b7e1d9ed9)

Chrome DevTools MCP — 这是什么 / 全景 / 主线 / 阅读地图

30 秒导读: 这是 Google 官方出的一个 MCP server,让你的编码 agent(Claude Code、Cursor、Copilot…)开一台真 Chrome、操作它、并用 DevTools 的全部分析能力检查它。它的独到之处不在"能点按钮",而在给模型的东西是什么形态:页面是一棵带 uid 的无障碍树文本、性能问题是一句"LCP 3.2s,瓶颈在文档延迟"、网络和控制台是分页且可折叠的清单——而不是截图和几万行 JSON。


1. 这是什么(零基础也能懂)

一句话定义

chrome-devtools-mcp 是一个 MCP server(Model Context Protocol,模型上下文协议——一种让 LLM 客户端以统一方式调用外部工具的协议)。它对外暴露约 56 个工具,内部用 Puppeteer 通过 CDP(Chrome DevTools Protocol,Chrome 的远程调试协议)驱动一台真实 Chrome。

解决谁的什么问题

场景:你让 AI 改了一段前端代码,它说"改好了"。但它没看见页面——不知道按钮点下去报没报错、首屏为什么慢、那个请求是不是 404。

于是你要么自己去浏览器里验,要么给它接一个浏览器自动化工具。可普通自动化工具只能"点和抓 HTML",而排障需要的是 DevTools 那一套:性能面板、网络面板、控制台带 source map 的堆栈、内存快照。

这个项目要做的就是把后者整包搬到 agent 面前:

你想让 AI 干的事它给的工具
打开页面、点、填、拖、上传new_page / click / fill_form / drag / upload_file
看页面现在长什么样(结构)take_snapshot(文本无障碍树)、take_screenshot
查报错和网络list_console_messages / list_network_requests / get_network_request
查性能performance_start_trace / performance_analyze_insight / lighthouse_audit
查内存泄漏take_heapsnapshot / compare_heapsnapshots / get_heapsnapshot_retaining_paths
模拟弱网/慢 CPU/移动端emulate / resize_page

工具清单由脚本从真实 schema 生成,见 docs/tool-reference.md(56 个 ### 条目)。

用起来什么样

形态一:MCP server(给 agent 用)。在 MCP 客户端里加一段配置就完事:

{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
}
}
}

形态二:CLI(给人/给脚本用)。同一个 npm 包还装了第二个可执行文件 chrome-devtools(package.jsonbin 字段):

chrome-devtools new_page "https://example.com"
chrome-devtools take_snapshot
chrome-devtools click 1_12 # 1_12 是上一步快照里的 uid
chrome-devtools evaluate_script "() => document.title"
chrome-devtools stop

第一次调用会自动在后台拉起一个常驻进程,后续命令复用同一台浏览器(见 docs/cli.md 与本库第 7 章)。

快照长什么样(理解本项目的关键)

take_snapshot 返回的不是 HTML,而是一棵缩进的无障碍树文本,每行开头带一个 uid:

## Latest page snapshot
uid=1_0 RootWebArea "Example Domain"
uid=1_1 heading "Example Domain" level="1"
uid=1_2 paragraph
uid=1_3 link "More information..." focusable

(格式由 src/formatters/SnapshotFormatter.ts:39#formatNode 决定:两空格缩进 + uid= + role + "name" + 属性。)

然后 agent 说 click(uid="1_3")"模型指认元素"这件事,靠的是 uid,不是坐标、不是 CSS 选择器。

一句话直觉

可以这样建立心智模型:它把 DevTools 面板里那些给人看的图表,换成了给模型看的短文本结论——面板里那条 LCP 瀑布图,到了这里是一段"LCP 是 3.2 秒,主要花在文档延迟上"的文字。

(这只是入门直觉。下文所有术语都按字面意思用,不再打比方。)


2. 顶层全景(它大概怎么转)

静态结构

怎么读这张图:从上往下是一次请求穿过的层;左右两支是 ToolHandler 分别持有的"状态"和"输出"两个对象。

MCP 客户端(Claude Code / Cursor / Copilot …)
│ stdio,tools/call

┌────────────────────────────────┐
│ ① MCP server 壳 │ src/index.ts
│ 把 56 个工具注册进 SDK │
└───────────────┬────────────────┘
│ 每个工具包一层

┌────────────────────────────────┐
│ ② ToolHandler(一次调用的总控) │ src/ToolHandler.ts
└───┬────────────────────────┬───┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ ③ 状态层 │ │ ④ 输出层 │
│ McpContext / │ │ McpResponse │
│ McpPage │ │ + formatters │
└────────┬────────┘ └──────────────────┘

┌─────────────────────────────────────────┐
│ ⑤ Puppeteer → CDP → 真实 Chrome │
│ ⑥ devtools-frontend(trace/issue/heap) │
└─────────────────────────────────────────┘

部件一句话职责

部件干什么主文件
MCP server 壳McpServer、注册工具、握手时问客户端要 rootssrc/index.ts
ToolHandler一次调用的总控:加锁、备浏览器、跑 handler、渲染、埋点src/ToolHandler.ts
工具定义每个工具 = 名字 + 描述 + zod schema + 类别 + handlersrc/tools/*.tssrc/tools/ToolDefinition.ts
McpContext浏览器级状态:页面表、选中页、堆快照、路径沙箱src/McpContext.ts
McpPage页面级状态:快照、对话框、模拟设置、控制台/网络收集器src/McpPage.ts
McpResponse把 handler 打的"标记"统一变成文本 + 结构化内容src/McpResponse.ts
formatters快照/网络/控制台/issue/堆快照各自的文本与 JSON 格式src/formatters/*.ts
WaitForHelper动作之后等导航、等 DOM 不再变src/utils/WaitForHelper.ts
collectors按导航分段地攒控制台消息和网络请求src/collectors/PageCollector.ts
devtools 复用层直接 import 真 DevTools 前端的 trace 引擎等模块src/devtools/*src/third_party/index.ts
CLI + daemon把同一批工具变成命令行命令,后台常驻src/bin/chrome-devtools.tssrc/daemon/*

主线:一次 click 从请求到响应

不进代码,先看流程。这条线在第 1、3、4、5 章会被拆开细讲。

客户端 tools/call {name:"click", args:{uid:"1_3"}}

├─(1) ToolHandler 拒绝未知参数 → 直接返回可自愈的错误文案

├─(2) 抢全局互斥锁 ······ 同一时刻只允许一个工具在跑

├─(3) getContext() ······ 第一次调用才真正启动/连接 Chrome

├─(4) 校验参数里的文件路径(本工具没有,跳过)

├─(5) 取"当前选中页";若有未处理对话框,直接报错

├─(6) uid → ElementHandle → Puppeteer Locator.click()
│ └─ 包在 waitForEventsAfterAction 里:等可能的导航 + 等 DOM 静默

├─(7) handler 往 response 上打标记(成功文案、要不要附快照)

├─(8) McpResponse.handle():并行取快照/网络/控制台…,再统一渲染

├─(9) 返回 {content:[text, image?], structuredContent?}

└─(10) finally:上报一条脱敏后的遥测,释放锁

这条主线里有四个设计决定,是全项目的骨架:

  1. 浏览器是懒启动的——server 起来时不开 Chrome,第一次工具调用才开(src/index.ts:123getContext)。
  2. 全局串行——一把 Mutex 管住所有工具(src/index.ts:198),不存在两个工具同时操作同一个页面。
  3. handler 不拼字符串——它只在 response 上打标记,渲染集中在一处(第 4 章)。
  4. 动作自带等待——点击/输入之后要不要等,由 WaitForHelper 统一判断(第 5 章)。

3. 阅读地图

按下面顺序读,是一条由浅入深的完整路径:

顺序章节讲什么什么时候读
101-tool-definition.md工具的定义/注册/开关,ToolHandler.handle 十步想加一个工具、或想懂调用生命周期
202-context-and-pages.md启动还是接管浏览器、页面 id、路径沙箱关心多标签页、重连、文件安全
303-snapshot-and-uid.md无障碍树快照与 uid 的跨快照复用关心"模型怎么指认元素"
404-response-assembly.md声明式响应装配、分页、结构化输出关心 token 成本与输出格式
505-waiting-and-collectors.md自动等待与按导航分段的收集器关心自动化稳定性
606-devtools-reuse.md复用真 DevTools 的 trace/issue/heap 能力关心性能与内存分析怎么来的
707-cli-and-daemon.md一份定义生成 MCP 工具 + CLI + 文档,后台 daemon关心工程化与多形态分发
808-deep-dive-and-boundaries.md巧妙之处、边界、横向对比、总代码地图想带走精华 / 做技术选型

赶时间的话: 读本页 + 第 3 章 + 第 4 章,就能讲清楚这个项目最独特的那部分(给模型什么形态的页面表示,以及怎么控制输出体积)。


4. 代码地图(入口级)

主题文件路径符号名
MCP server 组装src/index.tscreateMcpServerregisterToolgetContext
进程入口(stdio)src/bin/chrome-devtools-mcp-main.tsshutdownStdioServerTransport
一次调用的总控src/ToolHandler.tsToolHandlerhandlegetToolStatusInfo
工具定义原语src/tools/ToolDefinition.tsdefineTooldefinePageToolBaseToolDefinition
工具汇总src/tools/tools.tscreateTools
浏览器状态src/McpContext.tsMcpContextcreatePagesSnapshotvalidatePath
页面状态src/McpPage.tsMcpPagegetElementByUidemulate
响应装配src/McpResponse.tsMcpResponsehandleformat
版本/包信息package.jsonbinpeerDependencies