跳到主要内容

Chrome DevTools MCP — 总览

30 秒导读: chrome-devtools-mcp 是一个 MCP server——它把一个真实运行的 Chrome 浏览器包装成一组 AI coding agent(Claude、Cursor、Copilot、Gemini CLI……)能直接调用的工具。 agent 说"点这个按钮""量一下这页的加载性能",server 就用 Puppeteer 驱动 Chrome 去做, 并把结果(文本快照、性能洞察、网络/控制台数据)结构化地回传。一句话:给大模型装上一套 能开车的手,外加一整套 Chrome DevTools 的仪表盘。

本章只讲全景与路由:这是什么、大盘怎么转、一次调用怎么走、该按什么顺序读后面各章、 以及全库的代码地图。具体实现都在 01–06 章,本章不深入。


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

一句话定义

MCP(Model-Context-Protocol,模型上下文协议) 是一套让大模型客户端调用外部"工具"的 标准协议。chrome-devtools-mcp 就是一个说这套协议的 server:它对外暴露几十个工具 (clicknavigate_pagetake_snapshotperformance_start_trace……),内部用 Puppeteer 驱动一个真实 Chrome,并复用 Chrome DevTools 前端自己的引擎去做性能分析、Lighthouse 审计、内存堆快照。

解决什么问题 / 给谁用

写代码的 AI agent 用。以前 agent 只能"读你的代码、猜网页长什么样";装上这个 server 后, 它能真的打开浏览器、操作页面、看到真实的 DOM 和网络请求、量真实的性能数字——从"纸上谈兵" 变成"能上手调试"。README 顶部的 Key features 概括为三条能力:

能力白话底层
Get performance insights录性能 trace,提炼可执行的优化建议复用 DevTools 的 trace 引擎
Advanced browser debugging看网络请求、截图、读控制台(带 source-map 栈)CDP + DevTools
Reliable automation自动化点击/输入,并自动等待动作生效Puppeteer

(以上三条摘自 README.md 的 "Key features" 一节。)

用起来什么样

在 MCP 客户端里加一段配置,server 就通过 npx 拉起(README.md 的 Getting started):

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

然后对 agent 说一句自然语言就能触发(README 的"Your first prompt"):

Check the performance of https://developers.chrome.com

客户端会调用 performance_start_trace 等工具,server 打开浏览器、录一段性能 trace 并回传报告。

一个重要直觉: server 连上时不会立刻开浏览器;只有当某个工具真的需要浏览器时, 才惰性启动 Chrome(见 README.md 的 NOTE,以及 02 章getContext)。

一句话类比

把它想成给大模型的"遥控 Chrome + DevTools 面板":模型发指令,一只机械手(Puppeteer) 去操作真浏览器,同时一整套原厂仪表盘(DevTools 引擎)把发生的事读回来给模型看。


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

一张全景图

下面这张图从左到右就是一次工具调用的数据流:MCP 客户端在最左,真实 Chrome 在最右, 中间是本项目的部件。怎么读: 请求向右流入、经过一把串行锁(Mutex)后落到某个工具, 工具借 Puppeteer 操作 Chrome;响应经 McpResponse + 各 formatter 组装后向左回传。

┌────────────┐ MCP 协议(stdio / JSON-RPC)
│ MCP 客户端 │ Claude / Cursor / Copilot / Gemini CLI …
│ (LLM) │
└─────┬──────┘
│ tools/call

┌───────────────────────┐
│ StdioServerTransport │ bin/chrome-devtools-mcp-main.ts
│ + McpServer │ index.ts: createMcpServer
└─────────┬─────────────┘
│ 每个工具注册一个回调

┌───────────────────────┐ ┌──────────────┐
│ ToolHandler │◄────►│ Mutex(串行)│ 一次只跑一个工具
│ 门控/校验/计时/组装 │ └──────────────┘
└─────────┬─────────────┘
│ getContext()

┌───────────────────────┐ ┌───────────────────────┐
│ McpContext │─────►│ McpPage(每个标签页) │
│ 浏览器+多页+路径沙箱 │ │ uid 定位 / 自动等待 │
└─────────┬─────────────┘ └──────────┬────────────┘
│ │ Puppeteer Browser
▼ ▼
┌───────────────────────────────────────────────────────┐
│ 真实 Chrome 浏览器 │
│ ← PageCollector 按导航分桶采集(网络/控制台/issue) │
│ ← 复用 chrome-devtools-frontend 的 trace / 堆快照引擎 │
└───────────────────────────────────────────────────────┘

