Skip to content

Repository files navigation

chrome-devtools-mcp-rs

Pure-Rust, single-binary, drop-in replacement for chrome-devtools-mcp: an MCP server that gives coding agents control of a Chrome browser via the Chrome DevTools Protocol. Same tool names, schemas, response text, and CLI flags — swap one line in your MCP config and existing prompts work unchanged.

Status — drop-in compatible with chrome-devtools-mcp 1.3.0, verified in CI:

  • Full tool surface — all 46 reference tools and schemas implemented (29 in the default set, the rest behind experimental flags).
  • Byte-identical tools/list — matches 1.3.0 in every flag combination (slim, full, page-id routing, interop, navigation allowlist, and URL filtering), pinned by captured fixtures and live tools/list diffs.
  • Every experimental flag implemented--redactNetworkHeaders, --experimentalInteropTools (get_tab_id), --experimentalNavigationAllowlist, --blockedUrlPattern / --allowedUrlPattern, --experimentalStructuredContent, --experimentalToonFormat, --experimentalIncludeAllPages, and --experimentalDevtools all drive real behavior. The only remaining no-ops are telemetry/compatibility opt-outs (--no-usageStatistics, --viaCli, --clearcut*) — accepted without error because this server never collects telemetry, so no action is needed.
  • Live response parity — covered tools produce normalized output identical to the reference, including argument-validation errors, exercised per category by the golden-output harness in CI (see the parity matrix).
  • ~20× lighter, ~140× faster cold start than the Node reference (Performance).
  • lighthouse_audit runs via a Node.js sidecar bundled with the npm package, covered by its own harness scenario (lighthouse.yaml); see Known limitations for the non-npm fallback.

Install

npm install -g chrome-devtools-mcp-rs   # or run on demand with: npx chrome-devtools-mcp-rs

The npm package (npm-wrapper/) is the primary channel: a thin launcher whose postinstall fetches the prebuilt static binary for your platform (macOS arm64/x64, Linux x64, Windows x64) from the matching GitHub release. Also available via cargo install --git https://github.com/nhtera/chrome-devtools-mcp-rs, a Homebrew tap, or the binaries attached to each GitHub release.

Migrate from chrome-devtools-mcp

Change the one command line in your MCP config — args, tool names, and prompts are unchanged:

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

Usage

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "chrome-devtools-mcp-rs",
      "args": ["--headless", "--isolated"]
    }
  }
}

All CLI flags of the reference server are accepted (camelCase and kebab-case spellings), including --autoConnect (Chrome 144+) and --experimentalPageIdRouting (adds a pageId parameter to page-scoped tools so one server can drive several pages concurrently). Every documented flag — including --experimentalDevtools, --experimentalToonFormat, and --experimentalIncludeAllPages — drives real behavior; only the telemetry/compatibility opt-outs (--no-usageStatistics, --viaCli, --clearcut*) are accepted as silent no-ops. See Known limitations for the --experimentalDevtools page-id caveat.

The full memory-debugging surface matches 1.3.0: --memoryDebugging exposes all nine heap readers, including get_heapsnapshot_dominators, get_heapsnapshot_edges, and get_heapsnapshot_retaining_paths (added upstream in 1.3.0, gated on memoryDebugging like the rest).

The 1.3.0 screenshot size caps are also supported: --screenshotFormat (jpeg/png/webp), --screenshotQuality (0–100, JPEG/WebP only), --screenshotMaxWidth, and --screenshotMaxHeight set the defaults take_screenshot uses when a call omits them. Oversized captures are downscaled preserving aspect ratio (the smaller of the width/height scale wins) via the Chrome DevTools Protocol's native clip scaling, matching the reference.

Performance

Server-process measurements vs the pinned reference chrome-devtools-mcp@1.3.0, median of 3 cold starts (macOS arm64, Chrome 149 headless, scripts/measure-rss.mjs

  • a cold-start harness). RSS is the server process only — Chrome's own memory is identical for both and excluded. loaded/peak = after navigate + 10 screenshots. Slim = --slim --headless --isolated (3 tools); full drops --slim (29 tools).
Metric chrome-devtools-mcp-rs (release) chrome-devtools-mcp 1.3.0 (Node 22) Ratio
Idle RSS (slim / full) 4.9 / 5.5 MiB 109 / 108 MiB ~20×
Peak RSS (slim / full) 7.4 / 7.2 MiB 109 / 108 MiB ~15×
Startup (spawn → initialize) ~4.5 ms ~645 ms ~140×

Browser-driving throughput (navigate + screenshots) is a wash — both drive the same Chrome. Adding 26 tools (slim → full) costs the Rust server +0.6 MiB idle and nothing at startup; the Node floor is unchanged at ~108 MiB. The gap is the runtime — a static binary vs V8 plus bundled JS — not the size of the tool list.

CI enforces three RSS ceilings on the release binary (.github/workflows/memory.yml): < 15 MB idle (after initialize + tools/list, before Chrome launches), < 100 MB loaded (after the core scenario suite), and < 200 MB during a ~100 MB trace parse.

Building

cargo build --release
cargo test            # integration tests need a local Chrome (or CHROME_PATH)

Parity verification

