Browser Controller MCP server
Commit 14. Nov. 2026Ermöglicht es AI Agents, deine bestehenden Chrome-Browser-Sessions inklusive Logins und Cookies über einen MCP server und eine Extension zu steuern.
Auch bekannt als compnew2006/browser-controller
- Stars
- 9
- Tools
- 25
- Downloads, 30 Tage
- —
- Neueste Version
- —
- Letzter Commit
- 14. Nov. 2026
- Lizenz
- MIT
Was ist Browser Controller MCP?
Browser Controller ist ein MCP server. Ermöglicht es AI Agents, deine bestehenden Chrome-Browser-Sessions inklusive Logins und Cookies über einen MCP server und eine Extension zu steuern. Er stellt 25 Tools bereit, etwa url, tabId, snapshot.
Zusammenfassung generiert aus dem README des Projekts
Über Browser Controller MCP server
Browser Controller ermöglicht es AI Agents, mit deinen aktiven Chrome, Edge oder Brave Browser-Sessions zu interagieren. Im Gegensatz zu Headless-Automatisierung nutzt dieses Tool deine bestehenden Profile. Das bedeutet, dass Agents auf deine echten Logins, Cookies und authentifizierten Sessions zugreifen können, ohne dass eine erneute Authentifizierung erforderlich ist. Es funktioniert über einen lokalen Daemon und eine Chrome Extension, wodurch sichergestellt wird, dass alle Daten via localhost auf deinem Rechner bleiben, ohne Cloud-Telemetrie.
Entwickler können dies mit MCP-kompatiblen Clients wie Cursor, Claude Desktop oder Windsurf nutzen. Das System unterstützt mehrere Agents gleichzeitig durch die Verwendung spezifischer Tab-IDs, sodass ein Agent in einem Tab arbeiten kann, während du in einem anderen weiter surfst. Es bietet hochpräzise Interaktionen über das Chrome DevTools Protocol, wodurch sichergestellt wird, dass Klicks und Tastatureingaben als vertrauenswürdige User-Events erkannt werden. Der Server enthält 19 Tools für Navigation, Element-Interaktion und JavaScript-Evaluation sowie Funktionen zum Überwachen von Console Logs und Network Requests.
Was du damit machen kannst
- 1Automatisierte Software-VerifizierungEin AI Agent kann einen Code-Fix verifizieren, indem er zu deiner lokalen Anwendung navigiert und mit dem UI interagiert.
- 2Parallele Multi-Agent-WorkflowsFühre verschiedene AI Agents gleichzeitig in separaten Browser-Tabs aus, ohne dass sie sich gegenseitig stören.
- 3Debugging und Network InspectionFordere den Agent auf, Console-Errors zu analysieren oder den Network Traffic abzufangen, um Webanwendungen zu troubleshooten.
Geschrieben aus dem README des Projekts. Jeder Use Case wurde gegen ein Zitat daraus geprüft.
Browser Controller MCP tools 25
Erkannt aus dem READMEurltabIdsnapshotactionbrowserisolationaccesstrustedreadtargetquerymaxChars
| url | — | |
| tabId | — | |
| snapshot | — | |
| action | — | |
| browser | — | |
| isolation | — | |
| access | — | |
| trusted | — | |
| read | — | |
| target | — | |
| query | — | |
| maxChars | — |
Alle 25 Tools anzeigenWeniger Tools anzeigen
propertiesruleslistenersenableddefaultActionsiteRulesbuttonexpectobservehoverselectuntilactions
| properties | — | |
| rules | — | |
| listeners | — | |
| enabled | — | |
| defaultAction | — | |
| siteRules | — | |
| button | — | |
| expect | — | |
| observe | — | |
| hover | — | |
| select | — | |
| until | — | |
| actions | — |
Konfiguration
WS_PORT
| Name | Beschreibung | Typ |
|---|---|---|
| WS_PORT | — |
Automatisierte Checks
Geluften am 14. Nov. 2026Vollständiger Bericht →Noch nicht verifiziert. Ein Server benötigt einen Score von 80, keine kritischen Befunde und genug Daten für unsere Prüfung. Wie die Checks funktionieren · Was du für mehr Punkte verbessern kannst
- Source Repository verknüpft und erreichbarcompnew2006/browser-controller is public and reachablegithub.com/compnew2006/browser-controller ↗Bestanden
- Paket nennt dieses Repository als QuelleNicht geprüft
- Build-Provenienz (Sigstore-Attestierung)Nicht geprüft
- Open Source Lizenz (OSI)MITspdx.org/licenses/MIT.html ↗Bestanden
- Commit oder Release im letzten JahrLast commit or release 2026-11-09github.com/compnew2006/browser-controller ↗Bestanden
- OpenSSF ScorecardOpenSSF Scorecard 6.9 / 10; weakest: Code-Review 0, Token-Permissions 0, CII-Best-Practices 0scorecard.dev/viewer/?uri=github.com/compnew2006/browser-con ↗Teilweise 10/15
- Package-Name ähnelt keinem populären PackageNicht geprüft
- Keine kritischen Advisories im Paket oder seinen AbhängigkeitenNicht geprüft
- Keine versteckten Anweisungen an das Modell25 tool descriptions and the README read; no override phrases, credential paths or hidden charactersBestanden
- Destruktive Tools sind markiertNo tool named like delete, drop or execBestanden
- Remote-Endpoint beantwortet den MCP-HandshakeNicht geprüft
README
Auf GitHub ansehenWhat this project solves
You ship a fix. Your agent says "done, please verify." You alt-tab to Chrome, navigate to the page, log in, click around, find the bug.
Your agent just wrote the code. It could also verify it. It already has your browser open right there. It just can't see it.
Now it can. Browser Controller gives any MCP-compatible AI agent (Cursor, Claude Desktop, Windsurf, …) direct control of the browser you already have open — your real sessions, your logins, your cookies. No headless browser, no fresh profile, no re-authentication.
Version 3.0 is a breaking release: 19 tools, one target locator, and text results with structured receipts for actions. See Migrating from 2.x.
Key capabilities
- Multiple agents at once. Cursor can drive tab 10 while Claude drives tab 11 — both through one shared daemon, neither blocking the other.
- Tab targeting, not "the active tab." Every page action names a
tabId. Move your mouse, switch tabs, watch YouTube — the agent keeps working on the tab you told it to. It never hijacks the page you're reading. - Tab ownership without lock calls. A tab that
browser_navigateopens for a session belongs to that session until it closes. Another session's call on that tab fails at once withTAB_LOCKED. - Per-tab isolation. Element refs are per page, and logs and network buffers are per tab. A ref from tab 10 can never click something in tab 20.
- Per-tab concurrency. Two actions on the same tab serialize (no races); actions on different tabs run in parallel.
- Agent-control shield. While a tool runs on a tab, you see a translucent blue inner frame and your input on that tab is blocked (mouse, keyboard, wheel). It disappears when the action finishes.
- Visible agent cursor (optional). Switch on Show agent cursor in the popup's Settings and agent mouse actions draw a pointer that glides to its target first. Off by default.
- Real, trusted input. Clicks, typing, keys, wheel and drags go through the Chrome DevTools Protocol, so the page sees
isTrustedevents and focus, Tab, Enter and autocomplete behave as they do for a person. There is no synthetic-event fallback: if the debugger cannot attach, input fails withDEBUGGER_UNAVAILABLE. The yellow "being debugged" banner shows while the debugger is attached. - One locator.
targettakes a ref (e12),text=Sign in, viewport coordinates (x,y), a CSS selector, or an accessible{ role, name, nth? }object. Shadow roots and same-origin iframes are searched; cross-origin iframes are listed as not readable. - Honest results. A success is compact text. A failure is an
isErrorresult whose text isCODE: message, so the agent acts on the code instead of guessing. - Batches.
browser_batchruns up to 50 tool calls in one round trip and stops at the first failing step (onError:"continue"runs the rest and names every failure). - The page is read after it settled. An action waits for the page to stop changing before the call returns, and a navigation waits for the page it loaded to draw, so the read that follows sees what the action produced, not the page before it.
browser_wait {until:"stable"}waits for the same thing on demand. - A session can be fenced in.
browser_tabs {action:"session"}opens the session for reading only (every call that changes something is refused), or isolates it (the agent touches the tabs it opened, and only those). - Console-style JavaScript.
browser_evaluateaccepts code as you'd type it in DevTools: top-levelawait, several statements withreturn, DOM nodes come back as readable descriptions. Over CDP, page CSP does not block it. - Console, network and mocks on demand.
browser_logsreads a tab's console (uncaught errors with stacks) and its network requests, with response bodies on request.browser_mockanswers or blocks one tab's requests, so the page really receives the fake response. - Frozen tabs don't freeze the agent.
browser_navigatereplaces a tab that stopped answering, and its result says so with anote:line naming the newtabId. - Several browsers. Every connected Chrome profile is its own connection.
browser_tabs { action: "profiles" }lists stable IDs, local labels, the default, and whether each profile has open tabs without switching the session. Use the ID to select a profile;automeans the earliest-connected default. Set a recognizable local label in the extension's Settings. - Authenticated local connection. Token + enrollment secret, so no other local process can silently drive your browser — and after a one-time
npm run setup:pairingthe extension pairs itself. Everything stays on localhost — no cloud, no telemetry. - Versioned compatibility handshake. The daemon and extension advertise a protocol version and capabilities before tool traffic is accepted. A peer from before 3.0 is refused with an actionable error instead of producing unexplained timeouts.
- Consoles and appliances. A hypervisor web client is an ordinary page to the agent, and the guest behind it is reachable through the same tools — the guest is a canvas, so it needs its own rules for reading, clicking and typing. The field guide is
docs/esxi-vm-console-automation.md.
How it works
Three pieces, all on your machine. Nothing leaves localhost. The daemon control plane is hard-bound to 127.0.0.1; there is no supported remote/n8n listener.
flowchart LR
subgraph Client["MCP client (Cursor / Claude / Windsurf)"]
A["agent"]
end
subgraph Thin["thin MCP client — mcp-server/dist/index.js"]
B["DaemonClient<br/>speaks MCP over stdio<br/>spawns daemon if not running<br/>gets its own sessionId"]
end
subgraph Daemon["daemon — single long-running process, owns port 7225"]
C["daemon.ts<br/>multiplexes N clients → 1 extension<br/>sessions · rate limit · heartbeats"]
D["bridge.ts (ExtensionBridge)<br/>HTTP /pair /status /kill<br/>WebSocket for the extension"]
end
subgraph Ext["Chrome extension (Manifest V3 service worker)"]
E["connection.js<br/>pairing · reconnect backoff"]
F["router.js<br/>tool dispatch"]
G["tab-concurrency.js<br/>per-tab mutex · ownership · shield"]
H["handlers/*<br/>interaction · inspection · evaluate · navigation · tabs<br/>logs · mock · emulate · cdp"]
I["page-exec.js safeExec<br/>chrome.scripting func: — CSP-safe"]
E --> F --> G --> H --> I
end
P["Page — your real sessions"]
A -->|stdio MCP| B
B -->|IPC socket + token| C
C --> D
D <-->|Authenticated WebSocket<br/>protocol version + capabilities| E
I --> P
Key idea: the first time any agent runs, the thin client spawns a background daemon that owns port 7225 and the extension connection. Every subsequent agent (even from a different MCP client) connects to that same daemon over a local IPC socket and gets its own sessionId. The extension sees one stable connection and routes each call to the exact tab the caller specified.
Quick Start
The project is not on the Chrome Web Store or npm — you install it from this repository. Two parts: the MCP server (runs on your machine, talks to your AI agent) and the Chrome extension (sits in your browser, executes commands).
Prerequisites: Node.js 22.18+ within the 22.x line, 24.11+ within the 24.x line, or 26+; and Chrome/Chromium/Edge. CI tests the minimum and latest releases of the 22, 24, and 26 lines. Later Node.js major versions are allowed by engines but are not covered by the current CI matrix.
1. Clone & build
git clone https://github.com/compnew2006/browser-controller.git
cd browser-controller
npm install
npm run build # compiles TypeScript → mcp-server/dist/
2. Load the Chrome extension
- Open
chrome://extensionsand enable Developer mode (toggle in the top right) - Click Load unpacked and select the
extension/folder from the cloned repo - Pin the Browser Controller icon to your toolbar
Gray dot = waiting for the daemon. Green = connected.
3. Add the MCP server to your client
Cursor: Settings → MCP → "Add new MCP server". Claude Desktop: edit claude_desktop_config.json. Windsurf: Settings → MCP. Any MCP-compatible client works.
Replace /path/to/browser-controller with the absolute path of your clone (Windows: use C:\\path\\to\\browser-controller\\mcp-server\\dist\\index.js):
{
"mcpServers": {
"browser-controller": {
"command": "node",
"args": ["/path/to/browser-controller/mcp-server/dist/index.js"]
}
}
}
By default the daemon names each connection after its parent IDE ("Cursor", "Claude", …). To override — e.g. when several agents share one IDE, or to label them by project — pass --agent <name> in the args. It takes priority over every auto-detection:
{
"mcpServers": {
"browser-controller": {
"command": "node",
"args": [
"/path/to/browser-controller/mcp-server/dist/index.js",
"--agent",
"My Project Agent"
]
}
}
}
The name appears in the popup's Connected Agents list. (You can also set the MCP_AGENT_NAME env var — equivalent.) Reconnecting with the same name replaces the old entry, so IDE restarts don't pile up duplicates.
4. Pair the extension with the daemon
Run this once from the repo root:
npm run setup:pairing
Then click Reload on Browser Controller in chrome://extensions. The extension pairs itself — nothing to copy or paste. Green dot = you're connected. Your agent can now see your browser.
What the command sets up:
- A small local helper (a Chrome native messaging host,
mcp-server/dist/native-host.js), registered with every Chromium browser it finds: Chrome (stable, Beta, Canary), Chromium, Edge and Brave. It is a per-user install (on Windows, underHKCU\Software\…\NativeMessagingHosts) and needs no admin rights. - Chrome lets only this extension's ID start the helper. An unpacked extension's ID comes from its folder path; the command prints the ID it computed, and it must match the one shown in
chrome://extensions. If you loaded the extension from another folder, pass its ID:npm run setup:pairing -- --extension-id <id>. - A launcher in
.native-host/that pins the currentnode, because a browser started from the Dock or Start menu does not see your shell'sPATH.
The extension asks the helper only when the daemon refuses its secret — the first time, and after you rotate the secrets — so a rotation needs no action either. Check the setup with npm run pairing:status (it never prints the secret) and remove it with npm run pairing:uninstall. Run npm run setup:pairing again after moving the repository or switching Node installations, since the launcher pins both paths. When pairing cannot happen, the popup's activity log says why and what to run.
Only the enrollment secret is needed — the extension fetches the auth token from the daemon by itself.
- Start the daemon once by asking your agent to "list my browser tabs". It creates the secrets in
~/.browser-controller/(Windows:%USERPROFILE%\.browser-controller\), and the MCP client prints the enrollment secret to its log on first run. - Copy the
secretvalue:cat ~/.browser-controller/enrollment.json - Click the extension icon → Settings tab → paste it into Enrollment Secret (leave the port at
7225unless you changedWS_PORT).
These secrets protect the local control channel. To rotate them without deleting vault and memory data, use
npm run pairing:rotateand then restart the daemon as described in SECURITY.md. Processes running as the same OS user can read the secrets; pairing is not a same-user sandbox.
Runtime lifecycle (authoritative daemon)
The daemon is the only process that owns the extension-facing runtime. MCP
clients are thin stdio adapters and may start it automatically, but deployment
scripts should use the lifecycle commands below so there is one restart owner.
Do not run a second daemon.js or install a launch supervisor that competes for
port 7225.
npm run build
npm run daemon:start # start, or report the already-running PID
npm run daemon:status # JSON health/runtime information
npm run daemon:health # authenticated daemon + extension check; exit 1 if unhealthy
npm run daemon:stop # graceful SIGTERM; removes runtime metadata
npm run daemon:restart # stop, then start; preserves token/enrollment
The daemon survives browser/Chrome restarts: token, enrollment secret, and
pairing remain in ~/.browser-controller/ (override with BC_STATE_DIR), and
the extension reconnects to the same endpoint. The lifecycle wrapper reads the
daemon.json PID and is safe to run repeatedly; a stale lock is removed only
when its recorded PID is not alive.
For service monitoring, backup boundaries and recovery drills, see the operations and recovery runbook.
MCP clients reconnect after every drop of their daemon connection (a restart,
a crash). Each try connects to the daemon that answers, or waits for one that
is starting (its daemon.lock names a live PID), or, when none is alive,
starts one (never with BROWSER_CONTROLLER_DAEMON_MODE=connect). Tries back
off from 0.25 s to 5 s; after 8 failed tries the client waits for its next tool
call to try again. A tool call made while the client reconnects waits up to
10 s for it. A call that was running when the connection dropped fails
NOT_CONNECTED: daemon connection closed and is not repeated: it may have run.
A client starts a daemon at most 3 times a minute, so a daemon that cannot stay
up is not restarted in a loop; calls then fail NOT_CONNECTED: Not connected to daemon: … with the reason and the path of daemon.log.
When several clients start a daemon at the same moment, the first one takes
daemon.lock. Each other one writes one line, … lock is held by live process <pid>; this daemon exits and clients use that one, and exits with code 0; its
client connects to the first. A daemon.log larger than 5 MB is moved to
daemon.log.1 before the next daemon starts (one old copy is kept).
Expected endpoints
- MCP endpoint: stdio, launched as
node mcp-server/dist/index.js(the standardmcpServerscommand/args form is shown above). - Extension runtime:
ws://127.0.0.1:7225by default, with HTTP/pair,/status, and/kill?sessionId=...on the same port. These are daemon/popup endpoints, not an MCP HTTP transport. - MCP client IPC:
~/.browser-controller/daemon.sockon Unix or\\.\pipe\browser-controlleron Windows. It is internal and token-authenticated. - State:
~/.browser-controller/{daemon.json,daemon.lock,token.json, enrollment.json,daemon.log}.WS_PORT,WS_HOST, andBC_STATE_DIRare the supported configuration overrides.
This preserves the real Chrome session workflow: no Playwright/headless browser is launched, and the existing Chrome profile, cookies, logins, and tabs remain the browser being controlled.
Permission and trust boundary
The unpacked extension deliberately requests Chrome's powerful debugger, scripting, webRequest, and <all_urls> permissions, plus nativeMessaging, which it uses only to ask the local pairing helper for the enrollment secret, and webNavigation, which it uses only to know which tab opened a new one. Together they let a connected MCP agent read network metadata, run functions in the pages you select, drive trusted input and evaluate JavaScript through the debugger, and answer requests in a tab with mock responses. A connected MCP agent can therefore read and change sensitive pages in your signed-in browser. Install the extension only from source you trust, pair it only with a trusted local daemon, and do not expose the daemon port beyond localhost. Chrome-protected pages such as chrome://, the Web Store, and DevTools remain inaccessible.
Using it
The model is tab-first: the agent always says which tab to act on. It never assumes "the active tab."
Basic workflow
- List tabs to get a
tabId:browser_tabs { action: "list" } → 123 [user, focused] "Inbox" mail.example.com/inbox 456 [own] "Sign in" login.example.com - Snapshot that tab to see its structure and get element refs. Use
queryon large pages:browser_snapshot { tabId: 456, query: "Sign in" } → textbox "Email" [e5] button "Sign in" [e3] - Act with the same
tabIdand atarget:browser_type { tabId: 456, target: "e5", text: "hello@example.com" } browser_type { tabId: 456, key: "Tab" } browser_click { tabId: 456, target: "text=Sign in" } - Wait for what you expect, then verify:
browser_wait { tabId: 456, target: "text=Welcome" } browser_text { tabId: 456 }
A ref (e5) is valid for the tab and page that produced it. If its element was re-rendered, the call finds the element again by its snapshot description and adds a note: e5 was re-found after the page changed line. The note appears in the results of click (also hover and drag), type with a target, fill, snapshot, text, scroll and wait with a target, and inspect_element. Screenshot finds the element again without the note. A ref from an earlier page of the tab (after a navigation or reload) fails REF_GONE ("from an earlier page"). A ref that was never issued in the tab fails at once with REF_NOT_FOUND. If the element cannot be found again, the call fails REF_GONE: take a new browser_snapshot.
Browser Controller MCP Fragen
Welche Tools bietet Browser Controller MCP?
Er stellt 25 Tools bereit, darunter url, tabId, snapshot, action, browser.
Wird ein Headless-Browser verwendet?
Nein, es gibt Agents die direkte Kontrolle über den Browser, den du bereits offen hast, und nutzt deine echten Sessions, Logins und Cookies.
Können mehrere AI Agents gleichzeitig den Browser nutzen?
Ja, mehrere Agents können über einen einzigen geteilten Daemon gleichzeitig verschiedene Tabs steuern, ohne sich gegenseitig zu blockieren.
Werden meine Daten in die Cloud gesendet?
Nein, alles bleibt auf deinem lokalen Rechner und kommuniziert via localhost.