Skip to content

Run beside Chrome DevTools MCP

chrome-devtools-mcp gives an agent raw control of a live Chrome instance, and recent versions added extension tools (install, list, reload, trigger and uninstall, plus service worker logs). @extension.dev/mcp covers the same extension capabilities build-aware and across browsers, because it wraps an Extension.js dev session instead of a bare browser.

They are complementary, not competing. Run both: let chrome-devtools-mcp drive Chrome itself, and let the extension.dev server own everything that depends on the project: the build, hot reload, the generated manifest, storage, logs across every context, and the same flow on Firefox, Edge and Safari.

When to use which

TaskUse
Build, dev server, hot reload, production packagingextension.dev (extension_dev, extension_build)
Read the generated, cross-browser manifestextension.dev (extension_manifest_validate)
Replay the toolbar action handler, scriptably, no popupextension.dev (extension_open with surface: "action")
Replay a keyboard shortcut command handlerextension.dev (extension_open with surface: "command")
List extensions with a live context in the dev browserextension.dev (extension_list_extensions)
Logs across service worker, content scripts, popup, optionsextension.dev (extension_logs)
Read or write chrome.storage, eval in any contextextension.dev (extension_storage, extension_eval)
Same flow on Firefox, Edge or Safariextension.dev (cross-browser by design)
Drive an arbitrary web page, click, scroll, fill formschrome-devtools-mcp
Performance traces, Lighthouse audits, network inspectionchrome-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)

Rule of thumb: if the task 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.

Install both

The extension.dev tools are namespaced extension_*, so they never collide with chrome-devtools-mcp tools, and an agent fluent in one transfers to the other.

bash
# extension.dev, build-aware extension control
claude mcp add extension-dev npx @extension.dev/mcp

# chrome-devtools-mcp, raw Chrome debugging (extension tools opt-in)
# `--` hands the flag to the server; without it `claude` parses it as its own
claude mcp add chrome-devtools -- npx chrome-devtools-mcp@latest --categoryExtensions
json
{
  "mcpServers": {
    "extension-dev": {
      "command": "npx",
      "args": ["@extension.dev/mcp"]
    },
    "chrome-devtools": {
      "command": "npx",
      "args": ["chrome-devtools-mcp@latest", "--categoryExtensions"]
    }
  }
}
json
{
  "mcpServers": {
    "extension-dev": {
      "command": "npx",
      "args": ["@extension.dev/mcp"]
    },
    "chrome-devtools": {
      "command": "npx",
      "args": ["chrome-devtools-mcp@latest", "--categoryExtensions"]
    }
  }
}

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 that the dev session launched, so its extension tools work today.

Capability map

Every chrome-devtools-mcp extension verb has an extension.dev counterpart, plus a build platform around it.

chrome-devtools-mcpextension.devNotes
install_extensionextension_dev, extension_startLoading is tied to a real build and hot reload, not a static folder
list_extensionsextension_list_extensionsLists extensions with a live context, read-only through the Extensions domain, Chromium only
reload_extensionextension_reloadRebuild-aware, reloads the background or a tab
trigger_extension_actionextension_open (surface: "action")Portable replay of the onClicked handler, cross-browser, no gesture. For a genuine click that grants activeTab, use the left
noneextension_open (surface: "command")Replays a chrome.commands.onCommand keyboard shortcut handler, no chrome-devtools-mcp equivalent
uninstall_extensionmanaged by the dev session lifecycleThe dev session owns load and unload through dev and preview
service worker logsextension_logsOne ordered timeline across every context, with follow

Action and command triggers, and their one caveat

chrome-devtools-mcp triggers an action by clicking the real toolbar button, which needs a visible window and a genuine user gesture. Extension.js takes a different approach: it captures the extension's chrome.action.onClicked and chrome.commands.onCommand listeners at build time and replays them on demand. That makes triggering scriptable and reproducible, the natural mode for agentic testing, and because it only touches addListener it works on both Chromium and Firefox. A single background.service_worker source works on Firefox too: 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 permission and satisfies gesture-gated APIs (chrome.permissions.request, interactive identity.getAuthToken); a replay does not. A handler that relies on activeTab (for example chrome.scripting.executeScript on the active tab, or captureVisibleTab) behaves differently than it does on a real click. The result includes gesture: false, and a warning when the manifest declares activeTab. When you need click fidelity, use chrome-devtools-mcp's trigger_extension_action.

When you need a genuine gesture

  • extension_open (surface: "action"): the everyday path. Replays the handler, cross-browser, headless, no gesture (activeTab not granted). Use it for most handler testing.
  • chrome-devtools-mcp trigger_extension_action: a real action invocation through Puppeteer over the pipe transport, so activeTab is granted exactly like a user click. Chromium only. Reach for it only when the handler depends on the gesture.

Safe by construction

The replay wraps are injected only into the dev build. The agent bridge is gated on a control port that exists solely during extension dev and extension preview, and nothing is added to a production build. The addListener wraps delegate transparently to the originals, so the extension behaves identically with or without the bridge. The framework side of this is documented at extension.js.org/docs/debugging/trigger-actions-and-commands.

Next