{
  "markdown": "# Chrome Bridge\n\n![License: MIT](https://img.shields.io/badge/license-MIT-green) ![Node 18+](https://img.shields.io/badge/node-%E2%89%A518-brightgreen) ![Chrome 135+](https://img.shields.io/badge/chrome-%E2%89%A5135-blue) ![Tests](https://img.shields.io/badge/tests-257%20unit%20%2B%2032%20e2e-brightgreen) [![Chrome Web Store](https://img.shields.io/badge/web%20store-published-blue)](https://chromewebstore.google.com/detail/chrome-bridge-for-claude/bioknpaeahidbelaljjohjofiloeodmb)\n\n**An MCP server that gives Claude Code your real, logged-in Chrome — measured\n2.75× fewer turns and 2.28× lower cost than the official \"Claude in Chrome\"\nextension on a form-filling task, with ~3× the toolset and no paid plan.**\n\n59 web-development tools (navigation, DOM inspection, visual regression, audits,\nnetwork mocking) over a local WebSocket bridge, plus a headless instance for CI.\nSelf-hosted, local-only.\n\n![The same form filled in 6 turns instead of 16.5 — 2.75× fewer turns, 2.28× lower cost](assets/readme/card1-race.png)\n\n## Quickstart\n\n**Requires** Node.js 18+ and Chrome 135+.\n\n```bash\ngit clone git@github.com:frsorrentino/chrome-bridge.git\ncd chrome-bridge && ./install.sh\n```\n\n1. Open `chrome://extensions`, enable **Developer mode**, click **Load\n   unpacked**, select the `extension/` folder.\n2. Restart Claude Code.\n\nThen ask for something like *\"open localhost:3000, run an accessibility audit\nand find the Sign Up button\"*: Claude Code calls `navigate`,\n`audit` and `find_text`. Because `navigate` already returns\nelement refs, `click(ref=\"n1\")` follows with no discovery turn in between.\n\n> **On ChromeOS/Crostini** install from the [Chrome Web\n> Store](https://chromewebstore.google.com/detail/chrome-bridge-for-claude/bioknpaeahidbelaljjohjofiloeodmb)\n> instead: an unpacked extension is dropped on every reboot, because the\n> container isn't mounted when Chrome starts.\n\n`install.sh` registers the MCP server with `--scope user`. To do it by hand:\n`claude mcp add --scope user chrome-bridge node /path/to/server/index.js`.\nFor `execute_js`, enable **Allow user scripts** in `chrome://extensions` →\nChrome Bridge → Details (on Chrome 135-137, enable Developer Mode instead).\n\n## Why Chrome Bridge?\n\n| | Chrome Bridge | Claude in Chrome | Chrome DevTools MCP | Playwright MCP |\n|---|---|---|---|---|\n| **ChromeOS / Crostini** | **Yes** (real host) | No | Container only | Container only |\n| **Tools** | **59** (38 core) | ~20 | ~50 | 23 core (71 total) |\n| **Requires paid plan** | **No** | Yes (Pro+) | No | No |\n| **Network mocking** | **Yes** (stub/headers) | No | No | Yes |\n| **Visual regression** | **Yes** (`screenshot_diff`) | No | No | No |\n| **Audits (a11y/SEO/sec)** | **Yes** (one call, report on disk) | No | Partial | No |\n| **Headless / CI** | **Yes** | No | Yes | Yes |\n| **GIF / video** | No | **Yes** | Partial | No |\n| **Breakpoints / heap** | No | No | **Yes** | No |\n\nIt wins on **round trips, not payload size**: short element refs instead of the\nscreenshot-and-click loop, `fill_form` filling N fields in one call, table\nfiltering done server-side. Per single turn it actually costs slightly *more*.\n\nThe full benchmark — method, every raw run including the unfavourable ones, and\nwhat the harness can't measure — is in\n[docs/EFFICIENCY.md](docs/EFFICIENCY.md).\n\n![Claude checks its own work: console errors, pixel diffs, network mocking and audits](assets/readme/card5-devloop.png)\n\n## Using it\n\nThe **skill** in [`skills/chrome-bridge/SKILL.md`](skills/chrome-bridge/SKILL.md)\nis what makes the tools discoverable: recipes with the phrase that triggers\neach one (\"verify the email arrives\", \"test the checkout with a test card\",\n\"which plugin slows the page\", \"what fires before consent\"), the tool sequence,\nand the zero-token CLI commands the model would otherwise never see.\n`install.sh` copies it to `~/.claude/skills/chrome-bridge`; do the same by\nhand for other clients.\n\nBeyond the MCP tools, two lanes keep work away from the model entirely.\n\n![Some jobs never touch the model: the CLI lane runs the same tools at zero tokens](assets/readme/card3-lane.png)\n\n**CLI** — batch operations, piped through `grep` or `jq` before anything reaches\nthe context:\n\n```bash\nchrome-bridge navigate --url https://example.com\nchrome-bridge read_console --level error | head -20\nchrome-bridge assert --selector \"#success\" --text \"Done\"\nchrome-bridge replay --file ./recordings/login.jsonl\n```\n\n**Launch mode** — a dedicated Chromium instance with an ephemeral profile, for\nisolated sessions or CI:\n\n```bash\nnode server/index.js --launch --headless\n```\n\nPair it with `session_record` + `replay` for smoke tests with no model in the\nloop. In launch mode `execute_js` falls back to `new Function` when the\nuser-script toggle isn't available.\n\n## Tools\n\n59 in total, in seven groups. Only `core` (38 tools) loads by default; the rest\nare opt-in via `--caps`.\n\n![59 tools in seven groups, from clicking a button to auditing a whole page](assets/readme/card4-toolbox.png)\n\n| Group | N | What's in it |\n|---|---|---|\n| Core & Navigation | 13 | tabs, windows, `navigate`, `screenshot`, `tile_windows` |\n| Interaction | 11 | `click`, `fill_form`, `upload_file`, dialogs, clipboard |\n| DOM & Inspection | 10 | `read_page`, `extract`, `query_dom`, `watch_dom` |\n| Debugging & Network | 8 | `execute_js`, console, network log, mocking, `track_events` |\n| Visual & Responsive | 5 | `screenshot_diff`, viewport and zoom, media emulation |\n| Audits | 2 | `audit` (a11y, keyboard, SEO, security, links, vitals, css, resources, cache in one call), `cookie_audit` |\n| State, Storage & Files | 9 | storage, fixtures, MHTML, recording, `assert` |\n\nEvery tool, with the notes that matter: [docs/TOOLS.md](docs/TOOLS.md).\n\n## How it works\n\n![It drives the Chrome you are logged into, over a local WebSocket bridge](assets/readme/card2-bridge.png)\n\n```\nClaude Code  <--stdio-->  MCP Server  <--WebSocket :8765-->  Chrome Extension\n                          (server/)                          (extension/, MV3)\n```\n\nThe Node.js server handles the protocol and tool logic; the MV3 extension\nexecutes commands through Chrome APIs. User scripts (`execute_js`) run via\n`chrome.userScripts.execute()`.\n\n## Configuration and security\n\nEnvironment variables, each with a matching CLI flag:\n\n| Variable | Default | Notes |\n|---|---|---|\n| `CHROME_BRIDGE_PORT` | `8765` | |\n| `CHROME_BRIDGE_HOST` / `--host` | `127.0.0.1` | `0.0.0.0` **only** where the browser lives outside the container (ChromeOS/Crostini port-forward) — and only with a token |\n| `CHROME_BRIDGE_TOKEN` | unset | Required on both `ext_init` and `relay_init`. Strongly recommended whenever the bind isn't loopback |\n| `CHROME_BRIDGE_CAPS` / `--caps` | `core` | `core`, `audits`, `visual`, `network`, `storage`, `dom`, `files`, `all`. `install.sh` uses `all` |\n\nThe bridge binds loopback, accepts extension connections only from a\n`chrome-extension://` origin, and — when a token is set — requires it on both\nhandshakes. Without one, any local process could act as a relay and reach\n`execute_js` inside your authenticated browser session. Secondary MCP instances\nconnect via loopback and are acknowledged with `relay_init_ok`, so a foreign\nprocess holding the port fails fast instead of timing out per command.\n\n**What is *not* protected:** page content reaches the model unfiltered, so a\nhostile page's text is untrusted input. `get_storage`, `session_fixture`, HAR\nexports and screenshots are **not** redacted and may carry cookies, tokens or\npersonal data. Don't point the automation at pages holding secrets you wouldn't\npaste into a chat.\n\n## Troubleshooting\n\n| Symptom | Cause / fix |\n|---|---|\n| `Chrome extension not connected` | Extension disabled, or its port differs from the server's. The error names the actual host/port; check them in the popup (⚙). |\n| Port 8765 already in use | Expected: a second MCP session becomes a **relay** and shares the one bridge. Set `CHROME_BRIDGE_PORT` for a separate one. |\n| `Port N is held by a process that is not chrome-bridge` | Something else owns the port. Free it or change `CHROME_BRIDGE_PORT`. |\n| `execute_js` fails | Enable **Allow user scripts** in `chrome://extensions` → Chrome Bridge → Details (Chrome 138+; on 135-137 enable Developer Mode). |\n| `read_console` returns `note=Instrumentation not loaded` | The page was opened before the extension, \"Capture console & metrics\" is off, or the page isn't injectable (`chrome://`). Reload it. |\n| Screenshot times out | On ChromeOS a fully occluded window stops producing frames; captures fail after 10s. Bring the window forward. |\n| Commands work, then stop | The MV3 service worker restarted and in-memory state (network log, diff baselines, HTTP auth) was reset. Re-run the monitoring call. |\n| Extension dropped on every ChromeOS reboot | Install from the Web Store instead of Load unpacked. |\n| Tool missing from the list | It's in an opt-in group. Check `get_status` → `caps_available`, then set `CHROME_BRIDGE_CAPS=all`. |\n\n## Documentation\n\n- [docs/TOOLS.md](docs/TOOLS.md) — all 59 tools, by group\n- [docs/EFFICIENCY.md](docs/EFFICIENCY.md) — the benchmark and the design behind it\n- [bench/RESULTS.md](bench/RESULTS.md) — raw runs and inclusion rule\n- [CHANGELOG.md](CHANGELOG.md)\n\n## Tests\n\n`npm test` (Chrome-free, ~22s) · `npm run test:e2e` (needs Chrome and a\nconnected extension; with a bridge already on 8765:\n`CHROME_BRIDGE_PORT=8799 node test/test-devtools.js --launch`, which opens\nits own Chromium with `extension/`) · `npm run measure` (schema cost).\n\n## License\n\nMIT\n",
  "bytes": 9563,
  "sha": "a2271c1f21281217ddcf237aa9c94a0fbec20a5c33810e66eeb35ba3c310d394",
  "repo_slug": "frsorrentino/chrome-bridge",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_frsorrentino_chrome_bridge_a6bf1088/readme"
}