Skip to main content
Glama
Soph1yzzz

ChromeBridge

by Soph1yzzz
README.md
# ChromeBridge

ChromeBridge is a local-first MCP bridge for controlling an **existing, already logged-in Chrome session** without exporting browser cookies, OAuth tokens, or Chrome profile data.

It is designed for the gap between a full computer-use agent and a simple HTTP fetcher: read the page that is already open, interact with DOM elements, upload an explicitly allowlisted local file, or download a file while keeping the browser session on the user's machine.

> Status: early OSS MVP (`0.3.0`). The local bridge, MCP/REST surfaces, MV3 extension, CDP controls, security boundaries, scoped Computer Use fallback contract, and automated tests are implemented. Real-site compatibility still needs broader manual testing before a stable release.

## Architecture

```text
ChatGPT / MCP client
        |
        | private/dev: OpenAI Secure MCP Tunnel
        | public: stable HTTPS endpoint (for example Cloudflare Named Tunnel)
        v
127.0.0.1:8765  ChromeBridge
        |
        | local authenticated WebSocket /extension
        v
Chrome MV3 extension
        |
        | chrome.debugger / Chrome DevTools Protocol
        v
Existing Chrome tabs and login session
```

The extension WebSocket is intentionally **not** part of the public tunnel ingress.

## Human Space / AI Tab Group

ChromeBridge `0.3.0` defaults to **Dedicated AI Tab Group** mode. It keeps AI work inside a native Chrome tab group named `ChromeBridge AI` in the same signed-in Chrome profile/session.

- Tabs outside the `ChromeBridge AI` group are **Human Space**: readable, but write actions are rejected in Dedicated mode.
- Tabs inside the group are writable: navigation, typing, clicking, uploads, downloads, and tab operations are allowed there.
- `browser_open_tab` creates a background AI-group tab by default, so the human active tab and OS focus are not stolen.
- `browser_select_ai_tab` selects ChromeBridge's preferred AI working tab without visually activating it; `browser_activate_tab` is the explicit foreground/focus path. `browser_switch_tab` is retained as a deprecated compatibility alias.
- AI interactions render a page-local **virtual AI cursor** and `AI TAB GROUP` badge. The Windows mouse cursor is never moved by ChromeBridge.
- Clicking the extension action opens a Chrome **Side Panel** showing bridge state, the AI group, AI tabs, and controls to create/expand/collapse the group.

Users who explicitly want the original unrestricted behavior can switch to `Shared mode` in extension options.

## v0.3 Agent Ergonomics

ChromeBridge 0.3 keeps the explicit Human/AI boundary while reducing how much Chrome/CDP implementation detail an agent must reason about.

- `browser_find` returns richer state including `visible`, `enabled`, `checked`, `selected`, `value`, `href`, and `rect`; use `visible_only=true` for action targets.
- `browser_get_element_state` re-checks a previously found element without mutating it.
- `browser_select_ai_tab` changes the background ChromeBridge work target without stealing focus.
- `browser_activate_tab` is the explicit foreground escalation path for pages that genuinely require an active/focused Chrome tab.
- `browser_switch_tab` remains as a deprecated compatibility alias for background selection.
- Click/double-click can take a small `expect` post-condition and report `transport_success` separately from `effect_verified`. If a background input is delivered but the expected effect is not observed, ChromeBridge can return `requires_foreground=true` instead of silently stealing focus.
- Hidden/no-box/disabled elements have distinct error codes instead of being collapsed into `ELEMENT_STALE`.
- ChromeBridge's visual AI overlay is excluded from normal page text/search data.

See [docs/ROADMAP.md](docs/ROADMAP.md) for the provisional direction after v0.3.

## Chrome-authoritative routing and Computer Use fallback

ChromeBridge is the authoritative path for ordinary Chrome/web-page interaction. MCP initialization includes routing instructions that tell capable clients not to silently switch to OS-level Computer Use while ChromeBridge can handle the task.

The extension exposes a `browser_get_routing_policy` tool and three fallback modes:

- `Chrome-only automatic` (default): Computer Use is eligible only for explicitly unsupported Chrome UI/native-dialog surfaces, such as `chrome://...` browser UI. The fallback scope is `chrome-only`, and control should return to ChromeBridge immediately afterward.
- `Ask before fallback`: the same surfaces are eligible, but the user must be asked first.
- `Disabled`: Computer Use fallback is denied.

Normal automation failures are **not** fallback triggers. Missing/stale elements, timeouts, debugger failures, domain-policy blocks, and file-policy failures stay inside ChromeBridge for retry/repair instead of moving the physical mouse. When ChromeBridge detects a Chrome-internal surface it returns structured `error.details.fallback` metadata with `action=auto|ask_user|deny` and `scope=chrome-only`.

This is a routing contract for MCP/agent hosts; ChromeBridge cannot technically disable a separate Computer Use tool owned by the host. Hosts that ignore MCP instructions can still bypass this policy.

## What it can do

Read operations include tab listing, active-tab state, page text/DOM summaries, accessibility data, element search, screenshots, page-state inspection, and recent downloads.

Action operations include click, double-click, hover, text entry, key presses, scrolling, navigation, history/reload, tab open/close, background AI-tab selection, and explicit foreground activation.

