{"slug": "show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp", "title": "Show HN: Drive your real logged-in Chrome from Claude Code and Codex (MCP)", "summary": "Browser Bridge, a local MCP server and Manifest V3 Chrome extension, lets AI coding agents Claude Code and OpenAI Codex CLI control a user's real logged-in Chrome browser, inheriting cookies, SSO, and 2FA state without re-login. The tool ships 63 tools including DevTools-grade network capture, a web-security testing toolkit, playbooks, and session recording with export to high-resolution MP4.", "body_md": "*Drive your real, logged-in Chrome from an AI agent - over the Model Context Protocol.*\n\nNo headless browser. No fresh profile. No re-login. Your agent reads and acts inside the exact sessions you're already signed into.\n\nBrowser Bridge is a local **MCP server + Manifest V3 Chrome extension** that lets AI coding agents - **Claude Code** and **OpenAI Codex CLI** - control the Chrome you use every day. Because it runs *inside* your real profile, the agent inherits your cookies, `HttpOnly`\n\nsessions, SSO, and 2FA state automatically. Ask it to *\"read my feed and summarize it\"* or *\"capture the API traffic on this page and show me the responses\"* - and it works against the live, authenticated app.\n\nIt ships **63 tools** spanning everyday browsing, DevTools-grade network capture, a full web-security testing toolkit, **playbooks** (saved, self-healing recipes), and **session recording** - record an interaction into a self-contained, offline-faithful HTML replay (full-page, custom-designed player, with a smooth mouse-trail / click / keystroke overlay) and **export it to a high-resolution MP4**.\n\n[\n](/vitalysim/browser-bridge/blob/main/docs/replay.gif)\n\n*Record a session → a self-contained, offline replay with a smooth mouse-trail / click / keystroke overlay → export to a high-res MP4.*\n\n[Quick start](#quick-start)[Why Browser Bridge?](#why-browser-bridge)[See it in action](#see-it-in-action)[Architecture](#architecture)[Features & tools](#features--tools)[Playbooks](#playbooks)[Recording](#recording)[Setup](#setup)[Security & responsible use](#security--responsible-use)[Limitations](#limitations)[Roadmap](#roadmap)[Contributing](#contributing)[License](#license)\n\nBuild both packages, run the server, load the extension, connect your agent - about 60 seconds:\n\n```\ngit clone https://github.com/vitalysim/browser-bridge.git && cd browser-bridge\n( cd server    && npm install && npm run build )   # MCP server (TypeScript → dist/)\n( cd extension && npm install && npm run build )   # bundles background.js + options.js\n( cd server    && npm run install-service )        # run the server at login (systemd/launchd)\n```\n\n-\n**Load the extension**- open`chrome://extensions`\n\n, enable**Developer mode**, click** Load unpacked**, select the`extension/`\n\nfolder, then open its options and paste the token from`~/.browser-bridge/token`\n\n→**Save & connect**. -\n**Connect your agent:****Claude Code**\n\n```\nclaude mcp add --transport http --scope user browser-bridge \\\n  http://127.0.0.1:8765/mcp --header \"Authorization: Bearer $(cat ~/.browser-bridge/token)\"\n```\n\n**OpenAI Codex CLI**- export the token so Codex can read it, then register the server in one command:\n\n```\nexport BROWSER_BRIDGE_TOKEN=\"$(cat \"$HOME/.browser-bridge/token\")\"   # add to your shell profile\ncodex mcp add browser-bridge --url http://127.0.0.1:8765/mcp --bearer-token-env-var BROWSER_BRIDGE_TOKEN\n```\n\n**Verify:** `curl -s http://127.0.0.1:8765/health`\n\n→ `{\"ok\":true,\"extensionConnected\":true}`\n\n. Full details, autostart options, and the manual config alternatives are in [Setup](#setup).\n\n| Browser Bridge | Headless Playwright / Puppeteer | A raw CDP debug port | |\n|---|---|---|---|\nUses your real logged-in profile |\n✅ | ❌ (fresh profile, re-login) | |\nWorks from Claude Code and Codex |\n✅ | - | - |\nNo open debug port on your session |\n✅ (outbound WS) | n/a | ❌ any local process can hijack it |\nDevTools-grade capture (bodies, WS) |\n✅ | partial | ✅ |\nOne-command install, no native host |\n✅ | ✅ | ✅ |\n\n**One server, two clients.** Both agents connect to the same token-authed endpoint`http://127.0.0.1:8765/mcp`\n\n. Anthropic's*Claude in Chrome*is Claude-only and OpenAI's Codex browser extension is desktop-app-only - neither gives the Codex**CLI** a real browser. Browser Bridge does.**Extension, not a debug port.** Chrome 136+ blocks`--remote-debugging-port`\n\non your default profile. A Manifest V3 extension runs*inside*that profile instead - banner-free by default, with`chrome.debugger`\n\n(CDP) power features attached only on demand.**Outbound WebSocket, no native-messaging host.** The extension dials`ws://127.0.0.1:8765/ws`\n\n; there are no host-manifest files to install, and the WS keepalive keeps the MV3 service worker alive.**Localhost-only + token auth.** The server binds`127.0.0.1`\n\n, checks a bearer token on both the MCP endpoint and the WS handshake, and rejects any WS origin that isn't`chrome-extension://`\n\n.\n\nWith Chrome open and logged in, just ask your agent in natural language:\n\n```\n# Everyday\nlist my open tabs\nopen github.com, read my notifications, and summarize them\n\n# Screenshots\ntake a full-page retina screenshot of this page and save it to ~/Downloads/page.png\n\n# Network capture\nstart a network capture on this tab, reload it, and show me the JSON API responses\n\n# Record & export\nrecord my session, I'll click around and type, then stop - build the HTML replay and a 2x MP4\n\n# Web-security (authorized targets only)\ncapture identity \"A\" for app.example.com, then log in as B and capture \"B\";\nreplay the invoices request as A, B and anon and show me the authz_matrix\n\n# Remote desktop / canvas (e.g. a CTF AttackBox)\nscreenshot the DCV desktop, click the terminal, type \"id\" and press Enter, then screenshot the output\n```\n\nBoth Claude Code and Codex drive the same live browser through the same endpoint.\n\n**Browse & interact**- tabs, navigation, and click / fill / hover / type / scroll with** auto-wait actionability**(found + visible + enabled, auto-escalating to a trusted CDP click when a target is overlay-covered), plus file and image upload - all reaching**into iframes (incl. cross-origin) and open shadow DOM**- and** coordinate-level trusted input**(`input`\n\n) for`<canvas>`\n\nremote desktops (VNC/RDP/Amazon DCV), games, and drawing apps.**Read & inspect**- rendered page text, interactive-element snapshots with stable refs, screenshots (viewport → full-page retina, element clip, save-to-disk), and JavaScript evaluation that**bypasses strict CSP** via CDP.**DevTools-grade capture**- full request/response** bodies**, response headers,`Set-Cookie`\n\n, timings, and**WebSocket/SSE frames**- with durable on-disk persistence and** HAR / MHTML**evidence export.** Web-security toolkit**- named** identities**, an in-session request** replayer**,** BOLA/IDOR/BFLA**access-control diffing (`authz_matrix`\n\n),**Burp-style live interception**, an** intruder-style fuzzer**(sniper/pitchfork/clusterbomb/race), passive header/CORS/** secret**analysis,** JWT**decode, and** copy-as-curl**.** Session & storage**- read/write the** real cookie jar**(incl.`HttpOnly`\n\n),`localStorage`\n\n/`sessionStorage`\n\n, and console + CSP + exception logs.\n\n**Browsing & interaction**\n\n| Tool | Description |\n|---|---|\n`tabs_list` · `tab_new` · `tab_activate` · `tab_close` |\nManage tabs. `tabs_list(short:true)` returns id/title/origin/active only (no path/query), for quickly identifying tabs without echoing full URLs |\n`navigate` · `go_back` · `go_forward` · `wait_for` |\nNavigation |\n`click` · `fill` · `hover` · `type` · `press_key` · `scroll` |\nInteraction (iframe + open-shadow aware). Auto-waits for the element to be actionable (found + visible + enabled, `timeoutMs` ) and returns structured `{notActionable, reason}` on failure. `click` detects overlay-covered targets and auto-escalates to a trusted CDP click (`via:\"trusted\"` ); `fill` /`type` register in React inputs (native setter) and rich editors (execCommand). `trusted:true` for real CDP input; `withSnapshot:true` to get a fresh `snapshot` back inline |\n`input` |\nCoordinate-level trusted input via CDP for targets element selectors can't reach - a `<canvas>` remote desktop (VNC/RDP/Amazon DCV), a game, a WebGL app. Actions: `mouse_move` , `left/right/middle_click` , `double_click` , `left_mouse_down/up` , `left_click_drag` , `scroll` , `type` (to the focused element), `key` (combos like `ctrl+c` ). Coords are CSS viewport pixels (`= screenshotPixel / dpr` , and `screenshot` now returns `dpr` ). `activate:true` to foreground the tab so you can observe |\n`file_upload` |\nSet a file input via base64 or a local `path` (`DOM.setFileInputFiles` ) |\n`paste_image` |\nPaste a local image into a rich-text / contenteditable field; `trusted:true` uses the real OS clipboard + a genuine Cmd/Ctrl+V for strict editors (e.g. YesWeHack) that ignore synthetic events |\n\n**Read & inspect**\n\n| Tool | Description |\n|---|---|\n`get_page_text` |\nRendered text of the page (and its iframes). `includeHidden:true` reads `textContent` instead of `innerText` , capturing `display:none` /collapsed content (e.g. un-expanded accordion bodies) that the default drops |\n`snapshot` |\nInteractive elements with refs (+ `enabled` /`inViewport` hints); `deep:true` pierces closed shadow roots. Refs are held in an off-DOM registry, so a snapshot no longer mutates the page (a ref whose element was since re-rendered is reported so the caller re-snapshots). Deep-snapshot refs are numbered in their own range per snapshot generation, so they can never be confused with a plain-snapshot ref or a stale one from an earlier deep snapshot |\n`screenshot` |\nVisible viewport (banner-free) by default; `fullPage` for the whole page, `scale` for retina, `format` /`quality` , `selector` to clip, `savePath` to write a file. Returns `dpr` + CSS viewport size (to map screenshot pixels → `input` coords) and `visibilityState` - warns when the tab is occluded (its frame may be throttled/stale) |\n`download_resource` |\nDownload a URL to disk via Chrome's own download engine - up to 100MB by default (`maxBytes` to raise it), correct binary handling, real session cookies, banner-free; `savePath` to relocate it from the Downloads folder |\n`eval_js` |\nEvaluate JavaScript in the page's main world (banner-free). Auto-falls back to where in-page `cdp_eval` on strict-CSP pages`eval` is blocked (`via:\"cdp-fallback\"` ); `cdp:true` forces it, `noFallback:true` disables it. `timeoutMs` to wait past the 30s default |\n`cdp_eval` |\nEvaluate JS in the page's real main-world context via CDP `Runtime.evaluate` - not subject to CSP , so it runs on strict-CSP sites, and reaches the page's live JS (in-memory state, framework internals, closures, the app's own functions). Uses `unsafe-eval` `chrome.debugger` (shows the banner). `timeoutMs` raises the 30s cap for a long await/poll |\n`bridge_status` |\nIs the extension connected? |\n\n**Network capture** (chrome.debugger - shows the debugging banner)\n\n| Tool | Description |\n|---|---|\n`net_capture_start` |\nBegin capturing; then navigate/reload to record load traffic. `maxEntries` sizes the in-memory ring (default 500, max 5000); `persist:true` + `savePath` also streams each finished request/WS frame to a JSON-Lines file on disk (durable - survives the ring cap and, up to the last batch, a service-worker crash; `persistBodies:true` includes bodies) |\n`net_get_requests` |\nRequests with headers, `Set-Cookie` , timings, and (opt-in) response bodies |\n`net_get_body` |\nFetch one response body on demand |\n`net_get_ws_frames` |\nCaptured WebSocket / EventSource frames |\n`export_har` |\nWrite the tab's captured traffic to a HAR 1.2 file (import into Burp / DevTools / Playwright); bodies included by default |\n`debugger_detach` · `debugger_status` |\nEnd a session (banner off) / inspect sessions |\n\n**Web-security testing**\n\n| Tool | Description |\n|---|---|\n`identity_capture` · `identity_list` · `identity_purge` |\nSnapshot/manage named sessions (cookies incl. `HttpOnly` , storage, bearer) |\n`replay_request` |\nIn-session Repeater - replay a captured or ad-hoc request; override any header or swap identity (`anon` strips auth). `viaAppClient:true` replays through the page's own so app CSRF/auth interceptors apply`fetch` |\n`authz_matrix` |\nReplay a request set across identities and diff → flags access-control breaks (BOLA / IDOR / BFLA) |\n`response_diff` |\nStructural diff of two responses (status, length, token-Jaccard, noise-suppressed) |\n`intercept_start` · `intercept_pending` · `intercept_resolve` · `intercept_stop` |\nBurp-Proxy-style live interception (CDP Fetch): pause matching requests/responses, then continue (optionally mutating url/method/headers/body), fail (block), or fulfill/modify (synthesize a response). `rules` auto-apply; otherwise requests queue for resolution |\n`fuzz` |\nIntruder-style fuzzer over a request template - modes sniper / pitchfork / clusterbomb (multi-marker `payloadSets` ) / race (fire N together for race conditions). Per-request `status` /`length` /`timeMs` with anomalies flagged first |\n`analyze` |\nOne-call passive recon: grades response security headers (CSP/HSTS/CORS/X-Frame/nosniff/leaks), cookie flags, and sweeps the body for exposed secrets/API-keys/JWTs → findings ranked by severity. `deep:true` also fetches same-origin external `<script src>` bundles and sweeps those |\n`jwt_decode` |\nDecode a JWT (header/payload, no verify); flags `alg:none` , HS/RS confusion, expiry |\n`request_to_curl` |\nEmit a ready-to-run curl command reproducing a captured request (real sent headers incl. `Cookie` , plus body) or an ad-hoc one - for handoff to a terminal / Burp workflow |\n\n**Session, storage & evidence**\n\n| Tool | Description |\n|---|---|\n`cookies_get` · `cookies_set` · `cookies_delete` |\nRead/write the real browser cookie jar via `chrome.cookies` - includes `HttpOnly` , with full flags (`secure` , `sameSite` , `expirationDate` ) |\n`storage_dump` · `storage_set` · `storage_remove` · `storage_clear` |\nRead/write this origin's `localStorage` / `sessionStorage` |\n`console_start` · `console_get` · `console_stop` |\nBuffer console output, uncaught exceptions, and CSP/log violations (via CDP; CSP-independent). Filter `console_get` by regex `pattern` / `level` |\n`save_page` |\nSave the tab as a single self-contained `.mhtml` evidence snapshot |\n\n**Playbooks** (saved, self-healing task recipes)\n\n| Tool | Description |\n|---|---|\n`playbook_record_start` · `playbook_record_stop` |\nRecord mode: stream every tool call to a JSON-Lines draft, then stop - a seed you distill into a durable playbook |\n`playbook_save` |\nWrite a playbook's Markdown to disk server-side (global home or project-local), regardless of the client's write scope |\n\n**Session recording** (record → self-contained HTML replay → high-res MP4)\n\n| Tool | Description |\n|---|---|\n`session_record_start` |\nStart recording the tab as a session replay (rrweb) - DOM + mutations + input/scroll/mouse (~60 fps), banner-free. `allFrames:true` also records cross-origin iframes (best-effort, per-frame with a timeout); `maskInputs:true` redacts form values (default off) |\n`session_record_stop` |\nStop and assemble a self-contained, offline-faithful HTML replay: inlines every external asset (cross-origin CSS/fonts/images/lazy-images) through the extension, strips other extensions' nodes, and renders full-page (fits the viewer at the recorded viewport's exact aspect). A custom FRACTURE-styled player (play/scrub, speed, skip-idle, fullscreen) with a live interaction overlay - smooth mouse trail, click ripples, keystroke HUD - toggleable on. Opens offline in any browser. Options: `inlineAssets` , `assetBudgetMB` , `perAssetMB` , `skipInactive` , `autoplay` |\n`session_record_status` |\nList active recordings (tab, events file, events so far) |\n`render_recording_video` |\nRender a saved replay `.html` into a high-resolution MP4 (`fps` , `scale` up to 4× ≈ retina/4K, `crf` ). Deterministic + frame-exact: seeks the player per frame, captures lossless PNGs, then ffmpeg → H.264. Video = the recorded page + the interaction overlay, matching the live playback |\n\n**Screenshot recipes**\n\n`screenshot`\n\ndefaults to a banner-free capture of the visible viewport. Options (these use `chrome.debugger`\n\n, so they show the debugging banner):\n\n| Want | Call |\n|---|---|\n| Entire scrollable page | `screenshot(fullPage: true)` |\n| Retina / high-DPI (dimensions = CSS × scale) | `screenshot(fullPage: true, scale: 2)` |\n| Smaller file | `screenshot(format: \"jpeg\", quality: 85)` |\n| Just one element | `screenshot(selector: \"#invoice\")` |\n| Write to disk (best for large full pages) | `screenshot(fullPage: true, savePath: \"/abs/path.png\")` |\n\n`savePath`\n\nreturns `{ path, bytes, width, height }`\n\ninstead of a multi-MB inline image. Capture maxes out at Chrome's ~16384px surface size, and an oversized PNG auto-falls back to JPEG.\n\nRepetitive tasks - \"delete this kind of post\", \"run a BOLA check on an endpoint\" - cost expensive first-time understanding (snapshot, find selectors, trial and error). A **playbook** saves that resolved knowledge to a local Markdown file so the next run is cheap.\n\nA playbook is a **self-healing document, not a macro**: it records *intent + robust role/accessible-name locators + checkpoints + the hard-won \"understanding\"* - never raw clicks, coordinates, snapshot refs, or captured requestIds (those are ephemeral and break next run). The agent runs it **with judgment** - re-perceiving each step, verifying the target before acting, and re-deriving a step that has drifted - which is the whole advantage over a brittle record-replay macro. Destructive/irreversible steps require confirmation.\n\nPlaybooks live at `~/.browser-bridge/playbooks/<slug>.md`\n\n(global) or `./playbooks/<slug>.md`\n\n(project-local, git-shareable); every connected agent learns the convention automatically via the MCP `instructions`\n\nfield. Capture one with **record mode**: `playbook_record_start`\n\n→ do the task once → `playbook_record_stop`\n\n→ distill the draft → `playbook_save`\n\n.\n\n**Format, execution protocol, heal/safety rules, and two worked examples (a DOM delete + a BOLA/IDOR flow): docs/PLAYBOOKS.md.**\n\nRecord a live interaction and replay it. `session_record_start`\n\ncaptures the DOM + mutations + input/scroll/mouse over time (rrweb), **banner-free**; interact with the page; `session_record_stop`\n\nassembles a **single self-contained HTML file** that plays the whole thing back with a **play button, timeline scrubber, and speed control** - offline, in any browser.\n\nBecause the extension injects the recorder into **every frame including cross-origin iframes** (which page-level rrweb can't) and is **CSP-immune**, it records sites and embedded frames a normal recorder can't even load on. Events stream to `~/.browser-bridge/recordings/*.events.jsonl`\n\nduring capture (surviving long sessions), then get inlined with the rrweb-player into the HTML on stop.\n\nThe replay is **truly self-contained / offline-faithful**: on stop, the server fetches every external asset the capture references — cross-origin stylesheets, fonts, images, and lazy-loaded images — **through the extension** (background `fetch`\n\nunder `<all_urls>`\n\nhas no CORS wall + sends your session cookies) and inlines them, and strips nodes injected by your *other* extensions. So it renders from captured data, not by re-fetching the live site (page-level rrweb can't read cross-origin CSS at all).\n\nThe player is a custom **FRACTURE**-styled UI: the replay **fills the window at the recorded page's exact aspect ratio** (rescaling on resize), with a play/scrub timeline, speed, skip-idle, and fullscreen. A toggleable **interaction overlay** annotates the playback with a **smooth mouse trail**, **click ripples**, and a **keystroke HUD** (typed text, plus physical keys like `Enter`\n\n/ `⌘C`\n\non new recordings). Then ** render_recording_video** turns a saved\n\n`.html`\n\ninto a **high-resolution MP4**(\n\n`fps`\n\n, `scale`\n\nup to 4× ≈ retina/4K) - a deterministic, frame-exact render (seek + lossless PNG per frame → ffmpeg H.264) whose motion matches the live playback. Note: input **masking is OFF by default**(cleartext values;\n\n`maskInputs:true`\n\nto redact); canvas/WebGL and live video **pixels** aren't captured by DOM replay.\n\n**Details:**\n\n[docs/RECORDING.md](/vitalysim/browser-bridge/blob/main/docs/RECORDING.md).**Node.js 18+** and**Chrome, Chromium, or Edge**- on** Linux, macOS, or Windows**(Chromium-based; not Brave/Arc, not WSL)** Claude Code ≥ 2.0.73**and/or** OpenAI Codex CLI**\n\n```\ngit clone https://github.com/vitalysim/browser-bridge.git\ncd browser-bridge\n( cd server    && npm install && npm run build )   # MCP server\n( cd extension && npm install && npm run build )   # bundles background.js + options.js\n```\n\nThe server generates a random bearer token on first run and stores it at `~/.browser-bridge/token`\n\n(also printed on startup). Pick one:\n\n**Autostart (recommended)** - one command installs a background service for your OS (**systemd** user service on Linux, **launchd** LaunchAgent on macOS):\n\n```\ncd server && npm run install-service     # runs at login, restarts on crash\n# Linux: to start at boot without an active login:  loginctl enable-linger \"$USER\"\n# remove later with:  npm run uninstall-service\n```\n\n**Manual** - just run it in a terminal:\n\n```\ncd server && npm start        # or: nohup node dist/index.js >~/.browser-bridge/server.log 2>&1 &\n```\n\nVerify: `curl -s http://127.0.0.1:8765/health`\n\n→ `{\"ok\":true,\"extensionConnected\":false}`\n\n(becomes `true`\n\nonce the extension is loaded). Logs: Linux `journalctl --user -u browser-bridge -f`\n\n; macOS/manual `tail -f ~/.browser-bridge/server.log`\n\n.\n\n- Open\n`chrome://extensions`\n\n, enable**Developer mode**. **Load unpacked**→ select the`extension/`\n\nfolder.- Open the extension's popup/options → paste the token from\n`~/.browser-bridge/token`\n\n→**Save & connect**. The status turns green.\n\nVerify: `curl -s http://127.0.0.1:8765/health`\n\n→ `{\"ok\":true,\"extensionConnected\":true}`\n\n.\n\nReloading the extension after an update may prompt for new permissions (e.g.\n\n`webNavigation`\n\n,`debugger`\n\n,`downloads`\n\n) - re-enable it if Chrome disables it.\n\n**Claude Code**\n\n```\nclaude mcp add --transport http --scope user browser-bridge \\\n  http://127.0.0.1:8765/mcp --header \"Authorization: Bearer $(cat ~/.browser-bridge/token)\"\n```\n\n**Codex CLI** - export the token, then register with one command:\n\n```\nexport BROWSER_BRIDGE_TOKEN=\"$(cat \"$HOME/.browser-bridge/token\")\"   # add to your shell profile\ncodex mcp add browser-bridge --url http://127.0.0.1:8765/mcp --bearer-token-env-var BROWSER_BRIDGE_TOKEN\n```\n\nOr edit `~/.codex/config.toml`\n\ndirectly:\n\n```\n[mcp_servers.browser-bridge]\nurl = \"http://127.0.0.1:8765/mcp\"\nbearer_token_env_var = \"BROWSER_BRIDGE_TOKEN\"\n```\n\nCodex reads the token\n\nby env-var name, so`BROWSER_BRIDGE_TOKEN`\n\nmust be exported in the shell that launches`codex`\n\n(hence adding it to your profile). Verify with`codex mcp list`\n\n.\n\n| OS | Server | Extension | Autostart |\n|---|---|---|---|\nLinux |\n✅ | ✅ | systemd user service (`npm run install-service` ) |\nmacOS |\n✅ | ✅ | launchd LaunchAgent (`npm run install-service` ) |\nWindows |\n✅ | ✅ | manual (`npm start` ); register with your service manager |\n\n**The agent acts with your real cookies.** Treat every tool call as running as*you*.**Prompt injection is the ambient risk.** Pages the agent reads are untrusted input; a malicious page can try to steer it. Keep write-capable tools behind your MCP client's permission prompts and don't point it at pages you don't trust.**Debugger mode is powerful.** While attached it can read full request/response bodies (including auth headers) and dispatch trusted input. It shows Chrome's*\"started debugging this browser\"*banner, auto-detaches after ~5 min idle (unless actively capturing), and can be ended immediately with`debugger_detach`\n\n.**The security-testing tools are raw offensive primitives with no built-in scope guard - by design.** Like Burp Suite Repeater/Intruder/Autorize, staying within an authorized engagement's scope is the**operator's responsibility**. Only point Browser Bridge at systems you are authorized to test.** No secrets in the repo.**The bearer token lives in`~/.browser-bridge/`\n\n(gitignored); binding is localhost-only. See[SECURITY.md](/vitalysim/browser-bridge/blob/main/SECURITY.md)to report a vulnerability.\n\n- Interaction auto-waits for actionability and, on\n`click`\n\n, auto-escalates to a trusted CDP click when the target is overlay-covered (`via:\"trusted\"`\n\n, shows the banner); force it anytime with`trusted:true`\n\n. A covered/hidden/disabled target returns a structured`{notActionable, reason}`\n\n. - A strict page\n**CSP**(`script-src`\n\nwithout`'unsafe-eval'`\n\n) blocks the banner-free`eval_js`\n\n; it auto-falls back to`cdp_eval`\n\n(CDP`Runtime.evaluate`\n\n, banner shown), which CSP cannot block. The isolated-world read/interact tools and all CDP/background tools are unaffected by CSP either way. `chrome.debugger`\n\nrequires sole access to a tab - it**can't attach if DevTools is open** on that tab.`net_capture_start`\n\nonly records traffic sent*after*it's called (navigate/reload to capture a page load).- The capture buffer is in-memory (a ring of\n`maxEntries`\n\nrequests/tab, default 500, ~512 KB/body). An active capture is not torn down by the idle sweep; for a durable record beyond the ring cap use`net_capture_start(persist:true, savePath:…)`\n\n, which streams to disk. Persistence is**durability, not continuity**- if the service worker dies the debugger detaches and capture stops until restarted; the file holds what was captured before that. - One extension connection at a time (last connect wins); multiple MCP clients can share it concurrently. A call in flight when the extension disconnects fails fast instead of waiting out the timeout.\n`input`\n\ncoordinates are**CSS viewport pixels**, but screenshots are** device pixels**- map with the`dpr`\n\nthe screenshot returns (`coord = screenshotPixel / dpr`\n\n).`input`\n\nis delivered even to a backgrounded tab, but a hidden tab's frame is throttled, so you can't*observe*the result until it's foregrounded (`activate:true`\n\n/`tab_activate`\n\n);`screenshot`\n\nflags this via`visibilityState`\n\n.`download_resource`\n\nalways uses the browser's live session - it can't download as a captured`identity`\n\n.`Cookie`\n\n/`Host`\n\n/`Origin`\n\n/`Referer`\n\n/`Content-Length`\n\nin its`headers`\n\nparam are browser-forbidden and silently ignored. If Chrome's \"Ask where to save each file\" setting is enabled, downloads may prompt for a location instead of completing automatically.\n\n**Shipped** (newest first):\n\n**v0.14 · MP4 export**-`render_recording_video`\n\nrenders a saved replay to a high-resolution, frame-exact**H.264 MP4**(deterministic seek + lossless-PNG frames → ffmpeg); the mouse-trail / click / keystroke motion matches the live playback.`chrome:true`\n\nincludes the player UI.**v0.13 · Designed replay player**- a custom** FRACTURE**-styled player with** full-page fit-to-viewport**rendering and a toggleable** interaction overlay**: smooth mouse trail, click ripples, and a keystroke HUD (typed text + physical keys).** v0.12 · Correctness & reliability**- an audit-driven pass (56-agent review): a silent capture-loss guard on socket replacement, MV3 memory-leak caps, cross-session recording, and robust`allFrames`\n\ninjection.**v0.11 · Offline-faithful replay**-`session_record_stop`\n\ninlines every external asset (cross-origin CSS / fonts / images, fetched*through the extension*- no CORS wall) and strips foreign-extension nodes, so the HTML is truly self-contained.**v0.10 · Session recording**- record a live interaction and replay it as a self-contained HTML timeline (rrweb;`session_record_start`\n\n/`stop`\n\n/`status`\n\n), banner-free, capturing cross-origin iframes. →[docs/RECORDING.md](/vitalysim/browser-bridge/blob/main/docs/RECORDING.md)**v0.9 · Playbooks**- saved, self-healing task recipes (Markdown at`~/.browser-bridge/playbooks/`\n\n; record-mode capture via`playbook_record_start`\n\n/`stop`\n\n/`playbook_save`\n\n). →[docs/PLAYBOOKS.md](/vitalysim/browser-bridge/blob/main/docs/PLAYBOOKS.md)**v0.8 · Remote-desktop pentest feedback**- coordinate-level trusted input (`input`\n\n) for canvas / VNC / RDP / DCV,`get_page_text(includeHidden)`\n\n,`cdp_eval`\n\n/`eval_js`\n\n`timeoutMs`\n\n, and`screenshot`\n\n`dpr`\n\n/`visibilityState`\n\n.**v0.7 · Durable capture & handoff**-`net_capture_start(persist)`\n\n+`maxEntries`\n\n, copy-as-curl (`request_to_curl`\n\n),`analyze deep`\n\n, plus reliability fixes.**v0.6 · Self-healing interaction, recon & evidence**- passive recon (`analyze`\n\n) +`jwt_decode`\n\n, HAR export, fuzz modes +`viaAppClient`\n\nreplay.**v0.5 · Security-toolkit foundation**- interception, fuzzing, cookie / storage, console / CSP capture, and MHTML.\n\n**Exploring next:**\n\n- A\n**realtime-screencast video mode**- to also capture time-based*page*animation (CSS keyframes / GIF /`<video>`\n\n) that deterministic seek can't pin. - Source-map\n**de-minification** on downloads. **GraphQL** introspection helpers.- A client-side\n**DOM-XSS / postMessage / prototype-pollution** suite.\n\n```\nserver/                 MCP server (TypeScript · @modelcontextprotocol/sdk · ws · express)\n  src/index.ts            HTTP MCP endpoint + auth + session management\n  src/hub.ts              single extension socket, request/response correlation, capture sinks\n  src/capture-sink.ts     durable on-disk JSON-Lines sink for persist captures\n  src/tools.ts            the 63 MCP tools\nextension/              Manifest V3 extension (bundled with esbuild via build.mjs)\n  manifest.json\n  src/background.ts       service worker: WS client, injection, chrome.debugger (CDP) layer\n  src/options.ts          token + connection UI\n  icons/                  generated app icons\nscripts/                install-service.mjs / uninstall-service.mjs (systemd or launchd)\ndocs/                   PLAYBOOKS.md · RECORDING.md · banner.svg · architecture.svg\n  server/vendor/          rrweb-player (inlined into session-replay HTML)\n  extension/vendor/       rrweb-record.js (injected recorder; built by build.mjs)\n```\n\nContributions are welcome - see ** CONTRIBUTING.md** for the build and dev loop (including the MV3 service-worker reload gotcha) and how to add a tool. Found a security issue in the bridge itself? Please report it privately per\n\n**.**\n\n[SECURITY.md](/vitalysim/browser-bridge/blob/main/SECURITY.md)**MIT** - see [LICENSE](/vitalysim/browser-bridge/blob/main/LICENSE). Bundled third-party components (rrweb, rrweb-player - both MIT) are credited in [THIRD-PARTY-NOTICES.md](/vitalysim/browser-bridge/blob/main/THIRD-PARTY-NOTICES.md).\n\nBrowser Bridge is provided for **authorized** automation, research, and security testing only. You are responsible for complying with the terms of service of the sites you automate and with the scope of any security engagement. The authors accept no liability for misuse.", "url": "https://wpnews.pro/news/show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp", "canonical_source": "https://github.com/vitalysim/browser-bridge", "published_at": "2026-07-24 16:18:05+00:00", "updated_at": "2026-07-24 16:22:35.654138+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents"], "entities": ["Browser Bridge", "Claude Code", "OpenAI Codex CLI", "Chrome", "Manifest V3", "Model Context Protocol"], "alternates": {"html": "https://wpnews.pro/news/show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp", "markdown": "https://wpnews.pro/news/show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp.md", "text": "https://wpnews.pro/news/show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp.txt", "jsonld": "https://wpnews.pro/news/show-hn-drive-your-real-logged-in-chrome-from-claude-code-and-codex-mcp.jsonld"}}