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 livetools/listdiffs. - Every experimental flag implemented —
--redactNetworkHeaders,--experimentalInteropTools(get_tab_id),--experimentalNavigationAllowlist,--blockedUrlPattern/--allowedUrlPattern,--experimentalStructuredContent,--experimentalToonFormat,--experimentalIncludeAllPages, and--experimentalDevtoolsall 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_auditruns 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.
npm install -g chrome-devtools-mcp-rs # or run on demand with: npx chrome-devtools-mcp-rsThe 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.
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"]
}{
"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.
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.
cargo build --release
cargo test # integration tests need a local Chrome (or CHROME_PATH)Two layers, both gated in CI:
- Captured fixtures —
parity/fixtures/reference/holds responses captured from the reference server (version pinned incapture-meta.json) viaparity/capture/capture-slim-reference.mjs. Tests assert against these fixtures; re-capture deliberately when bumping the pinned version. - Live golden-output harness —
cargo run -p parityspawns this server and the pinned npm reference side by side, drives identical tool calls fromparity/scenarios/*.yamlagainst local fixture pages, and diffs the normalized responses (.github/workflows/parity.yml, macOS + Linux). Seeparity/README.mdfor authoring scenarios and the pin-bump procedure.
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.
-
lighthouse_auditruns via a Node.js sidecar that ships with the npm package (lighthouse+puppeteer-corebundled 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
.ziprelease asset built onx86_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. -
--experimentalDevtoolsimplements the reference's page filter (DevToolsdevtools://targets become listable/selectable, unit-tested), but is not byte-gated in CI. Under the flag the reference — via puppeteer's always-onhandleDevToolsAsPage— 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.yamlis kept as documentation and a local-repro harness, not a CI gate.
Apache-2.0. See NOTICE for third-party attributions.