Skip to main content
Glama
README.md
# cc-chrome-bridge

Browser control for **Claude Code** (and any MCP client) that uses your **existing signed-in Chrome profile**.

Works with **Bedrock**, LiteLLM, or any model backend — because the model never touches the browser at all. It only sends tool calls; a zero-dependency Node bridge forwards them to a companion Chrome extension that does the real work via CDP (Chrome DevTools Protocol) in your normal tabs. No Playwright, no fresh profile, no cookies to copy, and no first-party Anthropic API required — which is exactly why it works where Anthropic's built-in "Claude in Chrome" tool doesn't on Bedrock.

```
Claude Code / any MCP client          bridge-mcp.js                  your Chrome profile
        |  MCP stdio (JSON-RPC)           |                                |
        |-------------------------------->|                                |
        |   chrome_snapshot, etc.         |  long-poll GET /next?name=...  |
        |                                  |<----------------------------|
        |                                  |-- command {id,action,params} ->|
        |                                  |<- POST /result {id,ok,result}-|
        |<---------------------------------|                                |
```

## Why not the built-in browser tool?

Claude Code's native chrome integration (`--chrome-native-host`) authenticates against Anthropic's first-party API. On Bedrock (or any proxy) that auth path doesn't exist, so the tool is unavailable. This project sidesteps the problem entirely: it's a dumb pipe plus an extension — model-agnostic by construction.

## Features

- **Your real profile** — signed-in sessions, cookies, and extensions are all live; no re-login, no parallel browser instance
- **DOM-based, not vision-based** — `chrome_snapshot` returns structured text (stable element uids, visible actions, form fields), so it works with text-only models. Screenshots via CDP are available as an optional layer for multimodal models
- **Real input events** — clicks/typing go through Chrome's actual input layer (CDP), satisfying normal user-activation gates; bypasses page CSP because injection happens at the browser level, not in page JavaScript
- **Background mode by default** — tools never steal focus or activate tabs. New/grouped tabs join a per-session tab group ("Claude Code"). Pass `"background": false` on a call to allow foreground work
- **Zero dependencies** — one Node file (Node 18+), no npm install

## Quickstart