Two layers, both gated in CI:

  • Captured fixturesparity/fixtures/reference/ holds responses captured from the reference server (version pinned in capture-meta.json) via parity/capture/capture-slim-reference.mjs. Tests assert against these fixtures; re-capture deliberately when bumping the pinned version.
  • Live golden-output harnesscargo run -p parity spawns this server and the pinned npm reference side by side, drives identical tool calls from parity/scenarios/*.yaml against local fixture pages, and diffs the normalized responses (.github/workflows/parity.yml, macOS + Linux). See parity/README.md for authoring scenarios and the pin-bump procedure.

Tool parity matrix

Each row maps to scenario file(s) gated in CI — .github/workflows/parity.yml (or memory.yml for the RSS gates) — and diffed against the pinned reference.

Category (reference) Parity scenarios (CI-gated) Status
Input automation input.yaml ✅ live parity
Navigation automation navigation.yaml, slim.yaml, navigation-allowlist.yaml ✅ live parity
Emulation emulation.yaml ✅ live parity
Performance performance.yaml ✅ live parity
Network network.yaml, network-redirect.yaml, network-redact.yaml ✅ live parity
URL filtering url-block.yaml, url-block-subresource.yaml, url-allow.yaml ✅ live parity¹
Debugging snapshot.yaml, console.yaml, slim.yaml, lighthouse.yaml ✅ live parity (lighthouse_audit via npm sidecar, see below)
Memory memory.yaml, memory-idle.yaml (RSS), structured-content-heap.yaml ✅ RSS gates + live parity (incl. the v1.3.0 get_heapsnapshot_dominators / _edges / _retaining_paths readers)
Screenshot size caps (1.3.0) screenshot-size-caps.yaml ✅ live parity (--screenshotMaxWidth downscale, PNG + JPEG)
Interop / page-id routing interop.yaml, page-id-routing.yaml ✅ live parity
Structured content structured-content.yaml ✅ live parity
TOON format (--experimentalToonFormat) toon.yaml, toon-console.yaml ✅ live parity
Include-all-pages (--experimentalIncludeAllPages) include-all-pages.yaml ✅ live parity²
Argument validation tool-argument-validation.yaml ✅ live parity

¹ url-block-subresource is retry-reliant: Chrome emits the offline-subresource failure asynchronously, so the blocked request can momentarily read pending. The harness's one-shot retry absorbs it (a pass-on-retry is flagged in the report); see the scenario file. ² Gated on shape only — the headless CI fixture exposes no webview / background_page target, so the scenario verifies the page-listing shape under the flag rather than a non-page target.

Scenario files present but not CI-gated — extensions.yaml, thirdparty.yaml, webmcp.yaml, screencast.yaml, and devtools.yaml — need fixtures the headless CI image can't provide deterministically (a loaded extension, a third-party origin, a WebMCP page, an ffmpeg screencast, or a DevTools-target attach). Run them locally with cargo run -p parity -- --scenarios parity/scenarios/<file>. All five were verified locally against npm chrome-devtools-mcp@1.3.0 (Chrome 149 + ffmpeg), including the 1.3.0 screencast_stop no-active-recording line, the unsupported-extension rejection, and the WebMCP feature-flag rename. devtools.yaml (--experimentalDevtools) is additionally a known divergence — see Known limitations.

Known limitations

  • lighthouse_audit runs via a Node.js sidecar that ships with the npm package (lighthouse + puppeteer-core bundled alongside the binary). On npm installs the audit runs against the same Chrome this server drives and returns scores/reports identical to the reference. Lighthouse is a Node.js engine with no stable CDP equivalent, so it cannot be embedded in the binary itself: on standalone / cargo / homebrew installs (no Node engine present) the tool stays discoverable but a call returns a clear fallback error:

    lighthouse_audit is not available in this build. Lighthouse runs as a bundled Node.js engine, which this build does not ship, and Chrome exposes no stable CDP surface that reproduces it. Install via the npm package (which bundles the Lighthouse sidecar), or use the official Node-based chrome-devtools-mcp, the Lighthouse CLI, or the Lighthouse panel in Chrome DevTools. For performance audits, run performance_start_trace.

    Performance audits are fully supported everywhere via performance_start_trace / performance_stop_trace / performance_analyze_insight.

  • Windows (x64) ships a .zip release asset built on x86_64-pc-windows-msvc; the release gate covers macOS (arm64/x64), Linux (x64), and Windows (x64). The Windows build is guarded in CI (cargo build --release); the Chrome-driven test suite still runs on Linux only.

  • --experimentalDevtools implements the reference's page filter (DevTools devtools:// targets become listable/selectable, unit-tested), but is not byte-gated in CI. Under the flag the reference — via puppeteer's always-on handleDevToolsAsPage — surfaces an extra DevTools/startup target that takes page id 1, shifting the first real page to id 2; this server's session model never attaches to that target, so it lists the page as id 1. Only the page-id numbering differs (URL and selection match). devtools.yaml is kept as documentation and a local-repro harness, not a CI gate.

License

Apache-2.0. See NOTICE for third-party attributions.

About

Pure-Rust, single-binary drop-in replacement for chrome-devtools-mcp

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages