Discover MCPs & agents
Loading MCPs and agents…
Loading MCPs and agents…
Give your AI agent a real browser — with a human in the loop. Open-source MCP-native browser agent.
Fetched from the repository for this visit.

Give your AI agent a real browser, with a human in the loop.
Auto Browser is an MCP-native browser control plane for authorized workflows. It gives MCP clients, LLM agents, and operators a shared Playwright browser with human takeover, reusable auth profiles, approvals, audit trails, and local-first deployment.
Works with:
scripts/verify_witness_bundle.py — which imports nothing from this project, so a recipient need not run or trust this controller to check it. The signing key sits beside the receipts, so for evidence that survives a compromised box, pin a head hash you recorded earlier or ship the receipts off the box (details).docs/audits/2026-08-execution-audit.md documents an adversarial audit of this repo that found safety controls which reported success while doing nothing, with reproductions, the fixes, and the gates that close the class.| Browser Control | Operator Safety | Deployment and Integration |
|---|---|---|
| Playwright-backed sessions with screenshots, DOM summaries, OCR excerpts, tab controls, downloads, and network inspection | approval gates, operator identity headers, audit events, PII scrubbing, Witness receipts, and protection profiles | MCP over HTTP, bundled stdio bridge, REST API, Docker Compose, Codespaces, auth profiles, and optional per-session isolation |
git clone https://github.com/LvcidPsyche/auto-browser.git
cd auto-browser
docker compose up --build
That is enough for local development with the default settings. On first start the controller
generates an API token and saves it to data/api-token in this folder (git ignores it), and
every API and MCP request must send it as Authorization: Bearer <token>. The dashboard asks
for it once, the examples below read it with $(cat data/api-token), and the MCP clients take
it as shown under MCP Clients. API_ALLOW_TOKENLESS_LOOPBACK=true runs the
controller without a token, as it ran before, but then any container on the compose network
can drive the browser.
Optional:
cp .env.example .env
make doctor
Run make doctor from a normal terminal with local Docker access and permission to open localhost sockets.
Open:
http://127.0.0.1:8000/docs (Authorize with the token to try requests). The docs need no token on a loopback deployment (an exposed one answers 401), and Swagger UI loads its assets from cdn.jsdelivr.net.http://127.0.0.1:8000/dashboard, which includes the queue of actions waiting on your approval;
paste the token when it asks, or open http://127.0.0.1:8000/dashboard#token=<token>http://127.0.0.1:6080/vnc.html?autoconnect=true&resize=scaleAll published ports bind to 127.0.0.1 by default.
Every release is also published to GHCR, so you can skip the build:
docker compose -f docker-compose.yml -f docker-compose.images.yml up -d
AUTO_BROWSER_IMAGE_TAG picks the version: latest (the default), a release such as 1.10.1, or
edge for the current main. The images are linux/amd64, and each carries an SBOM and a build
provenance attestation (gh attestation verify oci://ghcr.io/lvcidpsyche/auto-browser-controller:latest -R LvcidPsyche/auto-browser).
The controller image leaves out the agent CLIs; for *_AUTH_MODE=cli, build from source with
INSTALL_AGENT_CLIS=true.
With isolated sessions, name docker-compose.images.yml last, so they start from the published browser image too:
docker compose -f docker-compose.yml -f docker-compose.isolation.yml -f docker-compose.images.yml up -d
In the other order, the isolation overlay's default wins, and isolated sessions run a local
auto-browser-browser-node:latest: a stale build, or no image at all.
Codespaces provisions the stack automatically. The dashboard and noVNC tabs are usually ready in about 90 seconds.
The highest-signal flow in this repo is:
Start here:
Minimal session creation, from the auto-browser folder (AUTH carries the token; if you
set API_BEARER_TOKEN, use $API_BEARER_TOKEN in place of $(cat data/api-token)):
AUTH=(-H "Authorization: Bearer $(cat data/api-token)")
curl -s "${AUTH[@]}" http://127.0.0.1:8000/sessions \
-X POST \
-H 'content-type: application/json' \
-d '{"name":"demo","start_url":"https://example.com"}' | jq
Minimal observation:
curl -s "${AUTH[@]}" http://127.0.0.1:8000/sessions/<session-id>/observe | jq
1.10.1
main commit whose CI run succeeded.1.10.0
API_BEARER_TOKENS), saved auth state, exported archives, harness runs, skill candidates, memory profiles, uploads, MCP resource lists and controller-wide approvals belong to the operator who made them.ALLOWED_HOSTS holds wherever a page ends up: after a redirect, a tab switch, a cookie written through browser.set_cookies, or a page that navigates itself or opens a popup (a popup's first page is held from 1.11.2). A page that gets off the list on its own is sent back to about:blank once it has navigated, not before its request goes out.valid now covers signatures. Read the upgrade notes in the changelog before upgrading.FORCE_GOVERNED_APPROVALS.1.9.1
1.9.0
API_BEARER_TOKENS), a session belongs to the operator who created it, as auth profiles already did..env reaches the controller. Compose used to forward only the keys it listed, so settings like API_BEARER_TOKENS and PII_SCRUB_* were ignored. Check your .env before upgrading.1.8.1
MAX_SESSIONS holds under concurrent creates, and sessions, tabs, cron jobs and the JSON stores no longer leak or lose writes.REQUIRE_OPERATOR_ID=true.create_session with totp_secret now needs totp_hosts or a start_url.See CHANGELOG.md for the full release history.
Auto Browser exposes:
http://127.0.0.1:8000/mcphttp://127.0.0.1:8000/mcp/tools and http://127.0.0.1:8000/mcp/tools/calluvx auto-browser-mcp from PyPI, or scripts/mcp_stdio_bridge.py in a repo checkoutClients that speak MCP over HTTP connect directly, sending the controller's token. With Claude
Code or Codex, from the auto-browser folder (--scope user makes the server available in every
project, not only this folder):
claude mcp add --transport http --scope user auto-browser http://127.0.0.1:8000/mcp \
--header "Authorization: Bearer $(cat data/api-token)"
# Codex reads the token from the variable you name: export it wherever Codex runs.
export AUTO_BROWSER_TOKEN="$(cat data/api-token)"
codex mcp add auto-browser --url http://127.0.0.1:8000/mcp --bearer-token-env-var AUTO_BROWSER_TOKEN
Google Antigravity takes the server in its raw MCP config (MCP Servers, then Manage MCP
Servers, then View raw config), or in ~/.gemini/config/mcp_config.json. It reads
serverUrl, not url, and the token goes in headers:
{
"mcpServers": {
"auto-browser": {
"serverUrl": "http://127.0.0.1:8000/mcp",
"headers": { "Authorization": "Bearer <contents of data/api-token>" }
}
}
}
Cursor, VS Code, Claude Desktop through the stdio bridge (which reads the file named by
AUTO_BROWSER_TOKEN_FILE / --token-file; the repo wrapper, make stdio-bridge or
scripts/mcp_stdio_bridge.py, defaults that to its checkout's data/api-token for a loopback
URL), and pairing Auto Browser with a web-search MCP server are covered in
docs/mcp-clients.md.
The default MCP tool profile is curated: the 20 tools a browsing agent needs (sessions, observe and screenshot, execute_action, page and download reading, tabs, auth profiles, human takeover). Every listed tool costs the model context on every request, so the diagnostics, audit, harness, and admin tools are in the full profile. To expose everything, set:
MCP_TOOL_PROFILE=full
MCP_TOOL_PROFILE=lean serves just the 7-tool browsing loop (observe, screenshot, execute_action, get_html, find_elements, human takeover, close), and MCP_TOOL_PACKS adds or removes named packs on top of any profile, e.g. MCP_TOOL_PACKS=tabs,downloads or -scripting. The pack table is in docs/mcp-clients.md.
Raw tool-call example:
curl -s "${AUTH[@]}" http://127.0.0.1:8000/mcp/tools/call \
-X POST \
-H 'content-type: application/json' \
-d '{
"name":"browser.create_session",
"arguments":{
"name":"demo",
"start_url":"https://example.com"
}
}' | jq
Client setup guides:
docs/mcp-clients.mdexamples/claude-desktop-setup.mdexamples/cursor-mcp-setup.mdexamples/claude_desktop_config.jsonFor resource listing, resource reads, and subscription-style update examples,
see docs/mcp-clients.md#resources-and-subscriptions.
Auto Browser ships a Stage 0 convergence harness for Agent Skill Induction. It runs a structured task contract, records tamper-checked traces, verifies completion, and writes a staged skill candidate carrying provenance. With a mesh identity configured that provenance is signed, and the registry verifies the signature before serving a candidate — a candidate that fails the check, or that was dropped into the staging directory unsigned, is refused. Candidates induced from a mock run are marked simulated so they cannot pass as converged. Generated skills are staged only — promotion stays explicit and reviewed.
The harness tools — convergence runs, run status and traces, drift checks, candidate management, and graduation — are in the full MCP tool profile (MCP_TOOL_PROFILE=full), or can be invoked directly over REST.
Start with docs/convergence-harness.md. A deterministic local smoke is:
python -m controller.harness.run --contract evals/contracts/example_read.json --mock-final-url https://example.com --mock-final-text "Example Domain"
For MCP clients, set MCP_TOOL_PROFILE=full (or MCP_TOOL_PACKS=harness on top of curated) to expose the harness.* tools.
For a real private deployment, set at least:
APP_ENV=production
API_BIND_SCOPE=exposed
API_BEARER_TOKEN=<strong-random-secret>
REQUIRE_OPERATOR_ID=true
AUTH_STATE_ENCRYPTION_KEY=<44-char-fernet-key>
REQUIRE_AUTH_STATE_ENCRYPTION=true
SHARE_TOKEN_SECRET=<strong-random-secret>
CONTROLLER_ALLOWED_HOSTS=<controller hostname>
ALLOWED_HOSTS=<sites the browser may visit>
REQUEST_RATE_LIMIT_ENABLED=true
METRICS_ENABLED=true
STEALTH_ENABLED=false
With APP_ENV=production the controller refuses to start while any of these is missing, and the startup log names the missing ones.
By default every session shares one Chromium process and one noVNC desktop (SESSION_ISOLATION_MODE=shared_browser_node). Cookies and storage stay separate per session, but a human taking over one session can see the others' windows. When sessions belong to different people, accounts or trust domains, start with make up-isolation to give each session its own browser container, takeover surface and Docker network (docker_ephemeral), so one session's browser cannot reach another's Playwright server. docs/session-isolation-audit.md has the details.
ALLOWED_HOSTS is held before the request goes out (PRE_REQUEST_BLOCKING=true, the default):
ALLOWED_HOSTS, including
every redirect hop and a popup's first request.about:blank once it
commits):
/readiness warns when that failed);blob: navigations a refused iframe makes;In an attach mode (CDP_CONNECT_URL, browser.cdp_attach) the gate stops navigations of the controller's
sessions only (apart from a frame it cannot classify, above), but every navigation in that Chrome, the
operator's own tabs included, waits on its reply: about 13 ms each, the median measured on Chromium 151. Start
that Chrome with --disable-features=BlockOriginHeaderModificationOnRedirect,AvoidCorsURLLoaderRestartOnRedirect
and set CDP_BLOCK_ORIGIN_ON_REDIRECT_DISABLED=true. Without it, cross-origin 307/308 POST redirects can fail, and
on Chrome 155 and later credentialed cross-origin requests that need a CORS preflight fail after a redirect, in
the operator's own tabs too, while the controller is attached. Details:
docs/deployment.md.
COMPLIANCE_TEMPLATE can apply a preconfigured posture at startup:
| Preset | Auth Encryption | Operator ID | PII Scrub | Isolation | Max Session Age |
|---|---|---|---|---|---|
strict | required | required | all layers | docker_ephemeral | 4h |
balanced | - | required | network + text | shared | 24h |
Both presets require upload approvals and enable Witness receipts. Startup writes the applied policy to /data/compliance-manifest.json. The legacy names (HIPAA, SOC2, GDPR, PCI-DSS) still work as deprecated aliases and emit a warning at startup.
Example:
COMPLIANCE_TEMPLATE=strict docker compose up
For deployment details, hosted Witness notes, CLI auth modes, and reverse-SSH guidance, see:
docs/deployment.mddocs/production-hardening.mddocs/session-isolation-audit.md: what each isolation mode does and does not separateflowchart LR
User[Human operator] -->|watch / takeover| noVNC[noVNC]
LLM[Any model: OpenAI / Claude / Gemini / OpenRouter / Grok / DeepSeek / MiniMax / local] -->|shared tools| Controller[Controller API]
Controller -->|Playwright protocol| Browser[Browser node]
noVNC --> Browser
Browser --> Artifacts[(screenshots / traces / auth state)]
Controller --> Artifacts
Controller --> Policy[Allowlist + approval gates]
First-class adapters for OpenAI, Claude, and Gemini (API or CLI). Beyond those,
a single generic OpenAI-compatible adapter drives any model reachable over an OpenAI
/chat/completions endpoint — set an API key to enable it:
| Provider | Reaches |
|---|---|
openrouter | one key → ~every frontier model (Claude, GPT, Gemini, Grok, DeepSeek, Llama, Mistral, Qwen, …) |
xai | Grok |
deepseek | DeepSeek (text-only; driven from the DOM/accessibility outline) |
minimax | MiniMax |
openai_compatible | any custom base URL — self-hosted Ollama / vLLM / LM Studio, Azure OpenAI, Together, Groq, Fireworks, … |
Vision (screenshots) is used for every provider except text-only ones. See .env.example for
the *_API_KEY / *_BASE_URL / *_MODEL settings.
Core components:
browser-node/ runs Chromium, Xvfb, x11vnc, and noVNCcontroller/ exposes the FastAPI controller, MCP transport, policy rails, and orchestration endpointsdata/ holds runtime artifacts, auth state, approvals, audit logs, and optional CLI cachesscripts/ contains local helpers for doctor, smoke tests, bridges, and release checks| Path | What It Contains |
|---|---|
controller/ | controller API, MCP transport, tests, and packaging |
browser-node/ | browser runtime and Playwright connection layer |
examples/ | copy-paste flows and MCP client setup |
integrations/langchain/ | LangChain, LangGraph, and CrewAI adapters |
docs/ | architecture, deployment, hardening, and launch docs |
scripts/ | doctor, smoke harnesses, stdio bridge, and auth helpers |
ops/ | supporting service templates and operational assets |
| Command | Purpose |
|---|---|
make help | list available repo commands |
make lint | run Ruff checks across the whole repo |
make test | run controller tests in Docker |
make test-local | run controller tests on host Python 3.11+ |
make eval | run deterministic provider/profile eval scoring |
make doctor | run the local readiness smoke |
make release-audit | run the fuller release-validation pass |
make smoke-isolation | verify per-session Docker isolation |
make smoke-reverse-ssh | verify reverse-SSH remote access |
| If You Want To... | Start Here |
|---|---|
| understand the system shape | docs/architecture.md |
| connect Claude, Codex, Antigravity, Cursor, or VS Code | docs/mcp-clients.md |
| run the curl-first examples | examples/README.md |
| deploy on a trusted host | docs/deployment.md |
| review production constraints | docs/production-hardening.md |
| see what session isolation does and does not separate | docs/session-isolation-audit.md |
| run the convergence harness | docs/convergence-harness.md |
| inspect release history | CHANGELOG.md |
| see where the project is headed | ROADMAP.md |
If you want to help, start with:
If Auto Browser is useful, a star helps other people find it. Sponsorship and tip options live in TIPS.md.
Loading reviews...
GitHub checked 310h ago - refresh overdue. Recently viewed repositories target hourly refresh.
Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). Connect directly and complete any provider authentication separately; this is not platform-key access.
Tool
OS
Config file: ~/.cursor/mcp.json
{
"mcpServers": {
"mcp-server": {
"url": "{MCP_ENDPOINT_URL}"
}
}
}Paste into mcpServers in the config file. Restart Cursor after saving.
If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.