Pair with Chrome DevTools MCP
chrome-devtools-mcp gives an agent raw control of a live Chrome, and its extension tools (install_extension, list_extensions, reload_extension, trigger_extension_action, uninstall_extension) load and poke a built extension. Reach for both servers at once: let chrome-devtools-mcp drive Chrome itself, and let @extension.dev/mcp own everything that depends on the project, because it wraps an Extension.js dev session instead of a bare browser.
Quick start
claude mcp add extension-dev npx @extension.dev/mcp
claude mcp add chrome-devtools -- npx chrome-devtools-mcp@latest --categoryExtensionsThe -- hands --categoryExtensions to the server. Without it, claude parses the flag as its own. The extension.dev tools are namespaced extension_*, so the two servers never collide.
{
"mcpServers": {
"extension-dev": {
"command": "npx",
"args": ["@extension.dev/mcp"]
},
"chrome-devtools": {
"command": "npx",
"args": ["chrome-devtools-mcp@latest", "--categoryExtensions"]
}
}
}{
"mcpServers": {
"extension-dev": {
"command": "npx",
"args": ["@extension.dev/mcp"]
},
"chrome-devtools": {
"command": "npx",
"args": ["chrome-devtools-mcp@latest", "--categoryExtensions"]
}
}
}How it works
The two servers split the work by what a task touches. If it touches the project (source, build, manifest, reload), reach for the extension.dev server. If it touches the browser generically (pages, network, performance), reach for chrome-devtools-mcp.
chrome-devtools-mcp triggers an action over the DevTools protocol (Extensions.triggerAction), which Chrome runs as a user action on the toolbar button, the same path as a click: the handler gets a user gesture and the activeTab grant, and the selected page must be a tab in a browser window. Extension.js takes a different route: it captures the extension's chrome.action.onClicked and chrome.commands.onCommand listeners at install time and replays them on demand. Triggering becomes scriptable and reproducible, and because it only touches addListener it works on both Chromium and Firefox. A single background.service_worker source works on Firefox too, because the framework translates it to a background.scripts event page for the Firefox build.
No gesture on replay
Replay invokes the handler without a user gesture. A real toolbar click grants temporary activeTab and satisfies gesture-gated APIs (chrome.permissions.request, interactive identity.getAuthToken). A replay does not. A handler that relies on activeTab (chrome.scripting.executeScript on the active tab, or captureVisibleTab) behaves differently than it does on a real click. The result carries gesture: false, and an action replay also carries a warning when the manifest declares activeTab. When you need click fidelity, use chrome-devtools-mcp's trigger_extension_action.
The replay wraps live only in the dev build. A production build carries no reload client and no wrap, and the addListener wraps delegate to the originals, so the extension behaves the same with or without the bridge. The framework side is documented at extension.js.org/docs/debugging/trigger-actions-and-commands.
Pipe transport
The chrome-devtools-mcp extension tools (--categoryExtensions) need a pipe connection. Attaching to an already running browser over a WebSocket endpoint (browserUrl or wsEndpoint) is not supported for that category before Chrome 149. The extension.dev server connects to the browser the dev session launched, so its extension tools work today.
Reference
| Task | Use |
|---|---|
| Build, dev server, hot reload, production packaging | extension.dev (extension_dev, extension_build) |
| Validate the manifest across browsers before a build | extension.dev (extension_manifest_validate) |
| Replay the toolbar action handler, scriptably, no popup | extension.dev (extension_open with surface: "action") |
| Replay a keyboard shortcut command handler | extension.dev (extension_open with surface: "command") |
| List the extensions loaded in the dev browser | extension.dev (extension_list_extensions) |
| Logs across service worker, content scripts, popup, options | extension.dev (extension_logs) |
Read or write chrome.storage, eval in any context | extension.dev (extension_storage, extension_eval) |
| Same flow on Firefox, Edge or Safari | extension.dev (cross-browser by design) |
| Drive an arbitrary web page, click, scroll, fill forms | chrome-devtools-mcp |
| Performance traces, Lighthouse audits, network inspection | chrome-devtools-mcp |
| Inspect an extension you did not build (no project) | chrome-devtools-mcp |
Trigger the action with a real gesture (grants activeTab) | chrome-devtools-mcp (trigger_extension_action) |
Every chrome-devtools-mcp extension verb has an extension.dev counterpart, plus a build platform around it.
| chrome-devtools-mcp | extension.dev | Notes |
|---|---|---|
install_extension | extension_dev, extension_start | extension_dev loads a real build with hot reload; extension_start runs the production build, or a prebuilt folder with outputPath |
list_extensions | extension_list_extensions | Read-only, on Chromium and Firefox; live contexts on Chromium only |
reload_extension | extension_reload | Reloads the background or a tab, and waits for the new background to reattach |
trigger_extension_action | extension_open (surface: "action") | Portable replay of the onClicked handler, cross-browser, no gesture. For a genuine click that grants activeTab, use the left |
| none | extension_open (surface: "command") | Replays a chrome.commands.onCommand keyboard shortcut handler; chrome-devtools-mcp has no equivalent |
uninstall_extension | extension_stop | The dev session owns load and unload |
| console messages filtered by service worker | extension_logs | One ordered timeline across every context, with follow |
When it fails
- A replayed handler does nothing on the active tab: it depends on
activeTab, which a replay never grants. Readgesture: falseand thewarningin the result, then trigger it with chrome-devtools-mcp'strigger_extension_action. That path is Chromium only. - chrome-devtools-mcp lists no extension tools: the category is off by default. Start it with
--categoryExtensions, and in Claude Code put--beforenpxso the flag reaches the server. - The extension tools fail against a browser you attached to:
--categoryExtensionsneeds a pipe connection, andbrowserUrlorwsEndpointare not supported for it before Chrome 149. Let chrome-devtools-mcp launch its own Chrome. - The same name answers from both servers: it cannot. The extension.dev tools are all
extension_*, and atrigger_extension_actioncall is chrome-devtools-mcp's.
Next
- MCP server is the tool reference
- Agent skill teaches the agent which server to reach for
- Inspect and act covers the observe and act gates
- Agent bridge is the local channel both the CLI and the server use