ByobBLOCK
Bring Your Own Browser — let your AI agent use the Chrome you already have open
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
Bring Your Own Browser — let your AI assistant use the Chrome you already have open.
[](LICENSE) [](https://modelcontextprotocol.io) [](https://developer.chrome.com/docs/extensions/mv3/intro/) [](CHANGELOG.md)
English · 中文
byob is a local MCP server that lets AI coding tools (Claude Code, Cursor, Cline, Windsurf, etc.) directly control your real Chrome — the one where you're already logged into everything.
"read my Twitter timeline and summarize the top 5 posts" "google 'mcp protocol spec', click the first result, read the page" "take a screenshot of example.com" "grab my GitHub session cookie so I can curl with it" "open my Gmail tab and tell me how many unread" "fill in this form with my details and submit it"
Compared with tools that attach over Chrome's remote-debugging port (DevTools MCP, agent-browser, Playwright --cdp): byob is an extension, so there's no debugging port to open, no "Allow remote debugging?" prompt on every connection, and nothing else on your machine can hijack your logged-in browser through it.
Install
Quick install (recommended)
curl -fsSL https://raw.githubusercontent.com/wxtsky/byob/main/install.sh | bash
On Windows, run the same command from Git Bash or MSYS2. The script checks prerequisites (Node.js ≥ 20, bun, Chrome/Edge/Brave), clones the repo, builds eve
a291a871b308OBSERVED · 2026-10-07Connect
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.
claude mcp add shared -- npx -y @byob/[email protected]
{
"mcpServers": {
"shared": {
"command": "npx",
"args": [
"-y",
"@byob/[email protected]"
]
}
}
}Exposed tools (25)
15 read · 6 write · 4 destructive. Blast radius: 4 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
browser_batch | write | Several steps in one call, e.g. fill + submit: [{tool: |
browser_click | read | Click by ref (from snapshot/find), CSS selector, or viewport x+y. Real mouse events. ${ACT} |
browser_clipboard | write | Read or write plain text on the system clipboard (explicit calls only). |
browser_console | read | Console output, uncaught errors and browser warnings of a tab, buffered since byob first touched it. |
browser_dialog | read | Get or answer (accept/dismiss + promptText) a JS dialog. Never auto-accepted; actions report when one opens. |
browser_download_images | write | Save the images of a page (or url) to disk, skipping icons smaller than minWidth×minHeight. |
browser_drag | destructive | Drag from one ref/selector/x+y to another. Supports HTML5 drag-and-drop as well as mouse-driven sliders and sortable lists. |
browser_emulate | read | Device/viewport, color scheme, reduced motion, geolocation, timezone, locale, offline, extra headers; reset:true clears all. |
browser_evaluate | read | Evaluate an expression (or a function body with return) in the page. With ref/selector the element is available as |
browser_find | read | Locate elements semantically and get refs: role(+name), text, label, placeholder, alt, title or testId (substring, case-insensitive unless exact). With action (click/fill/check/...) acts on match #nth right away — no snapshot needed. |
browser_hover | write | Move the mouse over a ref / selector / x+y (menus, tooltips). snapshot:true shows what appeared. |
browser_inspect | read | element: box, visibility, state, value, attributes, match count, computed styles. performance: Web Vitals + timing. |
browser_navigate | read | Open a URL (a new background tab, then reused — never the user |
browser_network | write | record → act → stop (summary, or json/har file). intercept: block / mock / modify requests; unintercept to stop. |
browser_press_key | read | Press a key or combo on the focused element (or on a ref/selector, focused first): Enter, Escape, Tab, ArrowDown, Backspace, |
browser_read | read | Page content: text (all visible), markdown (main article, else whole page), html, links or tables. outline:true = headings only; filter = sections mentioning a phrase; scope with ref/selector. For finding things to click use snapshot. |
browser_screenshot | read | Viewport (default), fullPage, element (ref/selector) or clip; returns the image and saves it. annotate:true labels the snapshot refs on it. format: |
browser_scroll | read | direction up/down/left/right (optional amount px) or to top/bottom — for the page, or inside the scroll container given by ref/selector. A target without direction scrolls it into view. Reports the scroll position so you know when the end is reached. |
browser_select | destructive | Select option(s) of a native <select> by value or visible label. For custom dropdowns click the control, then the option. |
browser_snapshot | read | The page as an outline of roles and names (iframes included) — the main way to see a page. Interactive elements get refs like [ref=e12] for click/type/etc., valid until the page navigates. interactive:true = controls only; diff:true = only changes since the last snapshot; scope with ref/selector. |
browser_storage | destructive | get / set / clear cookies (default: the tab URL) or local/sessionStorage — e.g. export a login cookie for curl. |
browser_tabs | read | Tabs of the user |
browser_type | destructive | Fill an input / textarea / contenteditable (replaces content; clear:false appends). No target = the focused element. slowly:true for autocompletes, submit:true presses Enter. ${ACT} |
browser_upload_file | write | Set absolute local file paths on an <input type=file> (hidden inputs work: target them with selector |
browser_wait | read | Wait (AND of all given): element state, text appears/gone, URL match, load/networkidle, JS predicate fn (BYOB_ALLOW_EVAL=1), ms delay. Actions already auto-wait — use this for things that happen later. |
Trust audit
BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (3 observation(s))
- Network
- declared (7 observation(s))
- Shell
- declared (4 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (25)
atob( ... new Function(
endpoint: `http://127.0.0.1:${port}/upload`,browser_drag, browser_select, browser_storage, browser_type
expect(() => new Function(`return (${src});`)).not.toThrow();expect(() => new Function(`return ${READABILITY_INSTALL};`)).not.toThrow();const hasSensitiveValue = new Function(
const repoRoot = path.resolve(here, '../../..');
endpoint: `http://127.0.0.1:${port}/upload`,readabilityEndpoint: `http://127.0.0.1:${port}/readability`,2. extension 把 outerHTML POST 到 bridge 的 `http://127.0.0.1:<port>/readability`(沿用 `download_images` 走过的 loopback HTTP)
primary: `http://127.0.0.1:${a.port}`,const bin = atob(b64);
const buf = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
@modelcontextprotocol/sdk
commander, @types/node, tsx, typescript
zod, @types/chrome, typescript, wxt
@modelcontextprotocol/sdk, undici, zod, @types/node, tsx, typescript
zod, typescript
`/get-console-logs` and `/extract-table` are simple `routeFor(...)` passthroughs. `/read-markdown` has to spin up the upload-server (for `/readability`) and pass `readabilityEndpoint + secret` into th
3. POST `{ html, sourceUrl, options }` to `readabilityEndpoint?secret=...` (bridge passes the endpoint + secret in params).`browser_screenshot` 这种动辄 MB 级的 PNG 不走 Native Messaging。bridge 临时开 `127.0.0.1:<random>` HTTP server,把 endpoint + secret 通过 Native Messaging 告诉扩展,扩展直接 `fetch(endpoint, { method:'POST', body: pngBytes }// We can't read process.env in extension; gate via chrome.storage.local for parity.
curl -fsSL https://raw.githubusercontent.com/wxtsky/byob/main/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/wxtsky/byob/main/install.sh | bash
Gates applied: critical_finding, no_behavioural_pass.
a291a871b308full audit observations/trust-audit/mcp-server/wxtsky__byob.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-07 | a291a871b308 | BLOCK | D | 69 | first audit |
Questions
What is the Byob MCP server?
Bring Your Own Browser — let your AI agent use the Chrome you already have open
What tools does Byob expose?
25 in total: 15 read-only, 6 that write, and 4 that can delete or overwrite (browser_drag, browser_select, browser_storage, browser_type). Every one is listed on this page with its risk.
Is Byob safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (69/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 4 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Byob need?
No credential environment variables were found in its source, so it appears to need none.
How does Byob run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as @byob/shared at 0.5.0.
How current is this page?
The grade is for one exact copy of the source (a291a871b308), read on 2026-10-07. The repository is watched and re-audited when it changes.