chrome-devtools-mcp 实战:用 --wsEndpoint 与 adb 端口转发连接 Android 上的 Chrome 调试
本文基于仓库文档 debugging-android.md 展开,介绍如何把 chrome-devtools-mcp(Chrome DevTools for coding agents)MCP 服务器接入物理 Android 设备上的 Chrome:先通过 adb forward 将设备上的 DevTools 抽象 socket 映射到本机 9222 端口,再以 --wsEndpoint 参数让服务器直连该 WebSocket 端点。读完本文,你可以复现完整的六步接入流程、理解 --wsEndpoint 的校验规则与参数互斥关系,并能从源码层面解释“为什么 MCP 服务器不启动任何本地浏览器,却可以操控手机上的 Chrome”。
为什么标注为 Experimental
文档开篇明确说明这是一个实验性功能:
This is an experimental feature as Puppeteer does not officially support Chrome on Android as a target.
也就是说,Puppeteer 并不把 Android 版 Chrome 视为官方支持的目标平台,整套流程依赖的是“远程 DevTools 协议端口可被 adb 暴露”这一通用机制,而非任何针对 Android 的一等支持。这带来两个使用前提:
- 功能可能随上游(Puppeteer / Chrome for Android 的调试协议行为)变化而不稳定;
- 排障时应以 Android 端 DevTools 远程调试的官方排查步骤为准(文档指向 Chrome 官方 remote-debugging 文档的 Troubleshooting 章节,此处不重复给出外部链接)。
但正因为 MCP 服务器走的是“连接已存在的浏览器”而非“启动浏览器”的路径,该方案对绝大多数用户都能工作。
完整接入流程(六步工作流)
文档给出的工作流如下,按顺序执行即可。
第一步:开启开发者选项与 USB 调试
在 Android 设备上打开 Developer Options(开发者选项)界面,并选中 Enable USB Debugging。开发者选项默认隐藏,需要通过 Android Studio 的 on-device developer options 官方配置方式激活(关于文档中提到的官方配置页面,此处不重复外链)。
第二步:用 USB 数据线直连设备
将 Android 设备通过 USB 线缆直接连接到你的开发机。注意是直连,不要经过无线调试或第三方转发工具,这是保证 adb 通道稳定的关键。
第三步:配置 adb 端口转发
在开发机上执行:
adb forward tcp:9222 localabstract:chrome_devtools_remote
这条命令的作用是把本机的 TCP 端口 9222 转发到 Android 设备上的本地抽象 socket chrome_devtools_remote。Chrome for Android 在运行时会监听这个抽象 socket 提供 DevTools 协议服务,adb forward 把它桥接为开发机上的一个普通 TCP 端口,于是 ws://127.0.0.1:9222/... 就成了一个标准可达的 DevTools 端点。
第四步:配置 MCP 服务器使用 --wsEndpoint 连接
在 coding agent 的 MCP 服务器配置中,将 chrome-devtools-mcp 指向前一步转发的端点。文档中的原始配置示例:
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest",
"--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/"
],
"trust": true
}
关键点:
- 使用
npx chrome-devtools-mcp@latest拉取最新版本的包; --wsEndpoint指向的是经adb forward映射后的本机地址ws://127.0.0.1:9222/devtools/browser/;trust: true用于在客户端中信任该 MCP 服务器(具体字段语义取决于你使用的 coding agent,以你所用客户端的配置说明为准)。
第五步:用提示词验证接入是否成功
文档建议的验证方式是直接在 coding agent 中运行以下提示词:
Check the performance of developers.chrome.com
如果服务器已经正确接管了 Android 设备上的 Chrome,agent 会通过 MCP 工具在手机上的 Chrome 里打开该页面并做性能检查,而不是在你开发机的浏览器中打开。此时可以确认整条链路(手机 Chrome → 抽象 socket → adb 转发 → 9222 → MCP 服务器)全部打通。
--wsEndpoint 参数详解(源码佐证)
--wsEndpoint 在服务器端的定义位于 mcp-options.ts,其中几个细节直接影响 Android 场景下的正确配置:
- 协议强校验:
coerce函数会解析该值并要求协议必须是ws://或wss://,否则抛出Provided wsEndpoint ... must use ws:// or wss:// protocol.。因此写成http://127.0.0.1:9222/...会直接启动失败; - 短别名:
-w等价于--wsEndpoint; - 互斥关系:
wsEndpoint与browserUrl(-u)冲突(见 mcp-options.ts 中browserUrl的conflicts: ['wsEndpoint'])。同时从选项定义看,--executablePath、--userDataDir、--channel均声明conflicts: ['browserUrl', 'wsEndpoint', ...],即指定--wsEndpoint后不能再携带任何“启动本地 Chrome”的参数——这与 Android 场景语义一致:服务器只做连接,不做启动; --wsHeaders:可选参数,接受 JSON 格式的自定义 WebSocket 请求头(如{"Authorization":"Bearer token"}),通过implies: 'wsEndpoint'声明只能配合--wsEndpoint使用(见 mcp-options.ts)。本地 USB 场景一般用不到,但它说明该参数是为任意需要鉴权头的远程浏览器端点设计的。
底层连接原理:为什么它“能控制”手机上的 Chrome
真正的连接逻辑在 browser.ts 的 ensureBrowserConnected 中(见 browser.ts):
if (options.wsEndpoint) {
connectOptions.browserWSEndpoint = options.wsEndpoint;
if (options.wsHeaders) {
connectOptions.headers = options.wsHeaders;
}
}
// ...
const connected = await puppeteer.connect(connectOptions);
browserMode = 'connected';
从源码结构看,整个流程是:
- 服务器启动后并不调用任何“launch”路径,而是带着
browserWSEndpoint直接执行puppeteer.connect(...); - 连接成功后内部状态被标记为
browserMode = 'connected',与本地启动 Chrome 的'launched'模式区分开; - 后续所有工具调用(导航、截图、性能、网络等)都通过这条 CDP WebSocket 通道下发,对 Puppeteer 而言目标浏览器是“一个远程 WebSocket 端点”,并不关心另一端跑在桌面、还是经
adb转发的 Android 设备上。
这解释了为什么 Android 方案成立:adb forward 把设备端点伪装成了 ws://127.0.0.1:9222/devtools/browser/ 这样一个普通 WebSocket 端点,而 --wsEndpoint 恰好是服务器中“连接已运行浏览器”的第一优先路径(优先于 browserURL 与本地 auto-connect 逻辑)。
常见问题排查
结合文档提示与源码行为,按以下顺序排查通常能定位绝大多数问题:
adb devices看不到设备:检查 USB 直连、数据线是否支持数据传输、设备端是否弹出“允许 USB 调试”授权对话框;- 端口转发失败或连接拒绝:重新执行
adb forward tcp:9222 localabstract:chrome_devtools_remote,并用adb forward --list确认转发规则存在;确保设备上的 Chrome 正在运行(抽象 socket 由运行中的 Chrome 进程提供); - 服务器启动即报协议/URL 错误:确认
--wsEndpoint以ws://开头且为合法 URL,这是 mcp-options.ts 中的硬性校验; - 误传了互斥参数:若同时出现
--browserUrl、--channel、--userDataDir等参数会因冲突启动失败,Android 场景只保留--wsEndpoint; - 设备长期不响应:参考 Android 端 DevTools 远程调试的官方 Troubleshooting(文档原文指向 Chrome 官方 remote-debugging 文档);本地服务器自身的连接失败日志可通过
--logFile与DEBUG=*环境变量辅助定位(见 mcp-options.ts 中logFile的描述),更多通用问题可查阅 troubleshooting.md。
小结
Android 调试方案的全部要点可浓缩为三点:设备侧开启 USB 调试并运行 Chrome;开发机侧用 adb forward tcp:9222 localabstract:chrome_devtools_remote 暴露设备 DevTools 端点;MCP 侧仅配置 --wsEndpoint=ws://127.0.0.1:9222/devtools/browser/。由于该路径复用了服务器“连接已运行浏览器”的通用机制(puppeteer.connect + browserWSEndpoint),它与本地 Chrome 的连接方式在 advanced-usage.md 中有平行说明,Android 场景相当于把端点从“本机 9222”换成了“adb 转发出来的 9222”。需要牢记的是其实验性定位:Puppeteer 未将 Android 版 Chrome 列为官方支持目标,生产排障时应结合设备端远程调试状态逐项验证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00