
Chromewright
โ 1from bnomei
Browser automation via Chrome DevTools Protocol
chromewright
Chromewright is a local-first browser automation MCP server built on Chrome DevTools Protocol (CDP). It exposes a real Chrome or Chromium browser to MCP clients over stdio or loopback streamable HTTP, with high-level tools for navigation, page reading, tab management, screenshots, viewport emulation, and bounded interaction.
Use Chromewright when an agent needs browser state from a real browser without embedding a Node.js automation stack or writing raw CDP calls. Chromewright is not an end-to-end test runner; it is a browser control layer for AI agents and MCP clients.
When to use Chromewright
- Attach an MCP client to an existing Chrome or Chromium profile on a DevTools endpoint.
- Launch a dedicated local browser session for agent work.
- Read pages through snapshots, markdown extraction, targeted inspection, and link inventory.
- Drive bounded interactions such as click, input, select, hover, key press, scroll, and wait.
- Capture managed PNG screenshots without letting callers choose arbitrary output paths.
- Reuse revision-scoped
cursorhandles from snapshots instead of relying only on CSS selectors.
Browser modes
Chromewright has two browser modes:
| Mode | How to start | What it does |
|---|---|---|
| Attach | Run chromewright or chromewright serve with no launch flags. | Connects to http://127.0.0.1:9222 by default. |
| Attach to another endpoint | Pass --ws-endpoint <URL>. | Connects to a browser WebSocket URL or a DevTools HTTP origin such as http://127.0.0.1:9333. |
| Launch | Pass any launch flag such as --user-data-dir, --headless, --executable-path, or --debug-port. | Starts a local browser session. Launch mode is headed unless you pass --headless. |
Examples:
# Default: attach to http://127.0.0.1:9222 and serve MCP over stdio.
chromewright
# Serve streamable HTTP on the default loopback endpoint.
chromewright serve
# Serve streamable HTTP on a custom port and path.
chromewright serve --port 3333 --http-path /browser
# Attach to a different DevTools endpoint.
chromewright --ws-endpoint http://127.0.0.1:9333
# Launch a visible browser with a dedicated profile.
chromewright --user-data-dir /tmp/chromewright-profile
# Launch a headless browser and serve streamable HTTP.
chromewright --headless --user-data-dir /tmp/chromewright-profile serveCLI reference
| Option or command | Default | Description |
|---|---|---|
chromewright | stdio transport | Starts the MCP server over stdio. |
chromewright serve | 127.0.0.1:3000/mcp | Starts the MCP server over loopback streamable HTTP. |
serve --port <PORT>, serve -p <PORT> | 3000 | Sets the HTTP port. |
serve --http-path <PATH> | /mcp | Sets the HTTP endpoint path. |
--ws-endpoint <URL> | http://127.0.0.1:9222 when no launch flags are present | Connects to an existing browser WebSocket URL or DevTools HTTP origin. This conflicts with launch flags. |
--headless | false | Launches a new browser in headless mode. |
--executable-path <PATH> | auto-detected by the browser backend | Uses a specific browser executable in launch mode. |
--user-data-dir <DIR> | backend default | Uses a persistent browser profile directory in launch mode. |
--debug-port <PORT> | auto-selected | Uses a specific DevTools port for a locally launched browser. |
Source: src/bin/mcp_server.rs.
Tool workflow
A typical agent workflow is:
- Call
tab_listornew_tabto establish an active tab. - Call
snapshotto read the current page and collect actionable nodes. - Prefer a fresh
cursorfromsnapshotorinspect_nodewhen targeting follow-up actions. - Use
inspect_node,get_markdown,extract, orread_linksfor more focused reads. - Use
click,input,select,hover,press_key,scroll,wait, or tab tools for bounded interaction. - Call
snapshotagain after navigation, DOM-changing actions, viewport changes, or ambiguous target recovery.
snapshot supports these modes:
| Mode | Use it when |
|---|---|
viewport | You want the default local reread of the current visible scope. |
delta | You want the changed local surface when a compatible prior snapshot base exists. |
full | You need an exhaustive page-wide read. |
DOM-targeted tools accept a public target object:
{
"target": {
"kind": "selector",
"selector": "h1"
}
}or:
{
"target": {
"kind": "cursor",
"cursor": "<cursor from snapshot or inspect_node>"
}
}Selector strings are still accepted for compatibility by tools that use the public target type, but the object form is the canonical contract.
Production MCP tool surface
Production MCP sessions register the default high-level tools plus the guarded operator tool evaluate.
| Category | Tools |
|---|---|
| Navigation | navigate, go_back, go_forward, wait |
| Interaction and viewport | click, input, select, hover, press_key, scroll, set_viewport |
| Tabs and lifecycle | new_tab, tab_list, switch_tab, close_tab, close |
| Reading and inspection | snapshot, inspect_node, get_markdown, extract, read_links |
| Managed artifacts | screenshot |
| Operator diagnostics | evaluate |
evaluate executes JavaScript in the active page and requires confirm_unsafe = true on each call. It is available for diagnostics and escape-hatch inspection when bounded tools cannot answer a page-specific question.
Source: src/tools/core/mod.rs and src/browser/session.rs.
Screenshots and viewport emulation
Use screenshot when a caller needs a managed PNG artifact. The tool accepts:
mode:viewport,full_page,element, orregionscale:deviceorcss- optional
tab_id - optional
targetforelementcaptures - optional
regionforregioncaptures
Successful calls return managed artifact metadata, including artifact_uri, artifact_path, mime_type, byte_count, image dimensions, CSS dimensions, device pixel ratio, pixel scale, revealed_from_offscreen, and optional clip data. Callers do not provide output paths.
Use set_viewport to emulate responsive breakpoints through CDP. Successful calls return viewport_metrics_after; later snapshot calls expose the live metrics under scope.viewport.
Safety boundaries
- Attach mode can see the tabs, cookies, and authenticated state in the browser profile you connect to.
- Use a dedicated browser profile for agent work when you do not want automation attached to a personal browser session.
evaluaterequiresconfirm_unsafe = truebecause it runs arbitrary JavaScript in the active page.navigateandnew_tabreject unsafe schemes such asdata:andfile:unless that request passesallow_unsafe = true.go_backandgo_forwardapply the same unsafe-scheme gate and revert rejected history moves.close_tabrequiresconfirm_destructive = truebefore closing an unmanaged active tab in a connected session.closerequiresconfirm_destructive = truebefore expanding connected-session cleanup from managed tabs to all tabs.cursorandnode_reftargets are revision-scoped. After navigation or DOM-changing actions, refresh withsnapshot.
Operation metrics
Finished tool results include operation_metrics metadata when a tool records non-zero metrics. operation_metrics.output_bytes is optional; it appears only when a tool path measures the exact serialized output size.
Measured paths may include:
- browser evaluation count
- poll iterations
- DOM extraction count and extraction time
- last DOM node count
- snapshot render time
- handoff rebuild count and time
- exact serialized output size when measured
Run the focused operation metrics tests:
cargo test --locked --all-features operation_metricsLocal development
Build from source:
cargo buildRun the normal test suite:
cargo testRun the browser smoke suite from the repository root:
scripts/browser-smoke.shThe smoke script runs:
cargo test --test browser_smoke -- --nocaptureBrowser smoke checks launch a local browser and are intended for maintainer workstations. CI covers formatting, clippy, MSRV, cargo check, tests, and packaging without requiring a live browser attach target.
Source anchors
- Package metadata and Rust version: Cargo.toml
- CLI flags and transports: src/bin/mcp_server.rs
- Tool registry: src/tools/core/mod.rs
- MCP handler: src/mcp/handler.rs
- Public target contract: src/contract/target.rs
- Screenshot contract: src/tools/screenshot.rs
- Browser smoke script: scripts/browser-smoke.sh
License
MIT
cargo install chromewrightInstallation
Chromewright requires Rust 1.88 or newer when you install or build it with Cargo.
Install from crates.io:
cargo install chromewrightInstall with Homebrew:
brew install bnomei/chromewright/chromewrightInstall from source:
git clone https://github.com/bnomei/chromewright.git
cd chromewright
cargo install --path .You can also download prebuilt archives from GitHub Releases and place the chromewright binary on your PATH.
Verify the binary is available:
chromewright --versionExpected output:
chromewright <version>Quickstart
This path starts a visible Chrome profile with DevTools enabled, then serves Chromewright over loopback HTTP at http://127.0.0.1:3000/mcp.
Prerequisites
chromewrighton yourPATH- Chrome, Chromium, or another CDP-compatible browser
- An MCP client that supports streamable HTTP or stdio servers
1. Start a dedicated browser profile
On macOS, run:
open -na "Google Chrome" --args \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.chromewright-agent-profile"Use a dedicated profile when you do not want agent automation attached to your personal browser session. The default Chromewright attach mode expects DevTools at http://127.0.0.1:9222.
2. Start Chromewright
Run the streamable HTTP server:
chromewright serveExpected log line:
Ready to accept MCP connections at http://127.0.0.1:3000/mcp3. Connect an MCP client
For JSON-configured clients that support streamable HTTP:
{
"mcpServers": {
"chromewright": {
"transport": "streamable_http",
"url": "http://127.0.0.1:3000/mcp"
}
}
}For Codex over stdio, let the client start the server:
[mcp_servers.chromewright]
command = "/absolute/path/to/chromewright"
enabled = trueFor Codex against the long-lived HTTP server from step 2:
[mcp_servers.chromewright]
url = "http://127.0.0.1:3000/mcp"
enabled = true4. Verify with the client
Use your MCP client to call tab_list. A connected session should return at least one tab with a stable tab_id. If no active tab is useful, call new_tab before calling snapshot.
No common issues documented yet. If you hit a problem, the repository's GitHub Issues page is the best place to look.