Content
# chrome-devtools-mcp-rs
Pure-Rust, single-binary, drop-in replacement for [chrome-devtools-mcp](https://github.com/ChromeDevTools/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](#tool-parity-matrix)).
- **~20× lighter, ~140× faster cold start** than the Node reference ([Performance](#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](#known-limitations) for the non-npm fallback.
## Install
```sh
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:
```diff
"chrome-devtools": {
- "command": "npx",
- "args": ["chrome-devtools-mcp@latest"]
+ "command": "npx",
+ "args": ["chrome-devtools-mcp-rs"]
}
```
## Usage
```json
{
"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](#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
```sh
cargo build --release
cargo test # integration tests need a local Chrome (or CHROME_PATH)
```
## Parity verification
Two layers, both gated in CI:
- **Captured fixtures** — `parity/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 harness** — `cargo 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).
## 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.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available