Atlas / MCP servers / frsorrentino / chrome-bridge

chrome-bridgeBLOCK

mcp/frsorrentino/chrome-bridge

Chrome Bridge by frsorrentino — your real, logged-in Chrome as an MCP server for Claude Code: 60 measured, token-efficient tools. ChromeOS included.

Verdict
BLOCK
Grade
D
Trust score
61 /100
Exposed tools
66 48r · 12w · 6d
Transport
stdio
License
MIT
Stars
5
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

By frsorrentino · npm chrome-bridge-mcp · not affiliated with other projects named "chrome-bridge".

[](https://chromewebstore.google.com/detail/chrome-bridge-for-claude/bioknpaeahidbelaljjohjofiloeodmb)

Claude Code borrows a tab from the Chrome you are already using — signed in, with your extensions and your cookies — works in it, and hands it back. What only a person can do (a login, a 2FA code, a CAPTCHA, a choice) comes back to you through `handoff`: a banner in the page, you act, the agent continues.

Measured against the official browser extension (paired runs, 29/09/2026, n=5 per task, same model): filling a form, 4.7× fewer turns and 2.8× lower cost; finding one row in a 1,500-row table, 2.3× fewer turns and 3.4× lower cost; debugging a broken page, 9.3× fewer turns and 4.3× lower cost. 15 correct answers out of 15, against 12 (bench/RESULTS.md). ~3× the toolset and no paid plan. 60 web-development tools (navigation, DOM inspection, visual regression, audits, network mocking) over a local WebSocket bridge, plus a headless instance for CI. Self-hosted, local-only. Works on ChromeOS.

Quickstart

Requires Node.js 18+ and Chrome 135+.

git clone https://github.com/frsorrentino/chrome-bridge.git
cd chrome-bridge && ./install.sh
  1. Open chrome://extensions, enable Developer mode, click **Load

unpac

Read from source at commit 3661aac0f719OBSERVED · 2026-10-11
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add chrome-bridge-mcp -- npx -y [email protected]
03

Exposed tools (66)

48 read · 12 write · 6 destructive. Blast radius: 6 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
animationsreadList the page animations: CSS animations, transitions, Web Animations and View Transitions, each with selector and ref,
assertreadAssert a page condition, polling until timeout: element exists/visible (optionally with count or containing text), text on page, tab url/title. Patterns: substring, or
auditwriteOne-call page audit, pick the kinds: accessibility, keyboard (tab order and focus issues), SEO, security headers, broken links,
clickreadClick an element by CSS selector or by a ref (n1, n2...) from get_interactives or navigate. A real pointer sequence: it can submit,
clipboardwriteRead or write the system clipboard (text). Activates the tab first.
cookie_auditreadCookie and consent-banner audit: clears this site\
create_tabwriteOpen a new tab, optionally at a URL, and make it the implicit target of later commands in this session.
dismiss_overlaysreadDismiss cookie banners/modal overlays: OneTrust, Cookiebot, Usercentrics, then generic heuristic. Idempotent.
drag_and_dropdestructiveDrag an element onto another. html5 = DragEvent+DataTransfer; pointer = pointer/mouse events (sortable libraries).
element_screenshotreadScreenshot cropped to one element or to a viewport region (PNG), optionally enlarged. Read-only.
emulate_mediadestructiveMake the page believe it runs elsewhere, until reset or reload: prefers-color-scheme, prefers-reduced-motion, print mode,
execute_jswriteRun JavaScript in the page (MAIN world). Requires the extension\
extractreadRead repeated non-tabular structures — product cards, list items, search results — as one record per item:
extract_tablereadRead a real <table> as JSON: thead cells become keys, each row an object. Read-only.
fill_formreadBatch fill form fields with React-compatible events. Handles input, select, checkbox, radio, and textarea.
find_settingreadWhere is a setting in an unknown admin panel: follows the panel\
find_textreadFind 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.
framesreadRecord the page for duration_ms and report how smooth it ran: main-thread frame rate and dropped frames, Long Animation Frames
full_page_screenshotreadFull-page capture by scrolling: stitched segments of ~2 viewports (≤1568px), or one image per viewport with stitch=false.
get_css_stylesreadWhy an element looks the way it does: for each CSS property the winning declaration — selector, stylesheet,
get_framesreadList frames (main + iframes) with frameId, parent, URL — for the frame_id parameter of DOM tools.
get_interactivesreadList actionable elements (buttons, links, inputs, [role], [onclick]) with ready-to-use CSS selector, label, position, flags. Prefer this over dumping HTML to discover selectors.
get_page_inforeadPage metadata: title, url, visibility, doctype, charset, meta tags, scripts, stylesheets, links and forms. visibility=hidden means
get_statusreadBridge status: extension connection, server mode (primary/relay), host, port, server and extension versions, js_evaluation
get_storagereadRead localStorage, sessionStorage or cookies of the current origin (type=all for every one). Read-only.
get_tabsreadList every open tab with id, url, title, active flag and mine (created by this session). Read-only. Find a tab_id when the implicit
handle_dialogsreadAuto-accept/dismiss future JS dialogs (alert/confirm/prompt), logging them. reset restores native dialogs and returns the log.
handoffreadHand 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
heap_snapshotreadTake a JS heap snapshot of the tab (after a garbage collection) and summarize it: object count, total size, detached DOM nodes, the
hoverreadHover over an element, by CSS selector or ref. Default: synthetic mouseenter/mouseover/mousemove, which fire JS hover handlers
http_authdestructiveSet/clear credentials for HTTP Basic/Digest auth dialogs (browser-wide, in-memory only).
http_requestreadHTTP request sent from the browser, with the logged-in user\
inject_cssreadInject a CSS rule into the page. Stays until the next navigation or reload, and re-injecting the same id
lighthousewriteRun a full Lighthouse audit (performance included, unlike chrome-devtools-mcp, plus accessibility, best practices, SEO) and return
manage_downloadswriteList downloads, start one, or wait for the newest to finish. Files land in the browser Downloads folder, not on the server.
measure_spacingreadMeasure the gap, overlap and distance in CSS pixels between two elements, with their margins and paddings.
modify_domwriteChange an element in the live DOM: setAttribute, removeAttribute, addClass, removeClass, setStyle,
monitor_networkreadMonitor 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.
move_tabwriteMove an existing tab into another window (chrome.tabs.move), keeping id, history and page state; works on chrome-untrusted://
navigatereadNavigate a Chrome tab to a URL. Returns a preview of interactive elements with refs usable in click/type_text/hover.
network_rulesreadNetwork 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).
perf_tracereadRecord a DevTools performance trace and return its conclusions, never the trace: LCP with its phases (TTFB, resource load delay and
press_keywriteSend a key to the focused element (or to selector, focusing it first) as a real keydown/keypress/keyup
query_domreadQuery DOM elements by CSS selector, returning structure, attributes, bounding rect, and computed styles.
read_consolereadRead console messages captured since page load, incl. uncaught errors and unhandled rejections.
read_formreadRead a form as the user filled it — label, type, value, checked/selected, required-but-empty, browser validity — to check it against the
read_pagereadRead the page as text (default), markdown, raw HTML, or accessibility tree. Read-only. markdown keeps headings, links and
save_pagewriteSave the full page (DOM, styles, images) as an MHTML archive file on the server filesystem.
screencastreadRecord the tab as a video (.mp4 or .webm) to watch an animation or interaction frame by frame; returns the file path and size, never
screenshotreadScreenshot of the visible viewport only (PNG), at the current scroll position, or one per viewport preset with presets. Read-only.
screenshot_diffread
scrollreadScroll. action=to: once to element/coordinates; action=until: repeatedly until element visible, network idle, or no new content (infinite scroll).
session_fixturereadSnapshot localStorage, sessionStorage and cookies of the current origin into a named fixture (a logged-in state, usually),
session_recordreadRecord the commands of this session as a replayable jsonl (chrome-bridge replay --file <path>); observe what the user does in a tab (
set_geolocationdestructiveOverride navigator.geolocation with fixed coordinates (page-level patch). reset restores native.
set_storagedestructiveWrite, delete or clear a localStorage/sessionStorage key, or a cookie with its path, domain and expiry.
tab_actionreadTab lifecycle: close, activate, reload, back, forward, discard, mute, duplicate, close_session (only tabs this session created).
tile_windowsreadTile Chrome windows over one monitor in equal parts with no gap. Only Chrome windows. The monitor is the one of a
track_eventsreadDecode the tracking beacons the page fired (GA4, Meta Pixel, Google Ads, TikTok, LinkedIn, Pinterest, Microsoft Ads, GTM, Hotjar, Clarity)
type_textwritePut text into an input, textarea or contenteditable, by selector or ref. Replaces the whole value through the
upload_filewriteSet 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,
viewport_resizereadResize the Chrome **window** to a preset (mobile 375x812, tablet 768x1024, desktop 1440x900) or explicit dimensions;
wait_forreadBlock until a condition holds: element, text, function (JS expression; needs the
watchreadKeep watching a page in the background —
watch_domreadWatch DOM mutations (MutationObserver). First call installs the watcher; later calls read accumulated mutations.
window_layoutdestructiveSave the current window arrangement under a name, restore, list or delete. save overwrites silently. Window ids do not survive
04

Trust audit

BLOCKgrade D · trust 61/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (5 observation(s))
Network
declared (7 observation(s))
Shell
declared (2 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
extension/service-worker.js:642
fn = new Function(`return (${userCode});`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
extension/service-worker.js:644
try { fn = new Function(userCode); } catch (e) {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
server/tools.js:59
const SECRET_FILES = /(^|[\\/])(\.env(\..*)?|\.netrc|\.npmrc|\.pypirc|\.git-credentials|id_(rsa|dsa|ecdsa|ed25519)(_sk)?|[^\\/]*\.(pem|key|p12|pfx|jks|keystore|kdbx))$/i;
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
server/tools.js:2252
'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, '
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
server/tools.js:2253
+ '~/.gnupg, .env*, *.pem, *.key, id_*...) are refused, and a --read-root on the server limits the readable tree: the call fails '
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
server/tools.js:2257
path: z.string().describe('Absolute path on the server machine; keys and credentials (~/.ssh, .env, *.pem) refused'),
Why it matters. touches a credential store
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
bench/latency.mjs:49
return { server, base: `http://127.0.0.1:${server.address().port}` };
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
server/heap.js:45
const list = await (await fetch(`http://127.0.0.1:${port}/json/list`)).json();
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
drag_and_drop, emulate_media, http_auth, set_geolocation, set_storage, window_layout
Why it matters. 6 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
test/unit/window-bounds-report.test.js:14
return new Function('chrome', `${body}; return windowBoundsReport;`)(chrome);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
server/tools.js:1027
const hash = createHash('sha1').update(data.image).digest('hex');
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
test/unit/observe.test.js:239
const entry = buildEntry({ name: 'upload_file', args: { path: 'x' }, message: 'Refusing to read ~/.ssh/id_ed25519', env: process.env });
Why it matters. touches a credential store
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
test/unit/assertions.test.js:3
import { runAssert, matchPattern } from '../../server/assertions.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
test/unit/audit.test.js:11
import { runAudit, summarizeAudit, auditReport, DEFAULT_KINDS } from '../../server/audit.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
test/unit/audit.test.js:12
import { registerTools } from '../../server/tools.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
test/unit/audit.test.js:13
import { MessageType } from '../../server/protocol.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
test/unit/capture-pacing.test.js:10
import { createPacer } from '../../extension/lib/capture-pacing.js';
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
test/unit/tools-tracking-consent-redirects.test.js:52
test('trackingLines senza beacon spiega il probabile motivo', () => {
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
CHANGELOG.md:412
http://127.0.0.1:.../ (tab N shows the browser's error page)`. The same goes
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/superpowers/plans/2026-06-12-chrome-bridge-overhaul.md:507
base = `http://127.0.0.1:${server.address().port}`;
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/superpowers/plans/2026-06-12-chrome-bridge-overhaul.md:527
const results = await checkLinksBatch([{ url: 'http://127.0.0.1:1/x', text: 'dead' }], 1000);
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
extension/service-worker.js:3669
u.parts[i] = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
extension/service-worker.js:3694
const bytes = id ? new Blob(pieces.parts) : Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@jridgewell/trace-mapping, @modelcontextprotocol/sdk, node-html-parser, ws
Why it matters. 4 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
docs/CAPABILITIES.md:57
| A second MCP session on the same browser | **Measured** (daily use) | The second server becomes a relay through the first; the two still share tabs and refs, so two agents on the same tab step on ea
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine

Gates applied: no_behavioural_pass.

Audited 2026-10-11 · audit v0.4.1 · source sha 3661aac0f719full audit observations/trust-audit/mcp-server/frsorrentino__chrome-bridge.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-113661aac0f719BLOCKD61first audit
06

Questions

What is the chrome-bridge MCP server?

Chrome Bridge by frsorrentino — your real, logged-in Chrome as an MCP server for Claude Code: 60 measured, token-efficient tools. ChromeOS included.

What tools does chrome-bridge expose?

66 in total: 48 read-only, 12 that write, and 6 that can delete or overwrite (drag_and_drop, emulate_media, http_auth, set_geolocation, set_storage). Every one is listed on this page with its risk.

Is chrome-bridge safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (61/100) and found 6 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 6 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does chrome-bridge need?

It reads CHROME_BRIDGE_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does chrome-bridge run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as chrome-bridge-mcp at 1.29.2.

How current is this page?

The grade is for one exact copy of the source (3661aac0f719), read on 2026-10-11. The repository is watched and re-audited when it changes.

Advertisement