File operations include uploading files from allowlisted local roots with `DOM.setFileInputFiles`, triggering downloads, and listing recent downloads.

## What it intentionally does not expose

ChromeBridge does not provide tools for cookies, OAuth tokens, localStorage dumps, Chrome profile export, arbitrary local filesystem reads, arbitrary CDP command execution, or arbitrary JavaScript execution supplied by the remote MCP client.

## Security model

The bridge refuses to bind to `0.0.0.0` and only listens on loopback. The MCP endpoint uses Bearer authentication. The compatibility REST endpoint uses HMAC-SHA256 over method, path, timestamp, nonce, and the exact raw request-body hash, with a replay window and nonce cache. Extension pairing uses a separate random token.

Local uploads are deny-by-default outside configured roots. Paths are canonicalized with `realpath`, UNC/device paths are rejected, browser profile/credential-store files are blocked even if they appear under an allowlisted directory, file size and extension limits are enforced, and only regular files are accepted.

Navigation only permits `http:` and `https:` URLs. Optional hostname allowlisting can restrict browser actions further.

See [SECURITY.md](SECURITY.md) and [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md).

## Requirements

- Windows 11 is the primary tested platform for the MVP.
- Node.js `>=20.12`.
- Google Chrome with Manifest V3 extension support.
- OpenAI `tunnel-client` is recommended for private ChatGPT/development connections.
- `cloudflared` is optional for a stable public MCP endpoint.

## Quick start on Windows

1. Run PowerShell from the repository root:

   ```powershell
   .\scripts\setup.ps1
   ```

   This installs pinned npm dependencies and creates `.env` with independent random MCP, REST-HMAC, and extension-pairing secrets.

2. Open `chrome://extensions`, enable Developer mode, choose **Load unpacked**, and select the `extension` directory.

3. Open the ChromeBridge extension options page and paste the extension pairing token printed by `setup.ps1`. The default bridge URL is `ws://127.0.0.1:8765/extension`. If `8765` is occupied, change `CHROMEBRIDGE_PORT` and the extension URL to the same loopback port.

4. Start the local bridge:

   ```powershell
   .\scripts\start-local.ps1
   ```

   After Secure MCP Tunnel registration, users who do not want a visible PowerShell console can install a hidden Windows Startup launcher once:

   ```powershell
   .\scripts\install-background-startup.ps1 -TunnelId tunnel_...
   ```

   On future Windows sign-ins, ChromeBridge and the Secure MCP Tunnel start as hidden background processes. The Chrome extension remains the user-facing control surface.

5. Verify locally:

   ```powershell
   Invoke-RestMethod http://127.0.0.1:8765/health
   ```

For OpenAI Secure MCP Tunnel (recommended for private ChatGPT use), public hosting, and ChatGPT registration, see [docs/SETUP_WINDOWS.md](docs/SETUP_WINDOWS.md).

## MCP endpoint

The stateless Streamable HTTP endpoint is:

```text
POST /mcp
Authorization: Bearer <CHROMEBRIDGE_MCP_TOKEN>
```

The MCP server exposes focused browser tools rather than a generic `cdp_command` escape hatch. Read-only tools are annotated as read-only; browser actions are annotated as writes/open-world operations where appropriate.

## Compatibility REST endpoint

`POST /api/v1/tool` is retained for clients that need the original JSON contract. Required headers:

```text
X-ChromeBridge-Timestamp
X-ChromeBridge-Nonce
X-ChromeBridge-Signature
```

Canonical HMAC input:

```text
METHOD\n
PATH\n
TIMESTAMP\n
NONCE\n
SHA256(EXACT_RAW_BODY)
```

The signature is `HMAC-SHA256(CHROMEBRIDGE_HMAC_SECRET, canonical_message)` encoded as lowercase hex (an optional `sha256=` prefix is accepted).

## Configuration

Copy `.env.example` if configuring manually. Important variables:

- `CHROMEBRIDGE_MCP_TOKEN`
- `CHROMEBRIDGE_HMAC_SECRET`
- `CHROMEBRIDGE_EXTENSION_TOKEN`
- `CHROMEBRIDGE_FILE_ROOTS` — semicolon-separated local roots
- `CHROMEBRIDGE_FILE_EXTENSIONS`
- `CHROMEBRIDGE_MAX_FILE_BYTES`
- `CHROMEBRIDGE_DOMAIN_ALLOWLIST` — optional semicolon-separated hostname allowlist

Never commit `.env` or Cloudflare tunnel credentials.

## Tests

```powershell
npm test
npm run check
npm audit --omit=dev
```

The current suite covers HMAC/raw-body verification, replay rejection, Bearer auth, Host-header protection, domain policy, local-file policy, request dedupe, authenticated WebSocket pairing, and bridge-to-extension RPC behavior.

## OpenAI Plugin packaging

`.codex-plugin/plugin.json` is included. An `.app.json` file is deliberately not committed with a fake identifier: after registering the MCP server in ChatGPT/OpenAI, use the real generated `plugin_asdk_app...` technical ID for the app mapping.

## License

MIT. See [LICENSE](LICENSE).