▼ 响应向左回传
┌───────────────────────┐
│ McpResponse + formatters │ 文本快照 / 性能洞察 / 网络 / 控制台
└───────────────────────┘

部件一句话职责

部件干什么文件
进程入口解析参数、装 stdio 传输、连 server、注册优雅退出src/bin/chrome-devtools-mcp-main.ts
装配createMcpServerMcpServer、建 Mutex、把每个工具注册进去src/index.ts
工具定义defineTool / definePageTool 声明每个工具的 schema + handlersrc/tools/ToolDefinition.tssrc/tools/*
请求生命周期ToolHandler 做分类门控、参数校验、串行加锁、计时、错误兜底、响应组装src/ToolHandler.ts
上下文McpContext 持有 Puppeteer Browser、管理多页、路径沙箱、trace 存储src/McpContext.ts
页面McpPage 包一个标签页:uid→元素解析、快照持有、自动等待入口src/McpPage.ts
文本快照TextSnapshot 把无障碍树压成带稳定 uid 的文本,让模型"看见"页面src/TextSnapshot.ts
自动等待WaitForHelper 在动作后等导航/DOM 稳定,让操作"真的落地"src/WaitForHelper.ts
响应McpResponse 收集声明("我要附快照/网络/截图"),最后统一组装成文本+图src/McpResponse.ts
采集PageCollector 监听页面事件,按主框架导航把网络/控制台/issue 分桶src/PageCollector.ts
DevTools 复用third_party/index.tschrome-devtools-frontend、Lighthouse、Puppeteer 统一再导出src/third_party/index.ts

3. 主线走一遍(高层,不进代码)

拿最典型的一个动作——click(uid)——端到端追一遍。这条主线串起了后面每一章:

  1. 客户端发请求。 MCP 客户端发 tools/call { name: "click", arguments: { uid } }, 经 StdioServerTransport 进入 McpServer,落到该工具注册的回调 (src/index.ts:186toolHandler.handle)。

  2. 串行加锁。 ToolHandler.handle 先做分类门控和参数校验,然后 await this.toolMutex.acquire()(src/ToolHandler.ts:208)——同一时刻只允许一个工具在跑, 避免并发操作同一个浏览器互相踩踏。详见 01 章

  3. 解析出目标页。 getContext() 惰性拿到 McpContext(必要时才启动/连接浏览器), 再取当前选中的 McpPage(getSelectedMcpPage,或按 pageId 路由; src/ToolHandler.ts:239)。详见 02 章

  4. uid → 真实元素。 click 工具用 request.page.getElementByUid(uid) (src/tools/input.ts:109)把模型给的稳定 uid 查回一个 Puppeteer ElementHandle—— uid 来自上一次文本快照。详见 03 章

  5. 动作 + 自动等待。 动作被包进 page.waitForEventsAfterAction(() => handle.asLocator().click()) (src/tools/input.ts:114-125):Puppeteer 的 Locator 先等元素可交互再点,点完再等导航/DOM 稳定。详见 04 章

  6. 重新快照 + 组装响应。 工具只是声明 response.includeSnapshot() (src/tools/input.ts:133);真正的重拍快照发生在 McpResponse.handle 里 (src/McpResponse.ts:600,TextSnapshot.create),连同网络/控制台等一起组装成文本回传。 详见 05 章

  7. 回传 + 解锁 + 计时。 handle 返回 CallToolResult,finally 里记一条遥测并 guard.dispose() 释放 Mutex(src/ToolHandler.ts:307-314),下一个工具才能进来。


4. 巧妙之处清单(指向各章)

这些是读完全库该带走的"精华"。每条只点破妙在哪,细节看对应章。

  • 稳定 uid 复用 —— 让模型能可靠"点中"元素。 快照给每个节点发 ${snapshotId}_${idCounter} 形式的 id(src/TextSnapshot.ts:85),模型据此下指令; server 再把 uid 映射回真实元素句柄(src/McpPage.ts:471 getElementByUid)。 → 03 章

  • 声明式响应 —— 工具不自己拼字符串。 工具只调用 response.includeSnapshot() / setIncludeNetworkRequests()声明想要什么,最终由 McpResponse.handle 统一组装、 统一重拍快照(src/McpResponse.ts:579)。→ 05 章

  • 自动等待 —— 每个动作后等 DOM/导航稳定。 WaitForHelper 用可配置的 "DOM 稳定 N 毫秒"策略(src/WaitForHelper.ts:29-30)避免"点完就读到旧页面"。 → 04 章

  • 按导航分桶采集 —— 网络/控制台不串味。 PageCollector 监听 framenavigated, 在主框架导航时切一个新桶(src/PageCollector.ts:74),让每次导航的数据互不污染。 → 05 章

  • 复用真实 DevTools 引擎 —— 不重造性能分析。 直接 import chrome-devtools-frontend/mcp/mcp.js(src/third_party/index.ts:88)和 Lighthouse (:74-82),把 DevTools 面板背后的 trace/堆快照/审计逻辑当库用。→ 06 章

  • 串行 Mutex —— 一次只跑一个工具。 一把进程级锁(src/index.ts:165, src/ToolHandler.ts:208)把并发工具调用排成队,避免争抢同一浏览器。→ 01 章


5. 阅读地图(建议顺序)

由浅入深,建议按 01 → 06 顺序读;每章一句话主题:

顺序章节一句话主题
101-tool-model.md工具怎么被定义、分类门控、ToolHandler 如何串行地跑完一次请求
202-browser-context-pages.md浏览器怎么 launch/connect,McpContext/McpPage 怎么管多页与路径沙箱
303-snapshot-uid.md文本快照与 uid 定位模型:agent 如何"看见"并"点中"页面
404-autowait-input.md自动等待与输入动作:让每个操作可靠落地
505-response-collectors.md声明式响应组装(McpResponse)与按导航分桶采集(PageCollector)
606-devtools-power.md复用真实 DevTools 引擎:性能 trace、Lighthouse、内存堆快照

新手路径: 只想快速理解"agent 怎么操作网页" → 读 §3 主线 + 03 + 04 章即可。 想吃透架构: 01 → 02 打底,再 03/04/05,最后 06。


6. 全库代码地图(导航索引)

三列表,给人和 agent 直接跳源码。行号 as-of sourceCommit;优先用符号名 grep(抗行号漂移)。

主题文件关键符号
进程入口 / stdio 传输 / 优雅退出src/bin/chrome-devtools-mcp-main.tsparseArgumentsStdioServerTransportserver.connectshutdown
装配 server / 注册工具 / 建 Mutexsrc/index.tscreateMcpServerregisterToolgetContexttoolMutex
请求生命周期 / 门控 / 串行 / 计时src/ToolHandler.tsToolHandlerhandlegetToolStatusInfobuildFlag
工具定义骨架src/tools/ToolDefinition.tsdefineTooldefinePageToolpageIdSchematimeoutSchema
工具集合(全部工具聚合)src/tools/tools.tscreateTools
输入动作(click 等)src/tools/input.tsclickclickAtselectNativeSelectOptionhandleActionError
分类与默认开关src/tools/categories.tsToolCategoryOFF_BY_DEFAULT_CATEGORIESlabels
浏览器 launch / connectsrc/browser.tsensureBrowserLaunchedensureBrowserConnectedcloseBrowser
上下文 / 多页 / 路径沙箱 / trace 存储src/McpContext.tsMcpContextfromgetSelectedMcpPagegetPageById
页面 / uid→元素 / 自动等待入口src/McpPage.tsMcpPagegetElementByUidgetAXNodeByUidwaitForEventsAfterAction
文本快照 / 稳定 uidsrc/TextSnapshot.tsTextSnapshotcreateidToNodesnapshotId
自动等待src/WaitForHelper.tsWaitForHelperwaitForEventsAfterAction#stableDomFor
声明式响应组装src/McpResponse.tsMcpResponsehandleincludeSnapshotappendResponseLine
按导航分桶采集src/PageCollector.tsPageCollectorgetDataframenavigated
串行锁src/utils/Mutex.tsMutexacquireGuard.dispose
DevTools/Lighthouse/Puppeteer 再导出src/third_party/index.tsDevToolssnapshotnavigationMcpServer
性能工具src/tools/performance.tsperformance_start_traceperformance_stop_traceperformance_analyze_insight
Lighthouse 工具src/tools/lighthouse.tslighthouse_audit
内存堆快照src/HeapSnapshotManager.tssrc/tools/memory.tsHeapSnapshotManagertake_heapsnapshot

同步提示(给维护者): 上表锚定的都是函数/类/常量这类稳定符号。上游更新后若这些文件 未被改动,本章结论仍成立,只需重盖 sourceCommit;若只是行号漂移,按符号重新定位即可。