# chrome-bridge [Health: Active]

**Category:** 📂 Browser Automation  
**Repository:** https://github.com/frsorrentino/chrome-bridge  
**GitHub Stars:** 6  
**npm Downloads (last month):** 4371  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/chrome-bridge

## Description
Your real, logged-in Chrome as an MCP server: 60 token-efficient web-dev tools. ChromeOS included.

## Tools
Capabilities this server exposes over MCP:

- **get_status** — Status of the bridge itself, not of a page: call it when a tool you expect is missing or browser commands fail (connected=false: the extension is not reachable, extension_install gives its Chrome Web Store link). Also reports mode (primary/relay), host, port, server and extension versions, js_evaluation (false under --no-js), write_root, read_root, session_tab_id (the implicit tab), owned_tabs (created by this session), uptime_sec. caps_active and caps_available: a missing tool lives in an inactive cap. enable is the only change it makes: it switches caps on for this session, no restart, and lists the tools added. Optional caps: audits (cookie_audit); visual (inject_css, measure_spacing, emulate_media, viewport_resize); perf (animations, frames, perf_trace, screencast, lighthouse, heap_snapshot); network (http_auth, set_geolocation, track_events); storage (get_storage, set_storage, session_fixture); dom (modify_dom, watch_dom, drag_and_drop); files (save_page, manage_downloads, session_record).
- **get_tabs** — List every open tab with id, url, title, active flag and mine (created by this session). Find a tab_id when the implicit target is not the one you mean. include_windows adds position, size, state and type of each window — needed before moving or tiling. Session tabs gone since the last call come back once in closed_session_tabs with the reason (closed, window_closed, replaced, closed_by_bridge).
- **navigate** — Navigate a Chrome tab to a URL and wait for the load; DNS and connection errors fail the call. Without tab_id it reuses the tab this session last navigated or created, else opens a new one rather than taking over the active tab. Returns a preview of interactive elements with refs usable in click/type_text/hover, plus the first console errors and failed requests, if any.
- **screenshot** — Screenshot of the visible viewport only (PNG), at the current scroll position, or one per viewport preset with presets. Read-only. Activates the tab in the background without stealing window focus, then restores the previous tab. Downscaled to ≤1568px: for fine print, element_screenshot with scale.
- **execute_js** — Run JavaScript in the page (MAIN world). Requires the extension's "Allow user scripts" toggle; errors explain setup if disabled. Use it when no dedicated tool fits: extract or extract_table read data, query_dom inspects elements, inject_css restyles, and none of them needs the toggle. A promise is awaited up to timeout. A cut result stays valid JSON and says truncated; save_to writes the whole result to disk.
- **click** — Click an element by CSS selector or by a ref (n1, n2…) from get_interactives or navigate. A real pointer sequence: it can submit, open a dialog or navigate — use wait_after. Not idempotent; a native confirm() blocks the bridge: handle_dialogs first. Returns page_changed (url, title and DOM deltas: nodes, text, open, expanded, checked, dialogs, focus): the effect, without a screenshot; when the click opens or reveals something, the refs of the visible interactives follow, no get_interactives needed.
- **type_text** — Put text into an input, textarea or contenteditable, by selector or ref. Replaces the whole value through the native setter (React/Vue controlled inputs register it) and fires input and change. mode=keys emits keydown/input/keyup per character for autocomplete and masked fields: slower, use it only when mode=set leaves the field empty. Returns value_after; mismatch=true means the field did not keep the value: retry with mode=keys.
- **read_page** — Read the page as text (default), markdown, raw HTML, or accessibility tree. Read-only. markdown keeps headings, links and tables at a fraction of the HTML cost. Expensive on big pages: HTML on a large table costs tens of thousands of tokens for data you filter anyway — prefer extract_table/extract for repeated content, get_interactives for click targets.
- **get_page_info** — Page metadata: title, url, visibility, doctype, charset, meta tags, scripts, stylesheets, links and forms. visibility=hidden means the window is minimized, covered or in the background: the page does not render (screenshots fail) and its timers slow down. dev.server names a dev server (vite, webpack-dev-server, next, nuxt) and dev.overlay carries the compiler message when an error overlay is open: read it before treating the page as valid. For the text use read_page, for specific elements query_dom, for the bridge itself get_status.
- **query_dom** — Query DOM elements by CSS selector, returning structure, attributes, bounding rect and, with properties, computed styles. Use it when you already have a selector (no match: count 0); to find one, get_interactives or find_text; for the rule that set a style, get_css_styles.
- **get_css_styles** — Why an element looks the way it does: for each CSS property the winning declaration — selector, stylesheet, rule position, !important, @layer, @media — and the ones it overrides, like the Styles panel of DevTools; query_dom gives the computed value, this gives who set it. Read-only, from the CSSOM: stylesheets of another origin without CORS are opaque and listed by href; user-agent styles, @container and @scope rules are not evaluated. properties narrows the output.
- **read_console** — Read console messages captured since page load, incl. uncaught errors and unhandled rejections. clear deletes the messages it returns, hence not read-only; since=cursor reads only newer ones without deleting, and failed requests are in monitor_network.
- **monitor_network** — Monitor network requests. source=page: XHR/fetch hook (installed on first call); source=browser: all requests incl. static assets; source=websocket: connections and messages. format=har exports HAR 1.2. It only observes: to block, stub or rewrite requests use network_rules, to send one yourself http_request.
- **create_tab** — Open a new tab, optionally at a URL, and make it the implicit target of later commands in this session. Each call creates another tab: reuse a tab_id or navigate() to move an existing one instead of piling up tabs.
- **wait_for** — Block until a condition holds: element, text, function (JS expression; needs the "Allow user scripts" toggle), navigation (mode=spa for client-side routes), network_idle. Polls until timeout (10s element/function, 15s the rest) then **returns `found: false` with a reason instead of raising**: check it, or a failed wait reads as success. Read-only.
- **scroll** — Scroll. action=to: once to element/coordinates; action=until: repeatedly until element visible, network idle, or no new content (infinite scroll). It moves the tab's scroll position and returns it (to) or stopped_reason and steps (until); full_page_screenshot scrolls by itself, wait_for waits without scrolling.
- **fill_form** — Batch fill form fields with React-compatible events. Handles input, select, checkbox, radio, and textarea. Fields and submit take a CSS selector or a ref (n1, n2…) from navigate/get_interactives. With submit_selector it also submits, so a repeated call submits twice — not safe to retry blindly; after a submit, after_submit carries url, title and the text the page gained (the confirmation or the errors). Each field reports value_after and mismatch; page_changed carries the DOM delta, and the refs of what appeared.
- **element_screenshot** — Screenshot cropped to one element or to a viewport region (PNG), optionally enlarged. Read-only. The cheapest image in the set, because it carries only the box you asked for — and with scale the way to read fine print: crop the box, zoom it, verify.
- **full_page_screenshot** — Full-page capture by scrolling: stitched segments of ~2 viewports (≤1568px), or one image per viewport with stitch=false. Expensive: ~2.7k image tokens per segment, only max_segments returned, the rest via segment_offset. Reading the text you need is cheaper by an order of magnitude — prefer read_page, extract or find_text unless layout is the question.
- **hover** — Hover over an element, by CSS selector or ref. Default: synthetic mouseenter/mouseover/mousemove, which fire JS hover handlers but not CSS :hover. trusted moves the real mouse pointer (chrome.debugger), so CSS :hover rules and their transitions apply.
- **press_key** — Send a key to the focused element (or to selector, focusing it first) as a real keydown/keypress/keyup sequence, so framework handlers fire. For typing a value use type_text; this is for Enter, Tab, Escape, arrows and shortcuts. Not idempotent: two calls send the key twice. Returns page_changed like click; when the key opens or reveals something, the refs of the visible interactives follow.
- **get_frames** — List frames (main + iframes) with frameId, parent, URL — for the frame_id parameter of DOM tools.
- **tab_action** — Tab lifecycle: close, activate, reload, back, forward, discard, mute, duplicate, close_session (only tabs this session created). close drops unsaved work and cannot be undone — it may be the user's tab. reload drops injected CSS, emulations and hooks. duplicate works where create_tab is forbidden (chrome-untrusted://) and lands in the source window, app windows included. discard replaces the tab id.
- **upload_file** — Set a file on input[type=file] from the server filesystem via DataTransfer (max 200 MB; over 6 MB it travels in pieces). Keys and credentials (~/.ssh, ~/.aws, ~/.gnupg, .env*, *.pem, *.key, id_*…) are refused, and a --read-root on the server limits the readable tree: the call fails with an error, nothing is read.
- **dismiss_overlays** — Dismiss cookie banners/modal overlays: OneTrust, Cookiebot, Usercentrics, then generic heuristic. Idempotent.
- **handle_dialogs** — Auto-accept/dismiss future JS dialogs (alert/confirm/prompt), logging them. reset restores native dialogs and returns the log.
- **find_text** — Find text on the page: parent selector, context, visibility, position per match. Attaches nearby interactive elements (with refs for click/type_text/hover) for the first visible match. Use it when you know the words on screen but not the selector (query_dom needs one); no match returns count 0.
- **network_rules** — Network interception, browser-wide, survives reloads until cleared: block, redirect, set/remove headers, stub a synthetic body, or record real API responses and replay them with forced errors/latency (local helper; from HTTPS pages the stub host must be trusted). It changes traffic, while monitor_network only observes it and http_request sends one request; each rule comes back as added, list shows them, clear removes them all.
- **screenshot_diff** — Visual regression: save a named baseline (viewport, element, or a PNG such as the design mockup) and compare later — changed-pixel % and a red-highlighted diff; or compare_urls: production vs staging in this tab, pixels plus text diff, logged-in pages included. Baselines are in-memory (lost on service worker restart).
- **handoff** — Hand the browser to the user for what only a person can do — 2FA, CAPTCHA, login, a choice — and wait: a banner in the page shows your message with Done/Cancel, the call returns on click or timeout, redirects included. pick_element: the user clicks an element and you get its selector. Never type credentials yourself. ask: the user types a reply in the banner ("which of the three?") and you get it as answer. pick_max: with pick_element, up to N elements; the user presses Done when finished.
- **watch** — Keep watching a page in the background — "tell me when the pipeline is green / the Approve button appears / this number changes" — checked every interval_s by the extension. Events are collected, not pushed: action=poll, or a script blocking on "chrome-bridge watch --wait <name>". Survives extension idling, not a browser restart. poll returns one line per event (time, name, kind, url, value, previous); a change due within seconds is wait_for.
- **read_form** — Read a form as the user filled it — label, type, value, checked/selected, required-but-empty, browser validity — to check it against the project's documents before an irreversible Submit. Password and card values come back [redacted]. Read-only, on request; to change values use fill_form.
- **audit** — One-call page audit, pick the kinds: accessibility, keyboard (tab order and focus issues), SEO, security headers, broken links, Core Web Vitals, unused CSS, resources (which plugin/theme/module/host slows the page), cache (is the CDN serving the new version). A summary line per kind; with save_to the full Markdown report with every finding. Read-only. For one deep look at load speed use perf_trace, for Lighthouse scores lighthouse.
- **find_setting** — Where is a setting in an unknown admin panel: follows the panel's menu links (same origin) until a page contains the keyword. Returns the URL, the menu path (Settings › Media) and the matching text; when nothing matches, how many pages it tried. Navigates the tab and leaves it on the last page visited, at most max_pages.
- **extract_table** — Read a real <table> as JSON: thead cells become keys, each row an object. Only for tabular markup — `where` filters rows server-side, so one matching row out of 1500 costs a few hundred bytes instead of the whole document. `row_count` is the table total, `match_count` how many rows passed the filter. No table at index is an error saying how many the selector found; for cards and lists use extract.
- **clipboard** — Read or write the system clipboard (text). Activates the tab and focuses its window first. write overwrites whatever the user had copied, which is not recoverable. To fill a field use type_text instead of write and paste; read checks what a Copy button copied, and an empty clipboard returns text "".
- **capture_downloads** — Save files the page builds itself, with no browser download and no "Save as" dialog: blob and data URL links (a[download]), window.showSaveFilePicker writes, and downloads the page starts (cancelled at once, bytes fetched again with the browser cookies). arm with save_dir, then click Export/Download, then wait: it returns the saved paths. A file with a URL: http_request save_to instead. Names are cleaned, existing files never overwritten, size capped by max_mb.
- **http_request** — HTTP request sent from the browser, with the logged-in user's cookies: fetches what a server-side request gets a login page for (invoices, authenticated JSON, exports). Text bodies inline (capped by max_length); save_to writes the bytes — the way to read a PDF, since read_page returns nothing on a PDF tab, and the way to save any file that has a URL: no click on Download, no browser download, no "Save as" dialog.
- **move_tab** — Move an existing tab into another window (chrome.tabs.move), keeping id, history and page state; works on chrome-untrusted:// tabs too. The **destination** must be a normal window: out of an app/popup window is fine, into one is refused. A ChromeOS Terminal tab can be pulled out (new_window, window_type popup) but never merged back: extensions cannot create app windows.
- **tile_windows** — Tile Chrome windows over one monitor in equal parts with no gap. Only Chrome windows. The monitor is the one of a window already on it, whose work area is read from a page there: at least one target needs a scriptable tab (not chrome://). Maximized windows are restored first, since maximized ignores bounds. To restore a saved arrangement use window_layout; to move one tab into another window, move_tab.
- **window_layout** — Save the current window arrangement under a name, restore, list or delete. save overwrites silently. Window ids do not survive a browser restart: restore matches windows by the overlap of their tab URLs and reports the ones it cannot recognise instead of guessing.
- **get_interactives** — List actionable elements (buttons, links, inputs, [role], [onclick]) with ready-to-use CSS selector, label, position, flags. Prefer this over dumping HTML to discover selectors. Document order, cut at limit (count equal to limit: there may be more), each with a ref (n1, n2…) for click, type_text and hover.
- **extract** — Read repeated non-tabular structures — product cards, list items, search results — as one record per item: item_selector matches the repeating block, fields map output names to selectors relative to it. Read-only, deterministic, parsed server-side from the main-document HTML. Default output: total and shown, then one tab-separated row per item under the field names; a field with no match is empty (null in json).
- **assert** — Assert a page condition, polling until timeout: element exists/visible (optionally with count or containing text), text on page, tab url/title. Patterns: substring, or "/…/" for regex. Recorded flows replay it as a test. Unlike wait_for, which returns found: false, a failure is an error naming what did not match; success returns passed and waited_ms.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "chrome-bridge": {
    "command": "npx",
    "args": ["-y","chrome-bridge-mcp"]
  }
}
```

## Documentation

## What chrome-bridge does

chrome-bridge gives an MCP client access to a real Chrome session instead of starting with a blank browser profile or requiring a remote browser service. The agent can use sites where you are already signed in, along with the session's cookies and installed extensions. It can open and operate its own tabs while leaving your existing tabs untouched; agent-owned tabs are closed when the session ends.

The toolset is aimed at web development and browser automation. It covers navigation, DOM and text inspection, element interaction, form filling, console checks, accessibility, SEO and security audits, screenshots, visual comparison, and network behavior. Server-side table filtering helps keep large-page responses smaller. A separate CLI can run batch operations through shell tools such as `grep` and `jq` without sending every intermediate result through the model.

## How it works

The local MCP server connects to the Chrome extension through a local WebSocket bridge. The extension runs inside the Chrome profile you are using, so authentication remains in that browser. When an action requires a person, `handoff` displays an in-page banner describing the required step. You can complete a login, enter a 2FA code, solve a CAPTCHA, answer a question, or select page elements; the agent then continues from its previous state.

The server also supports launch mode for isolated browser sessions and CI. It can start a dedicated Chromium-based browser with an ephemeral profile, including headless operation. Recording a session with `session_record` and replaying it with `replay` supports smoke tests without a model in the loop.

## Setup and configuration

The runtime requirements are Node.js 18 or newer and Chrome 135 or newer. The standard setup clones the repository, runs `install.sh`, loads the `extension/` directory as an unpacked extension from `chrome://extensions`, and restarts Claude Code. The script registers the MCP server for the user scope. Manual registration uses `claude mcp add --scope user` with the server's `index.js` path.

