Browser Controller MCP server
Commit 14 Nov 2026Memungkinkan AI agent untuk mengontrol sesi browser Chrome Anda yang sudah ada, termasuk login dan cookies, melalui MCP server dan extension.
Juga dikenal sebagai compnew2006/browser-controller
- Stars
- 9
- Tools
- 25
- Unduhan, 30 hari
- —
- Versi terbaru
- —
- Commit terakhir
- 14 Nov 2026
- Lisensi
- MIT
Apa itu Browser Controller MCP?
Browser Controller adalah MCP server. Memungkinkan AI agent untuk mengontrol sesi browser Chrome Anda yang sudah ada, termasuk login dan cookies, melalui MCP server dan extension. Server ini menyediakan 25 tool, seperti url, tabId, snapshot.
Ringkasan dibuat dari README proyek
Tentang Browser Controller MCP server
Browser Controller memungkinkan AI agent untuk berinteraksi dengan sesi browser Chrome, Edge, atau Brave Anda yang sedang aktif. Berbeda dengan otomatisasi headless, tool ini menggunakan profil Anda yang sudah ada, yang berarti agent dapat mengakses login, cookies, dan sesi terautentikasi asli Anda tanpa perlu re-autentikasi. Sistem ini bekerja melalui daemon lokal dan extension Chrome, memastikan semua data tetap berada di mesin Anda melalui localhost tanpa adanya telemetry cloud.
Developer dapat menggunakan ini dengan client yang kompatibel dengan MCP seperti Cursor, Claude Desktop, atau Windsurf. Sistem ini mendukung beberapa agent secara bersamaan dengan menggunakan tab ID spesifik, sehingga satu agent dapat bekerja pada satu tab sementara Anda tetap bisa browsing di tab lainnya. Tool ini menyediakan interaksi high-fidelity melalui Chrome DevTools Protocol, memastikan bahwa klik dan pengetikan dikenali sebagai event user yang terpercaya. Server ini menyertakan 19 tools untuk navigasi, interaksi elemen, dan evaluasi JavaScript, serta kemampuan untuk memantau console logs dan network requests.
Apa yang bisa Anda lakukan dengannya
- 1Verifikasi software otomatisAI agent dapat memverifikasi perbaikan kode dengan menavigasi ke aplikasi lokal Anda dan berinteraksi dengan UI.
- 2Workflow paralel multi-agentJalankan berbagai AI agent pada tab browser yang terpisah di waktu yang sama tanpa saling mengganggu satu sama lain.
- 3Debugging dan inspeksi networkMinta agent untuk menganalisis error pada console atau mencegat network traffic untuk melakukan troubleshooting pada aplikasi web.
Ditulis berdasarkan README proyek. Setiap use case diperiksa terhadap kutipan dari README tersebut.
Tool Browser Controller MCP 25
Terdeteksi dari READMEurltabIdsnapshotactionbrowserisolationaccesstrustedreadtargetquerymaxChars
| url | — | |
| tabId | — | |
| snapshot | — | |
| action | — | |
| browser | — | |
| isolation | — | |
| access | — | |
| trusted | — | |
| read | — | |
| target | — | |
| query | — | |
| maxChars | — |
Tampilkan semua 25 toolTampilkan lebih sedikit tool
propertiesruleslistenersenableddefaultActionsiteRulesbuttonexpectobservehoverselectuntilactions
| properties | — | |
| rules | — | |
| listeners | — | |
| enabled | — | |
| defaultAction | — | |
| siteRules | — | |
| button | — | |
| expect | — | |
| observe | — | |
| hover | — | |
| select | — | |
| until | — | |
| actions | — |
Konfigurasi
WS_PORT
| Nama | Deskripsi | Tipe |
|---|---|---|
| WS_PORT | — |
Pengecekan otomatis
Berjalan 14 Nov 2026Laporan lengkap →Belum diverifikasi. Sebuah server memerlukan skor 80, tidak ada temuan serius, dan data yang cukup untuk kami periksa. Cara kerja checks · Yang perlu diperbaiki untuk menambah poin
- Source repository terhubung dan dapat dijangkaucompnew2006/browser-controller is public and reachablegithub.com/compnew2006/browser-controller ↗Lolos
- Nama paket mencantumkan repositori ini sebagai sumbernyaTidak diperiksa
- Provenance build (atestasi Sigstore)Tidak diperiksa
- Lisensi open source (OSI)MITspdx.org/licenses/MIT.html ↗Lolos
- Ada commit atau release dalam satu tahun terakhirLast commit or release 2026-11-09github.com/compnew2006/browser-controller ↗Lolos
- 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 ↗Parsial 10/15
- Nama package tidak mirip dengan package populerTidak diperiksa
- Tidak ada advisory kritis pada paket atau dependensinyaTidak diperiksa
- Tidak ada instruksi tersembunyi untuk model25 tool descriptions and the README read; no override phrases, credential paths or hidden charactersLolos
- Tools yang bersifat destruktif telah diberi labelNo tool named like delete, drop or execLolos
- Endpoint remote merespons handshake MCPTidak diperiksa
README
Lihat di GitHubWhat 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.
Pertanyaan tentang Browser Controller MCP
Tool apa yang disediakan Browser Controller MCP?
Server ini menyediakan 25 tool, termasuk url, tabId, snapshot, action, browser.
Apakah ini menggunakan headless browser?
Tidak, tool ini memberikan kontrol langsung kepada agent terhadap browser yang sudah Anda buka, menggunakan sesi, login, dan cookies asli Anda.
Dapatkah beberapa AI agent menggunakan browser secara bersamaan?
Ya, beberapa agent dapat menjalankan tab yang berbeda secara simultan melalui satu daemon yang sama tanpa saling menghalangi.
Apakah data saya dikirim ke cloud?
Tidak, semua data tetap berada di mesin lokal Anda dan berkomunikasi melalui localhost.