Skip to main content
Glama
Atlas-X-AI

Shade Browser Security MCP

by Atlas-X-AI

Shade Browser Security MCP

This repository exposes only the explicitly classified SECURITY tools from Shade Browser through a standalone MCP server. The implementation reuses the shared shade_browser_mcp browser core vendored in this repository; the public shade-browser-security entry point registers a separate FastMCP instance with the SECURITY allow-list only.

Run locally:

pip install -e '.[dev]'
shade-browser-security

The reduced/general server is maintained separately in the shade-browser-mcp repository's reduced-safe branch.

MCP server for Brave CDP browser automation across 20 flock-protected profile slots. Built on FastMCP + Playwright Python.

What this is

A one-shot-installable Model Context Protocol server that gives Claude Code a Brave browser with real cookies, auto-launched on demand, across 20 isolated slots (ports 61000-61019). Each slot gets its own profile copy by default, so parallel agents never collide on tabs or sessions. Persistent mode reuses a stable per-slot profile for manual logins, extensions, and browser config.

Related MCP server: BrowserMCP Secure

Install (3 commands)

uv tool install git+https://github.com/Atlas-X-AI/shade-browser-mcp
shade-browser-mcp postinstall
claude mcp add shade-browser-mcp --scope user -- shade-browser-mcp

Then restart Claude Code. Tools appear as mcp__browser-automation__*.

What each step does

Step

What it does

uv tool install git+...

Installs the Python package globally (isolated venv managed by uv)

shade-browser-mcp postinstall

Runs playwright install chromium — one-time Playwright browser fetch

claude mcp add ... --scope user ...

Registers the MCP in ~/.claude.json (user scope = available in all projects)

Upgrade an existing user-scope MCP install

Claude Code user-scope MCP registration runs the uv tool install copy of shade-browser-mcp. New tools do not appear in already-installed Hayden agent sessions until that tool install is replaced and Claude Code reconnects to the server.

For local development on the checked-out branch:

git switch feat/form-filler-bolt-on
uv tool install --force --editable .

Or install this branch directly from Git:

uv tool install --force git+https://github.com/Atlas-X-AI/shade-browser-mcp@feat/form-filler-bolt-on

Then fully exit and relaunch each Claude Code session that should see the new schema. Existing sessions keep the old MCP process and old tool list until they restart or reconnect that MCP server.

Smoke-test the installed server's tool registry:

uvx --from fastmcp fastmcp list --command "shade-browser-mcp" --json \
  | grep -E '"name": "form_(scan|fill|gate_check)"'

