MCP server Browser Controller
Commit 14 de nov. de 2026Permite que agentes de IA controlem suas sessões existentes do Chrome, incluindo logins e cookies, por meio de um MCP server e uma extensão.
Também conhecido como compnew2006/browser-controller
- Stars
- 9
- Ferramentas
- 25
- Downloads, 30 dias
- —
- Versão mais recente
- —
- Último commit
- 14 de nov. de 2026
- Licença
- MIT
O que é o MCP Browser Controller?
Browser Controller é um MCP server. Permite que agentes de IA controlem suas sessões existentes do Chrome, incluindo logins e cookies, por meio de um MCP server e uma extensão. Ele expõe 25 ferramentas, como url, tabId, snapshot.
Resumo gerado a partir do README do projeto
Sobre o MCP server de Browser Controller
O Browser Controller permite que agentes de IA interajam com suas sessões ativas nos navegadores Chrome, Edge ou Brave. Diferente da automação headless, esta ferramenta utiliza seus perfis existentes, o que significa que os agentes podem acessar seus logins, cookies e sessões autenticadas reais sem a necessidade de nova autenticação. Ele funciona por meio de um daemon local e uma extensão do Chrome, garantindo que todos os dados permaneçam na sua máquina via localhost, sem telemetria na nuvem.
Desenvolvedores podem utilizar isso com clientes compatíveis com MCP, como Cursor, Claude Desktop ou Windsurf. O sistema suporta múltiplos agentes simultaneamente através do uso de IDs de abas específicos, permitindo que um agente trabalhe em uma aba enquanto você continua navegando em outra. Ele oferece interação de alta fidelidade através do Chrome DevTools Protocol, garantindo que cliques e digitação sejam reconhecidos como eventos de usuário confiáveis. O servidor inclui 19 ferramentas para navegação, interação com elementos e avaliação de JavaScript, além de recursos para monitorar logs do console e requisições de rede.
O que você pode fazer com ele
- 1Verificação automatizada de softwareUm agente de IA pode verificar a correção de um código navegando até sua aplicação local e interagindo com a interface de usuário.
- 2Workflows paralelos multi-agenteExecute diferentes agentes de IA em abas separadas do navegador ao mesmo tempo, sem que eles interfiram entre si.
- 3Depuração e inspeção de redeSolicite ao agente que analise erros no console ou intercepte o tráfego de rede para solucionar problemas em aplicações web.
Escrito a partir do README do projeto. Cada caso de uso é verificado com uma citação dele.
Ferramentas do MCP Browser Controller 25
Detectadas a partir do READMEurltabIdsnapshotactionbrowserisolationaccesstrustedreadtargetquerymaxChars
| url | — | |
| tabId | — | |
| snapshot | — | |
| action | — | |
| browser | — | |
| isolation | — | |
| access | — | |
| trusted | — | |
| read | — | |
| target | — | |
| query | — | |
| maxChars | — |
Mostrar todas as 25 ferramentasMostrar menos ferramentas
propertiesruleslistenersenableddefaultActionsiteRulesbuttonexpectobservehoverselectuntilactions
| properties | — | |
| rules | — | |
| listeners | — | |
| enabled | — | |
| defaultAction | — | |
| siteRules | — | |
| button | — | |
| expect | — | |
| observe | — | |
| hover | — | |
| select | — | |
| until | — | |
| actions | — |
Configuração
WS_PORT
| Nome | Descrição | Tipo |
|---|---|---|
| WS_PORT | — |
Verificações automatizadas
Executado em 14 de nov. de 2026Relatório completo →Ainda não verificado. Um servidor precisa de uma pontuação de 80, nenhum problema grave e dados suficientes para verificarmos. Como as verificações funcionam · O que corrigir para ganhar mais pontos
- Repositório de origem vinculado e acessívelcompnew2006/browser-controller is public and reachablegithub.com/compnew2006/browser-controller ↗Passou
- O pacote indica este repositório como sua origemNão verificado
- Proveniência da build (atestação Sigstore)Não verificado
- Licença de código aberto (OSI)MITspdx.org/licenses/MIT.html ↗Passou
- Commit ou release no último anoLast commit or release 2026-11-09github.com/compnew2006/browser-controller ↗Passou
- 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 ↗Parcial 10/15
- Nome do pacote não é próximo a um pacote popularNão verificado
- Nenhum aviso crítico no pacote ou em suas dependênciasNão verificado
- Sem instruções ocultas para o modelo25 tool descriptions and the README read; no override phrases, credential paths or hidden charactersPassou
- Ferramentas destrutivas estão rotuladasNo tool named like delete, drop or execPassou
- O endpoint remoto responde ao handshake do MCPNão verificado
README
Ver no 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.
Perguntas sobre o MCP Browser Controller
Quais ferramentas o MCP Browser Controller oferece?
Ele expõe 25 ferramentas, incluindo url, tabId, snapshot, action, browser.
Isso utiliza um navegador headless?
Não, ele oferece aos agentes controle direto do navegador que você já tem aberto, utilizando suas sessões, logins e cookies reais.
Múltiplos agentes de IA podem usar o navegador ao mesmo tempo?
Sim, vários agentes podem controlar diferentes abas simultaneamente através de um único daemon compartilhado sem bloquear uns aos outros.
Meus dados são enviados para a nuvem?
Não, tudo permanece na sua máquina local e a comunicação é feita via localhost.