BrowserAttach
Control and automate existing Chrome/Edge tabs and profiles through a locally paired extension and stdio MCP server.
Discover browser profiles/tabs, claim tabs exclusively, and release, activate, or close them.
Open/navigate tabs, go back/forward, and fetch HTTP(S) pages in background tabs using existing sign-in.
Read accessibility snapshots, page/frame text, controls, fields, editor text, and console/network/navigation logs.
Interact with pages via click, hover, drag, type, fill, select option, press key, scroll, and ordered batch steps.
Evaluate JavaScript, wait for conditions, handle JS dialogs, upload files, and capture viewport/full-page/element screenshots.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@BrowserAttach click the Approve button on my open pull request tab and confirm the dialog"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BrowserAttach
Drive the Chrome / Edge tabs you already have open and already signed in from an MCP client. BrowserAttach connects to the browser through a locally paired extension, keeps your existing sign-in state, and needs neither a remote debugging port nor a separate automation browser.
npm · Usage guide · Architecture · Agent integration · Test report · Issues · Contributing
What it does
Discover multiple browser profiles, pick one precisely, claim a tab exclusively, and release it when done.
Control existing ordinary
file://tabs after enabling BrowserAttach's Allow access to file URLs setting in the browser's extension details; use the same discovery, claim, observation and input tools.Read the accessibility tree, query names/values/nearby field context, inspect field values and supported editor models; click, fill and type through refs or strict CSS/XPath, HTML label, placeholder and AX role/name locators. Type can also target the currently focused field explicitly.
Native pointer hover, stepped drags and conditional waits; select HTML options without opening a native popup.
Navigate and go back/forward, open or close tabs, handle JavaScript dialogs, upload local files, and capture the whole page or a single element.
Evaluate JavaScript expressions in the main page; read console, page-error, network and navigation logs captured after claiming, with bounded available stacks and request initiators; opt in to bounded, redacted request/response details when XHR/fetch needs verification.
Read one HTTP(S) URL in a temporary background tab with the profile's sign-in, returning rendered text, current DOM, or complete JSON with the main-document HTTP status when observed.
Standard stdio MCP with 24 tools. The Hub listens on loopback only and pairs with the extension through a random key.
Related MCP server: byob
Requirements
Node.js 22 or newer, plus npm.
Chrome / Edge 125 or newer with permission to load unpacked extensions. Latest stable is recommended.
An MCP client that speaks stdio MCP and can find Node/npm on
PATH.
Quick start
1. Install and pair
npm install --global @evan_zhong/browser-attach
browser-attach setupsetup prints a stable extension directory and starts the local Hub. The directory is usually:
Windows:
%USERPROFILE%\.browser-attach\extensionmacOS / Linux:
~/.local/share/browser-attach/extension
Open chrome://extensions or edge://extensions, enable developer mode, choose "Load unpacked" and load that directory. Load it once for every browser profile you want to expose; the extension options page lets you set a recognizable profile name.
Or without a global install:
npx --yes --package=@evan_zhong/browser-attach@latest browser-attach setup2. Configure the MCP client
Merge the following into your client's MCP configuration, or see mcp-config.json:
{
"mcpServers": {
"browser_attach": {
"command": "npx",
"args": ["--yes", "--package=@evan_zhong/browser-attach@latest", "browser-attach", "mcp"]
}
}
}On Windows clients that require a full command extension, use npx.cmd. With a global install you can also configure "command": "browser-attach", "args": ["mcp"]. Restart the MCP client to discover the tools.
@latest selects the package at launch; upgrading an existing pair is coordinated at startup. The first extension load, and pairs still on an older protocol, need one manual extension reload — see local data and upgrades.
Host entry points are collected in agent integration, and the connection parameters, JSON/TOML examples and verification steps are in the setup reference; other clients use the stdio entry above.
The npm package includes an optional browser-attach skill with setup, recovery and cross-site recipes. Copy the whole skills/browser-attach directory to your host's skill location if desired; npm installation does not register it with the host.
3. Start driving
browser_discover(kind="browsers")→browser_discover(kind="tabs")to confirm the browser, tab title and URL.browser_claim_tabwith thetab_idfromdiscover(kind="tabs")(optionalexpected_url/expected_titleexact guards) to take control and receive this connection'stab_handle.browser_snapshotto get elementrefs, then click, fill or run other actions.Observe when the next decision needs new state, and finish with
browser_tab_control(action="release"). Usesnapshot(diff_since="latest")or actionobserve:{diff_since:"latest"}for page changes; inspectmode/reset_reasonand finish pagination. A full-page refresh is not required after every action.
When titles change often, omit expected_title and check the identity returned by claim instead. Elements may be addressed by ref or by a selector re-resolved on every call; design trade-offs: architecture notes.
Claiming and ordinary input never activate a tab or window; call browser_tab_control(action="activate") explicitly when foreground rendering is needed. When an outcome is unknown, observe again first and avoid duplicate submissions. Full parameters, pagination, uploads and input semantics: usage guide.
Tools
Tool | Purpose |
|
|
| Exclusively claim a discovered tab |
| Create a tab, optionally claim it with |
| Read one HTTP(S) URL in a temporary background tab using the profile's sign-in; |
| AX snapshot, literal name/value query with actionable refs, and page text |
| Control state, related popups and active/selected options; preserves existing refs |
| Read-only checks with uniform expected/actual, pass/fail/unavailable and safe read retry; one top-level condition or |
| Native/DOM input, pointer hover and drag, option selection, character typing and scrolling |
| Run 1–30 click/fill/type/press_key/hover/scroll/select_option/wait steps in one queue; stops on the first failure and returns partial results |
| HTTP(S)/file navigation, back/forward and load waiting; local destinations require file access |
| alert, confirm, prompt |
| Native file input or an intercepted file chooser |
| Viewport or full-page PNG with coordinate mapping |
| Main-page JS evaluation, promise awaiting, bounded results |
| Read |
Local data and upgrades
Platform | Default data directory |
Windows |
|
macOS / Linux |
|
Override it explicitly with the absolute path BROWSER_ATTACH_HOME. The Windows default avoids AppData, which packaged hosts may virtualize; no other host's private cache is searched or merged automatically. The directory holds the pairing configuration, Hub logs and the stable extension copy, and depends on neither the clone location, the client working directory nor the npm cache. If you already use a custom directory, keep using the same environment variable or --config instead of accidentally creating a second pairing under the new default.
A host assembly step that writes the client entry pins the absolute paths of the current Node, CLI and the actual pairing file and sets BROWSER_ATTACH_HOME; it works together with a custom --config. When the MCP launches the Hub it passes the same absolute pairing path and directory, so different launch environments cannot derive a second configuration. See agent integration.
To upgrade, install again with the command from step 1 and reconnect the MCP client. With @latest and a pair on 0.17 or newer the restart is enough; a pair still on an older protocol needs browser-attach stop, a restart and one manual extension reload. Custom pairing paths, ports and extension directories are retained, closed browser profiles update when they next connect, and an older MCP package cannot downgrade a newer Hub or installed extension.
An upgrade waits for extension cleanup and confirms the new version after reload; cleanup or reload failures are reported instead of replaying page actions. Manual reload remains available on the extension options page for recovery, and Hub and extension versions must match for page control. The default port is 47831; choose another port with setup --port when creating a pairing.
Architecture and boundaries
MCP client → Node.js stdio MCP → 127.0.0.1 Hub
↕ local pairing
Chrome / Edge MV3 extension
↓ chrome.debugger / CDP
existing HTTP(S) / authorized file:// tabsEach MCP connection holds its own control and handles cannot be used across connections. Disconnecting or stopping debugging releases control. The client endpoint requires a Bearer key and rejects web page Origins; the extension verifies a fixed Origin, key and version. browser_evaluate can read and write data with the page's existing sign-in state; a timeout or error may already have had an effect and must not be replayed automatically. No generic CDP tool is exposed.
Logs are collected from claim time, survive navigation and are cleared on release, with bounded buffers that report data_loss on eviction. Buffered reads use the existing claim without requiring a supported or responsive current page; capture changes still require page access. Network logs store lifecycle metadata and available initiators by default; an explicit capture reads bounded, redacted headers/bodies of subsequent XHR/fetch requests without changing caches or intercepting traffic. Navigation requests and commits remain separate observations. Buffer limits and parameters: usage guide.
The extension holds debugger permission and client actions can use existing site sign-in state; only connect clients you trust. Web page content must not be treated as user authorization. The pairing key and the generated config.generated.js must not be committed or published; the packaging check rejects packages that contain that file.
Chrome / Edge HTTP(S) pages and existing ordinary file:// tabs with extension file access enabled are supported, and file access is checked during discovery, claim, operations and navigation. open_tab and fetch still accept HTTP(S) only. Browser internal pages, arbitrary extension pages, download management, network interception and Firefox / WebKit remain outside scope, and built-in PDF viewer content is browser-dependent. Native pointer input requires an unsuspended tab in a non-minimized window; an unmodified left single click may target an inactive tab, while hover, drag and other click variants require an active tab. Full limits and failure modes: usage guide.
Local development
git clone https://github.com/EvannZhongg/BrowserAttach.git
cd BrowserAttach
npm ci
npm test
npm run test:packageRun the source directly and pair the extension in the repository:
node bin/browser-attach.mjs setup --extension-dir ./extension
node bin/browser-attach.mjs mcpDevelopment mode deliberately uses the repository extension path. For normal installs, use setup without --extension-dir so it keeps working after the repository moves.
Real-browser tests need a Chromium / Edge executable that allows loading extensions from the command line; the path is supplied by the developer:
npm run test:live -- --executable /path/to/chromium --family chromium
npm run test:interaction -- --executable /path/to/chromium --family chromium
npm run test:interaction -- --tab-indicators --executable /path/to/chromium --family chromium
npm run test:upgrade -- --executable /path/to/chromiumThese tests use temporary profiles and local fixtures. Coverage and limits: test report; implementation and design trade-offs: architecture.
Contributing
Reproducible issues via Issues, or Pull Requests. Please include Node, OS, browser and extension versions, and remove pairing keys and private page data. See CONTRIBUTING.md for the process.
Released under the MIT License.
Available Tools
24 toolsbrowser_batchA
Run ordered steps in one tab queue under a shared deadline; per-step timeouts cap remaining time. Prevalidates all steps, including skipped ones. Stops on failure with failed_step/prior results and isError; no rollback or automatic replay.
Inputs: steps (required), tab_handle (required), observe, start_at, +2 more.
browser_claim_tabB
Exclusively claim a tab_id from this connection's latest tab discovery; optional expected_url/title must match exactly.
Inputs: tab_id (required), browser_id (required), expected_url, expected_title.
browser_clickB
Click exactly one ref/selector/x+y; elements auto-scroll and may recenter once before dispatch, with hit checks. Unmodified left single clicks may target inactive tabs. Native target_verified requires an element; coordinates return null and verify trusted delivery to the hit only. Native select requires select_option.
Inputs: tab_handle (required), x, y, nth, +16 more.
browser_discoverB
List connected profiles/capabilities or tabs with URL/title and control status. Tab discovery records this connection's latest observation for claim_tab.
Inputs: kind (required), browser_id.
browser_dragB
Drag between endpoints, each exactly one ref/selector/x+y; destination auto-scrolls while held.
Inputs: source (required), tab_handle (required), destination (required), mode, +6 more.
browser_evaluateB
Evaluate expression once; call a returned function once and await its Promise, without user activation. Use an async IIFE for statements. capture_truncated marks capture loss; required_chars/next_item signal page-budget needs. cursor reads cache without re-execution.
Inputs: tab_handle (required), frame, cursor, frame_id, +5 more.
browser_fetchA
Read a URL's main document using the profile's sign-in in a temporary background tab, then close it. Site scripts run and may affect other tabs. status/ok describe HTTP only (unknown=null); readiness/degradation are separate. body is a string. next_cursor reads immutable cache without revisiting; up to 4 captures per connection/profile.
Inputs: browser_id (required), url, cursor, format, +3 more.
browser_fillA
Replace one ref/selector input/textarea/contenteditable and verify retained text. Known Monaco/CM5 proxy textareas are rejected before focus/writes. verification_basis identifies the expectation; verification_source identifies DOM value, selected text or innerText. Native contenteditable readback temporarily selects/reads plain text, then restores selection. CR/CRLF count as LF; requested spaces may retain NBSP. No editor model write, paste, blur or dropdown commit.
Inputs: text (required), tab_handle (required), nth, ref, +10 more.
browser_handle_dialogC
Accept/dismiss a JS dialog and return its original details and accepted.
Inputs: accept (required), tab_handle (required), prompt_text.
browser_hoverA
Move to exactly one ref/selector/x+y, verify trusted mousemove, and leave the pointer there without clicking.
Inputs: tab_handle (required), x, y, nth, +11 more.
browser_logsA
Read buffered console, network or navigation events since claim, even if the page is blank or unresponsive. Capture changes require a supported page. Continue next_seq as after_seq for the same claim/kind; restart at 0 when changing filters. data_loss reports eviction.
Inputs: kind (required), tab_handle (required), level, limit, +4 more.
browser_open_tabB
Create a new HTTP(S) tab in the selected profile even if the URL is already open. claim=true also acquires a tab_handle without tab discovery; it does not wait for page load. A claim failure leaves the tab open and reports its identity in error.open_tab; never automatically repeat creation.
Inputs: url (required), browser_id (required), claim, active.
browser_press_keyA
Send a native key/chord to current focus and report its trusted keydown target. Optional ref/selector guards focus without focusing it; a mismatch before dispatch sends no key. Supports F1–F12, navigation/editing keys and US ASCII punctuation.
Inputs: key (required), tab_handle (required), nth, ref, +8 more.
browser_read_controlA
Read one explicit control: separate native DOM/AX values, rendered text and state; related popups, active descendant and currently exposed options in AX order. Bounded refs preserve the existing snapshot. No library-specific inference, complete virtual list, application commit or atomic DOM/AX view.
Inputs: tab_handle (required), nth, ref, name, +8 more.
browser_read_textA
Read page/frame text. Visible text excludes input/textarea values; use value for one field or snapshot profile=fields for forms. complete_source is source coverage, not pagination; next_offset continues live text, which may change.
Inputs: tab_handle (required), nth, mode, name, +6 more.
browser_screenshotA
Capture viewport, full_page or one ref/selector element as PNG with image-to-viewport CSS mapping. Element/full_page are exclusive; locator options need selector. Full-page points may need scrolling before input. If background rendering stalls, explicitly activate or use AX/text.
Inputs: tab_handle (required), nth, ref, name, +6 more.
browser_scrollA
Scroll one ref/selector container or viewport x/y (default center). DOM emits no wheel events; wheel sends native wheel input. until returns a fresh ref. Stopped searches report stop_reason, scroll_pending and confirmed progress; a boundary/miss does not prove end of data.
Inputs: tab_handle (required), x, y, nth, +14 more.
browser_select_optionA
Set an option on one ref/selector HTML select, including hidden selects, via synthetic input/change (events_trusted=false). Disabled/inert targets fail. Verifies retained selection only.
Inputs: tab_handle (required), nth, ref, name, +10 more.
browser_snapshotB
Read AX with refs, or profile=fields for DOM/AX field facts, labels, context and native values. Popup/controls/owns facts are browser-observed, not inferred ownership. New observations replace refs and retry one document/context race within 30s; next_cursor continues the captured view.
Inputs: tab_handle (required), text, query, cursor, +6 more.
browser_tab_controlA
Release control and leave the page open, activate the tab, or close it (may discard unsaved state). Release/close invalidate tab_handle.
Inputs: action (required), tab_handle (required), focus_window.
browser_typeA
Type printable characters with trusted keys without clearing. Choose exactly one ref/selector/focused=true; stop on focus loss/detachment. Enter/Tab use press_key; ordinary multiline replacement uses fill.
Inputs: text (required), tab_handle (required), nth, ref, +10 more.
browser_upload_fileA
Set browser-host absolute file paths on one file-input/label ref/selector, or omit target for the pending chooser. [] clears/cancels; multiple files need a multiple input; directories unsupported. assignment_acknowledged confirms the command, not event delivery/upload. count_verified compares retained FileList count (null if unreadable); mismatch is not assignment failure. Observe before uploading again.
Inputs: files (required), tab_handle (required), nth, ref, +8 more.
browser_waitA
Read-only wait for condition. State uses native properties/ARIA; missing state is unavailable, not false. Role absence need not mean DOM removal. Prefer a result/status container for text; compares full text, reports a bounded preview with length/truncation. Timeout reports last state; field values are omitted.
Inputs: condition (required), tab_handle (required), nth, name, +9 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Most tools target a clearly distinct action (click, hover, drag, scroll, press_key, screenshot, upload, dialog), and the tab-lifecycle group (discover, claim_tab, open_tab, tab_control) is well separated. The main ambiguity is in the read/input clusters: browser_type vs browser_fill, and browser_read_text vs browser_snapshot vs browser_read_control overlap in purpose, though descriptions do draw explicit boundaries (fill replaces, type appends; snapshot=AX refs, read_text=visible text, read_control=single control).
All 24 tools use a uniform browser_ prefix with snake_case, which is highly predictable. The pattern is verb-first (browser_click, browser_fill, browser_navigate, browser_read_text) with one structural outlier, browser_tab_control, which reads as noun_verb and slightly breaks the convention.
At 24 tools this sits at the top of the reasonable band, and it is on the heavy side. However, browser automation genuinely spans input primitives, reading modes, tab lifecycle, dialogs, uploads, logs, batch and evaluate, so nearly every tool covers a real capability rather than padding.
Coverage is broad and lifecycle-complete: discover/claim/open/navigate/tab_control for tabs, a full input set, multiple read modes, screenshots, dialogs, uploads, logs and batch orchestration. Gaps are minor — no download handling, cookie/storage or network interception tools, and no dedicated frame-switching tool (frames are only implied in read_text), which agents must work around via evaluate.
Maintenance
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Browz hosted MCP (free public beta): let an AI app drive your own Browz browser profiles from anywhere. Connect https://mcp.gobrowz.com/mcp and sign in with your Browz account (OAuth) or an agent token. Each call is relayed to the Browz app on your computer, which must be online with Remote control on and have a hardware security chip (Mac Secure Enclave or TPM 2.0). 17 tools: profiles, tabs, navigate, snapshot, act, wait, screenshot. Cookies, downloads and stored sign-ins stay on your computer.
Give AI agents a real cloud Chrome: open sessions, navigate, read pages, click, type and screenshot.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables any MCP client to drive the user's real Chrome profile through a Chrome extension bridge, with tools for navigation, accessibility snapshots, ref-based interactions, console/network reading, screenshots, tab management, and restricted script evaluation.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI coding tools to drive your real, already-logged-in Chrome browser through an extension-based local MCP bridge, with no debugging port or headless setup required. It provides tools for navigating pages, reading content, clicking, typing, screenshots, tabs, cookies, network inspection, and more.1 npmISC
- AlicenseNot gradedqualityAmaintenanceEnables AI coding tools to drive the user's real, already-logged-in Chrome through an MCP stdio interface, exposing 25 tools for navigating, clicking, typing, reading pages, taking screenshots, capturing network traffic, and accessing cookies and storage. The bundled Chrome extension talks to a local bridge instead of an open remote-debugging port, so logged-in sessions and bot-detection-proof human browsing work without extra setup.1 npmISC

byobofficial
AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI assistants to drive the user's real, already-logged-in Chrome browser locally, so they can read and summarize pages, click, type, fill and submit forms, navigate tabs, and capture screenshots with full access to existing sessions. It also exposes cookies, storage, console, network capture, and emulation capabilities without opening a remote-debugging port or sending data off the machine.1 npmISC