Prerequisites

  • Python 3.10+

  • uvcurl -LsSf https://astral.sh/uv/install.sh | sh

  • Claude Code CLI (for claude mcp add)

  • Brave browser at /opt/brave-bin/brave or /usr/bin/brave-browser

  • Brave profile at ~/.config/BraveSoftware/Brave-Browser (that's where your cookies come from — each slot gets a fresh cp -a copy)

Run shade-browser-mcp doctor after install to verify all six prerequisites.

Commands

shade-browser-mcp              # runs FastMCP stdio server (default — what Claude Code invokes)
shade-browser-mcp serve        # same as above
shade-browser-mcp postinstall  # playwright install chromium
shade-browser-mcp doctor       # health check: Brave, profile, Playwright, Claude registration
shade-browser-mcp --version

Runtime identity and safe rolling reload

Call the machine-readable MCP tool below on every connected server and after connecting to a candidate build:

browser_runtime_status(
  client_id="launcher-a",
  expected_version="0.1.10",
  expected_revision="<candidate-revision>"
)

The response includes the running server's version, revision, pid, UTC started_at, transport, effective focus defaults, and top-level reload_required/should_reload booleans. A build mismatch is deterministic: status is reload_required, reload.action is reconnect, and reload.process_action is always none. The server does not kill or restart itself and does not raise Brave, move the pointer, type, or call bring_to_front for this protocol. Focus defaults are browser_navigate=false and browser_switch_tab=false.

For a rolling reconnect, the launcher/client owns the transport lifecycle:

  1. Start the candidate server alongside the current server, injecting an immutable build value such as SHADE_BUILD_REVISION=$(git rev-parse --short HEAD).

  2. Probe the candidate with browser_runtime_status without expected values and record its returned version/revision as the target identity.

  3. Ask one client at a time to report status against that target identity. A client on the old server receives reload_required=true; close only that client's transport and reconnect it to the candidate. Other clients remain usable on the old server until their own turn.

  4. Verify each reconnected client with the same expected version/revision. A matching response has status=ready, reload_required=false, and the new PID/start time. Only the launcher decides when the old server is retired; this tool never performs that action.

If expected_version/expected_revision is omitted, the tool reports the identity but cannot detect staleness. If the revision is unknown, configure SHADE_BUILD_REVISION in the launcher; do not infer freshness from PID or start time. A reconnect failure leaves the existing client transport alone and must be handled by the launcher/client's normal retry policy.

Form-Filler Tools

Three bolt-on tools scan and fill ordinary web forms from a runtime JSON profile path:

form_scan(slot=-1)
form_fill(slot=-1, profile="docs/examples/form-fill-demo-profile.json", allow_submit=false)
form_gate_check(slot=-1, profile="docs/examples/form-fill-demo-profile.json")

form_scan returns field IDs, labels, required signals, option lists, upload controls, submit/advance controls, and profile-key hints such as person.email. form_fill reads the profile at call time, fills grounded fields, verifies read-back, and returns counts plus a gate check. Its response also includes additive field_outcomes entries with tier_used, committed, readback_value, escalate, and reason for each resolved field. Outcomes may also include attribution, for example pre_filled_verified:radio, when an already-filled control was verified before any actuation. form_gate_check verifies required fields, identity read-back, required uploads, visible page errors, and detector health.

Profile shape:

{
  "person": {"email": "casey@example.test", "first_name": "Casey"},
  "company": {"name": "Example Labs"},
  "files": {"Resume": "relative/or/absolute/path.txt"},
  "values": {"Work Type": "full time", "Location": ["Remote United States", "Remote"]},
  "never_submit": true
}

values entries override inferred person/company mappings by field ID or label. Option choices are grounded only by exact text/value equality after mechanical normalization, or by explicit profile variant lists. Relative upload paths resolve relative to the profile file. If never_submit is true, form_fill(..., allow_submit=true) still refuses to click submit.

Worked examples after navigating a browser slot to a form:

form_scan(slot=4)

Returns form inventory such as field IDs, labels, required signals, upload controls, options, submit controls, and inferred profile-key hints.

form_fill(slot=4, profile="docs/examples/form-fill-demo-profile.json", allow_submit=false)

Fills grounded fields from the JSON profile, verifies read-back, uploads files declared in files, and returns a nested gate check without submitting.

form_gate_check(slot=4, profile="docs/examples/form-fill-demo-profile.json")

Reports whether required fields, identity fields, required uploads, visible validation errors, and detector health are all ready for a guarded submit.

See docs/examples/form-fill-demo-profile.json and docs/examples/form-fill-live-slot-transcript.md for a real-slot loopback fixture transcript. docs/examples/form-fill-local-transcript.md is a shorter local fixture summary. The consolidated capabilities, schema, safety, packaging, and opt-in upgrade guide is docs/form-fill/README.md.

Headed vs headless mode

By default, shade-browser-mcp launches Brave headed if DISPLAY or WAYLAND_DISPLAY is set, and headless otherwise (CI, SSH sessions without X forwarding, systemd units without a user display).

To force a visible window regardless of env:

export HEADED=1
shade-browser-mcp

To force headless on a desktop session:

unset DISPLAY WAYLAND_DISPLAY
shade-browser-mcp

The HEADED=1 knob is useful when you want to watch an AI agent drive the browser, or when the MCP daemon was launched from an env that lacks DISPLAY but you later want to attach visibly.

Persistent profiles and Bitwarden

Default slot mode refreshes ~/.cache/brave-cdp/slot-N/ from the real Brave profile on launch. Persistent mode uses ~/.cache/brave-cdp/persistent/slot-N/ and reuses that profile across launches, so manual ChatGPT login, installed extensions, and browser settings survive.

export SHADE_PROFILE_MODE=persistent
export SHADE_INGEST_BW=1
shade-browser-mcp

You can also launch one slot manually:

launch-brave-cdp 5 --persistent

SHADE_INGEST_BW=1 runs ~/bin/bw-ensure.sh when BW_SESSION is absent and passes the resulting BW_SESSION only through the MCP/Brave launcher environment. Tokens are not written to manifests, screenshots, or browser session files.

Architecture (one-liner)

BrowserManager._ensure_brave_alive() on each tool call → httpx-probe port → if dead, subprocess.run(bash launch-brave-cdp N) with env including DISPLAY/WAYLAND_DISPLAY/XAUTHORITY/XDG_RUNTIME_DIR → poll 20s at 1Hz → playwright.connect_over_cdp(). Slots are flock-protected via cdp_slots.claim_slot().

Per-slot CDP auth proxy (Phase 1, library only)

A protocol-layer slot-ownership proxy ships in shade_browser_mcp.cdp_proxy. Each slot now carries an auth_token (256-bit, generated by claim_slot) and a private_port (62000+slot) where Brave will eventually bind. The proxy listens on the public port (61000+slot), validates Authorization via a /t/<token>/... URL prefix, and rewrites webSocketDebuggerUrl so Playwright's WS upgrade also carries the token.

CLI:

python -m shade_browser_mcp.cdp_proxy <slot>             # passthrough mode
python -m shade_browser_mcp.cdp_proxy <slot> --require-token  # enforce

Phase 1 ships the library + tests + audit fixes only — the proxy is not yet wired into _ensure_brave_alive. That production wiring (and the matching launch-brave-cdp --private-port flag) lands in a Phase 2 follow-up. Users who want to opt in early can drive the proxy module directly. See DONE.md for the migration ledger and audit-deferred items.

Shade Fleet Console (local dashboard)

A read-mostly local web console for watching and steering the 20 slots. It is a single-host operator tool, not a shared service.

export SHADE_DASHBOARD_TOKEN=$(openssl rand -hex 32)
shade-browser-mcp dashboard --port 8790
  • Loopback only. The console binds 127.0.0.1 exclusively and refuses to start on any non-local host (no --allow-nonlocal escape hatch in v1).

  • Token via env. The bearer token is read from the SHADE_DASHBOARD_TOKEN environment variable.

  • Opener URL carries the token in the fragment, never a query string. On start the server prints http://127.0.0.1:8790/#token=<token>. The fragment (#token=...) is never sent to the server in a request line and never lands in access logs; a query string (?token=...) would, so it is deliberately not used.

  • API auth uses a header. Every /api/* request must carry Authorization: Bearer <token>. The page JS reads the token from the URL fragment and replays it as that header; it is never written to localStorage/sessionStorage.

Phase 2 endpoint model

Phase 2 splits each slot into a private upstream port and a public proxied port:

Port

Who binds it

Reachable by

Auth

127.0.0.1:6200N (private)

Brave (CDP)

proxy only

n/a (loopback, private)

127.0.0.1:6100N (public)

per-slot auth proxy

local clients

tokenized path

  • Brave now binds the private per-slot port 127.0.0.1:6200N.

  • The per-slot auth proxy listens on the public port 127.0.0.1:6100N.

  • Internal Playwright attach uses the tokenized path http://127.0.0.1:6100N/t/<token> — the token rides in the URL path so it survives the WebSocket upgrade.

  • Direct unauthenticated access to 6100N is rejected with 401. A missing or wrong token never reaches Brave.

Synthetic Action View

The console renders each slot's recent activity from structured data, not from a live pixel feed:

  • Structured browser events are written to browser-events.jsonl (a separate stream from the existing actions.jsonl audit log), surfaced through GET /api/slots/{n}/events.

  • Each slot shows its current URL/title plus compact ARIA/text snapshots.

  • Screenshots are captured only on demand, on failure, or as evidence — there are no continuous thumbnails and no rolling viewport capture.

POST controls (all under Authorization: Bearer <token>):

POST /api/slots/{n}/navigate     # navigate the slot to a URL
POST /api/slots/{n}/screenshot   # capture one frame on demand / as evidence
POST /api/slots/{n}/release      # release the slot
POST /api/slots/{n}/focus        # focus / observe the slot
POST /api/slots/{n}/takeover     # operator takeover
POST /api/slots/{n}/resume       # hand control back to the agent

Example read call (sanitized fleet view):

SHADE_TOKEN="$SHADE_DASHBOARD_TOKEN"
curl -H "Authorization: Bearer $SHADE_TOKEN" http://127.0.0.1:8790/api/fleet

The single-frame capture endpoint is POST /api/slots/{n}/screenshot; issue it only when you actually need an on-demand frame.

v1 non-goals

The console deliberately does not include:

  • an agent-task launcher from the web view,

  • continuous screenshots or live viewport streaming,

  • an injected in-page recorder,

  • cloud sync, multi-user accounts, TLS, or any public (non-loopback) binding.

Uninstall

claude mcp remove shade-browser-mcp --scope user
uv tool uninstall shade-browser-mcp
rm -rf ~/.cache/brave-cdp/           # purge slot profile copies

Development

git clone https://github.com/Atlas-X-AI/shade-browser-mcp
cd shade-browser-mcp
uv sync --dev
uv run shade-browser-mcp doctor

Design notes

  • Vendored dependenciescdp_slots.py and launch-brave-cdp ship inside the package (loaded via importlib.resources). No symlinks, no external ~/bin/ scripts, no assumptions about the host.

  • Wheel loses exec bit — the shell script is invoked via bash <path> <slot> regardless of its executable bit after install.

  • No Brave auto-install — intentional. The package won't try to install Brave for you; run shade-browser-mcp doctor to find out if you're missing it.

  • User-scope MCP registration — the server runs under uv tool install's isolated venv; claude mcp add --scope user points Claude at the installed entry-point, no manual JSON surgery.

Supersedes

  • /home/anombyte/Hermes/current-projects/atlas-shade/shade-mcp/browser-server.py (monorepo path)

  • /home/anombyte/bin/browser-mcp-proxy.sh (wrapper script)

  • /home/anombyte/bin/launch-brave-cdp (now vendored)

Previous wiring relied on an external ~/bin/launch-brave-cdp and a symlinked cdp_slots.py from claude-launcher. That's fragile across reinstalls — this package fixes it.

Install Server
A
license - permissive license
B
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    A universal browser automation MCP server using Playwright, enabling programmatic control of Chrome with 63 tools for navigation, interaction, media control, and CDP-based diagnostics.
    63
    16
    1
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    Security-hardened MCP server that gives AI assistants full control over your real browser session, supporting 36 tools for navigation, data extraction, monitoring, and more.
    MIT
  • F
    license
    B
    quality
    B
    maintenance
    An MCP server for generic browser automation using Playwright. Enables MCP clients to navigate pages, inspect elements, execute JavaScript, capture screenshots, and monitor console logs and network traffic via a headless Chromium instance.
    7

View all related MCP servers

Related MCP Connectors

  • A paid remote MCP for AI agent browser MCP session, built to return verdicts, receipts, usage logs,

  • Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.

  • A paid remote MCP for AI agent browser approval MCP, built to return verdicts, receipts, usage logs,

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Atlas-X-AI/shade-browser-security'

If you have feedback or need assistance with the MCP directory API, please join our Discord server