The project also provides a Claude Code plugin that installs the npm-based MCP server and its recipes skill. Use either the plugin route or `install.sh`, not both, because each registers the same server. On ChromeOS with Crostini, install the extension from the Chrome Web Store. On Windows, use the plugin, Git Bash, or a supported browser launch configuration rather than running `install.sh` from PowerShell or Command Prompt.

For `execute_js`, enable user scripts in the Chrome Bridge extension settings. In launch mode, `CHROME_BRIDGE_BROWSER` can select a browser binary. Chromium, Microsoft Edge, Brave, and Chrome for Testing are supported launch choices; Google Chrome 137 and newer does not load the extension in this mode.

## Tools and capabilities

- Navigate pages and return element references for follow-up actions such as clicking.
- Inspect the DOM, find text, fill multiple form fields, and interact with page elements.
- Run accessibility, SEO, and security audits with reports written to disk.
- Read console output, assert selectors and text, and execute JavaScript.
- Capture screenshots, compare images with `screenshot_diff`, and inspect visual changes.
- Stub network responses or add request headers for network testing.
- Record and replay browser sessions, including headless CI workflows.
- Pause for human input through an in-page `handoff` banner.

## Limitations and notes

The browser extension must be installed and connected to the local server. ChromeOS requires the Web Store installation because unpacked extensions are removed after reboot. The browser's existing authentication is available to the agent, so use an appropriate Chrome profile and treat access accordingly.

The server is self-hosted and local-only. Launch mode is intended for isolated profiles and CI, while normal operation uses the Chrome profile already open on the computer. Claude Code is the documented client workflow; in claude.ai, the plugin loads its recipes skill, but the browser tools require Claude Code or Cowork running on the computer.

_Full upstream README: https://allmcps.com/mcp/chrome-bridge/readme_

