chrome-devtools-mcp 让 AI agent 能够直接控制一个真实运行的 Chrome 实例,近期版本还加入了扩展相关的工具(install、list、reload、trigger、uninstall,以及 service-worker 日志)。Extension.js 的 MCP 服务器(@extension.dev/mcp)覆盖同样的扩展能力,但具备构建感知,并支持跨浏览器。
它们是互补关系,而不是竞争关系。两个一起运行:让 chrome-devtools-mcp 驱动 Chrome 本身,让 Extension.js 接管一切与你项目相关的事——构建、热重载、生成的 manifest、storage、跨上下文的日志,以及在 Firefox、Edge 和 Safari 上的同一套工作流。
何时该用哪一个
| 任务 | 使用 |
|---|
| 构建、开发服务器、热重载、生产打包 | Extension.js (extension_dev、extension_build) |
| 读取生成的、跨浏览器的 manifest | Extension.js (extension_manifest_validate) |
| 以脚本化方式重放工具栏 action 处理器,无 popup | Extension.js (extension_open,surface: "action") |
| 重放键盘快捷键命令处理器 | Extension.js (extension_open,surface: "command") |
| 在开发浏览器中列出带有实时上下文的扩展 | Extension.js (extension_list_extensions) |
| 跨 SW、content script、popup、options、sidebar 的日志 | Extension.js (extension_logs) |
在任意上下文中读写 chrome.storage、求值 | Extension.js (extension_storage、extension_eval) |
| 同样的流程在 Firefox、Edge 或 Safari 上 | Extension.js(生来跨浏览器) |
| 驱动任意网页、点击/滚动、填写表单 | chrome-devtools-mcp |
| 性能追踪、Lighthouse 审计、网络检查 | chrome-devtools-mcp |
| 检查一个不是你构建的扩展(没有项目) | chrome-devtools-mcp |
以真实手势触发 action(授予 activeTab) | chrome-devtools-mcp (trigger_extension_action) |
一个有用的经验法则:如果任务涉及到你的项目(源码、构建、manifest、重载),就用 Extension.js;如果任务面向浏览器本身(页面、网络、性能),就用 chrome-devtools-mcp。
同时安装两个服务器
Extension.js 的工具都加了 extension_* 命名空间前缀,因此永远不会与 chrome-devtools-mcp 的工具冲突。熟悉其中一个的 agent 可以无缝迁移到另一个。
# Extension.js — 构建感知的扩展控制
claude mcp add extension-dev npx @extension.dev/mcp
# chrome-devtools-mcp — 原生 Chrome 调试(扩展工具按需启用)
claude mcp add chrome-devtools npx chrome-devtools-mcp@latest --categoryExtensions
chrome-devtools-mcp 的扩展工具(--categoryExtensions)目前要求使用 pipe
连接。在 Chrome 149 之前,通过 WebSocket 端点(browserUrl / wsEndpoint)
附加到一个已经在运行的浏览器,对 extension 类别是不支持的。Extension.js
连接的是它为你的开发会话启动的那个浏览器,因此它的扩展工具今天就能用。
能力对照表
chrome-devtools-mcp 每一个扩展相关动作在 Extension.js 中都有对应物,再加上围绕它构建的整套构建平台。
| chrome-devtools-mcp | Extension.js | 备注 |
|---|
install_extension | extension_dev、extension_preview | 加载与真实构建 + 热重载绑定,不是加载一个静态文件夹 |
list_extensions | extension_list_extensions | 列出带有实时上下文的扩展;通过 Extensions 域只读 |
reload_extension | extension_reload | 构建感知;重载 background 或某个标签页 |
trigger_extension_action | extension_open(surface: "action") | 可移植地重放 onClicked 处理器——跨浏览器、无手势(见注意事项)。如需真实手势点击(activeTab),请使用 chrome-devtools-mcp 的 trigger_extension_action |
| — | extension_open(surface: "command") | 重放一个 chrome.commands.onCommand 键盘快捷键处理器——chrome-devtools-mcp 没有对应物 |
uninstall_extension | 由开发会话生命周期管理 | Extension.js 通过 dev / preview 拥有加载/卸载流程 |
| service-worker 日志 | extension_logs | 一条按时间排序、跨所有上下文的统一时间线,并支持 follow |
action / command 触发器的工作原理——以及它们唯一的注意点
chrome-devtools-mcp 是通过点击真实的工具栏按钮来触发 action 的,这需要一个可见的窗口与真实的用户手势。Extension.js 走的是另一条路:它在构建阶段就捕获扩展的 chrome.action.onClicked(以及 chrome.commands.onCommand)监听器,并在你需要时重放它们。这让触发变得可脚本化且可重现——这正是 agent 化测试的天然模式——而且因为它只触及 addListener,它在 Chromium 和 Firefox 上都能工作(在两者上都已验证)。一份 background.service_worker 源码也能在 Firefox 上工作——由于 Firefox 不运行 service-worker background,Extension.js 会把它翻译为 Firefox 构建目标里的 background.scripts 事件页面。
重放会在没有用户手势的情况下调用你的处理器。真实的工具栏点击会临时授予
activeTab 权限并满足需要手势的 API(chrome.permissions.request、
交互式的 identity.getAuthToken);重放不会。因此那些依赖 activeTab
的处理器(例如在当前标签页上调用 chrome.scripting.executeScript 或
captureVisibleTab)其表现会与真实点击不同。返回结果中会包含 gesture: false,并且当你的 manifest 声明了 activeTab 时会带上 warning。如果你需要
真实点击的保真度,请使用 chrome-devtools-mcp 的 trigger_extension_action
(见下文)。
两者是互补的,而不是竞争关系:
extension_open(surface: "action")——日常路径。重放处理器,跨浏览器、无头、无手势(不授予 activeTab)。处理绝大多数处理器测试场景。
- chrome-devtools-mcp 的
trigger_extension_action——通过 Puppeteer(在受支持的 pipe 传输上)发起一次真实的 action 调用,因此 activeTab 会像真实用户点击那样被授予。仅限 Chromium。只有当你的处理器确实依赖手势时才需要它。
既然本页已经建议把两个服务器一起运行,那就让 chrome-devtools-mcp 负责真实手势的浏览器驱动,让 Extension.js 负责构建感知、跨浏览器的重放——没必要重复造轮子。
参见 重载与 HMR。
设计上即安全
重放包装只注入到你的开发构建里——agent 桥仅依赖一个只在 extension dev / preview 期间存在的控制端口,生产构建中不会添加任何内容。addListener 包装会透明地委托给原始实现,因此无论是否启用桥,你的扩展行为都完全一致。
下一步