Requires: Node 18+, Chrome with [Developer mode](chrome://extensions) enabled.

```bash
git clone https://github.com/joshoq/cc-chrome-bridge
cd cc-chrome-bridge
```

1. **Load the extension** (one-time, manual — it uses a native file picker):
   - `chrome://extensions` → enable *Developer mode* → *Load unpacked* → select `browser-extension/`
   - It appears as "CC Chrome Bridge". Keep that Chrome window open; the MV3 service worker polls the bridge.

2. **Run the bridge** (keep it running — use your service manager for persistence):
   ```bash
   node bridge-mcp.js
   # listens on 127.0.0.1:17318, waits for MCP requests on stdin
   ```

3. **Register with Claude Code**:
   ```bash
   claude mcp add cc-chrome -- node /path/to/cc-chrome-bridge/bridge-mcp.js
   ```
   Verify in a session with `/mcp` — you should see `cc-chrome` connected with 21 tools.

4. **Verify end-to-end**: ask Claude to list your open tabs (`chrome_tab`, action `list`). The first call may take a moment while the service worker wakes up (MV3 workers sleep after ~5 min idle; any tab activity wakes them).

### Other MCP clients

`bridge-mcp.js` is a standard MCP stdio server — point any client at it:
```json
{ "mcpServers": { "cc-chrome": { "command": "node", "args": ["/path/to/bridge-mcp.js"] } } }
```

## Tools (21)

| Tool | Purpose |
|---|---|
| `chrome_launch` | Check bridge status; optionally open a URL in the existing profile |
| `chrome_tab` | List / create / activate / close / group / ungroup tabs (`list`, `new`, `activate`, `close`, `group`, `ungroup`, `version`) |
| `chrome_snapshot` | Agent-friendly page observation: stable uids, visible actions, form fields; zoom with `mode`/`query`/`nearUid` |
| `chrome_find` | Find controls/text by natural-language query → ranked matches with uids + coordinates |
| `chrome_inspect` | Deep context around one uid/selector: nearby text, actions, ancestors, suggested click target |
| `chrome_navigate` | Navigate a tab (never replaces your active tab without an explicit target); optional `initScript` at document_start |
| `chrome_evaluate` | Run JS in the page's MAIN world via CDP — works under strict CSP |
| `chrome_click` / `chrome_type` / `chrome_fill` / `chrome_key` | Real-input actions by uid, selector, or coordinate; optional fresh snapshot after |
| `chrome_wait_for` | Poll until a selector exists or an expression is truthy |
| `chrome_list_console_messages` / `chrome_list_network_requests` / `chrome_get_network_request` | Captured console + XHR/fetch activity (with response bodies) |
| `chrome_screenshot` | CDP screenshot to disk (PNG/JPEG, optional full-page tiles); no tab activation |
| `chrome_hover` / `chrome_drag` / `chrome_tap` / `chrome_scroll` | Pointer movement, drag, real touch events, momentum-shaped wheel scroll |
| `chrome_upload_file` | Attach local files to `<input type=file>` without the native picker |

All tools accept optional targeting: `targetId`, `urlIncludes`, or `titleIncludes`. Without a target they act on this session's dedicated automation tab — never your active tab.

## Security model

- **Loopback only** — the bridge binds `127.0.0.1`; nothing is exposed to the network
- **Origin-gated endpoints** — `/next` and `/result` accept requests only from `chrome-extension://` origins (403 otherwise); CORS headers are issued solely for extension origins
- **No secrets in transit** — commands/results stay between your local bridge and your own browser; the model sees tool results, not raw credentials
- The extension needs broad permissions (`<all_urls>`, `debugger`) because it performs CDP work on your behalf — load it only in a profile you trust an agent with

## Environment variables

| Variable | Default | Purpose |
|---|---|---|
| `CC_CHROME_BRIDGE_PORT` | `17318` | Bridge port. Must match the extension's hardcoded URL (`service_worker.js` line 1) — change both together |
| `CC_CHROME_SESSION_KEY` | `claude-code` | Session key scoping tabs/groups per agent session (run multiple agents with different keys to keep their tab groups separate) |

## Self-test (no Chrome needed)

```bash
node bridge-selftest.mjs
```

Exercises the full protocol on port 17999: MCP handshake, `tools/list`, long-poll command delivery, `/result` round-trip resolving a pending tool call, origin gating, and background-mode enforcement.

## Troubleshooting

- **Tool times out with "extension is not polling"** — the extension isn't running or its service worker is asleep. Check chrome://extensions shows CC Chrome Bridge enabled; open any tab in that profile to wake it
- **Port 17318 already in use** — another bridge owns it (e.g., a Pi session on the same machine). Set `CC_CHROME_BRIDGE_PORT` and patch `BRIDGE_URL` in `service_worker.js` line 1 to match
- **"Tab activation is blocked by background mode"** — expected. Pass `"background": false` in that tool call if you truly need foreground focus

## License

MIT — see [LICENSE](LICENSE).

The `browser-extension/` directory is derived from [pi-chrome](https://github.com/tianrendong/pi-chrome) (© pi-chrome contributors, MIT) — see [browser-extension/LICENSE](browser-extension/LICENSE).

TDQS

B3.1/5.0

Scored across 21 tools

Disambiguation4/5

Tools are largely distinct, each targeting a specific action (click, type, fill, key, hover, drag, tap, scroll, etc.). Minor overlap exists between snapshot/find/inspect for element discovery and between fill/type for text input, but descriptions clearly differentiate them.

Naming Consistency3/5

Most tools follow a chrome_verb_noun pattern (navigate, evaluate, click, type, wait_for, upload_file), but a few use bare nouns (tab, snapshot, launch) which breaks consistency. Mixed conventions but still readable and predictable.

Tool Count3/5

21 tools is on the higher end for a server, but the breadth of Chrome automation (navigation, interaction, inspection, debugging, tab management) justifies the count. Slightly heavy but not excessive.

Completeness4/5

Covers a comprehensive set of browser automation capabilities: navigation, user input, element inspection, JavaScript evaluation, waiting, console/network monitoring, screenshots, file uploads, and tab management. Missing explicit cookie/storage controls, but these can be handled via evaluate.

Maintenance

ActivityMaintained
ResponsivenessNo issues