Secure Browser MCP

Secure Browser MCP

An MCP server that gives AI clients controlled access to a real headless browser with domain allowlisting, SSRF protection, per-session isolation, audit logging, and persistent cookies/state across restarts.

Category
Visit Server

README

Secure Browser MCP

An MCP server that gives an AI client (Claude, etc.) controlled access to a real headless browser on your server — with domain allowlisting, SSRF protection, per-session isolation, an audit log, and cookies/state that survive restarts.

Why "secure" specifically

Browser-automation MCPs are risky by default because the LLM effectively gets a pair of hands on a live browser that can reach anywhere on the internet (and, if misconfigured, your internal network). This server closes the common holes:

Risk Mitigation
SSRF (browser tricked into hitting internal services / cloud metadata endpoint) src/security.ts resolves DNS itself and blocks private/loopback/link-local IP ranges, independent of what hostname was requested
DNS rebinding (domain allowlisted, but later resolves to an internal IP) DNS is re-resolved and IP-checked on every navigation, not cached
javascript: / data: / file: URL abuse Scheme is rejected before anything touches the browser
Unrestricted destinations Hard allowlist via ALLOWED_DOMAINS — fails closed if empty
Unauthenticated access to the MCP endpoint Bearer token required on every request (MCP_AUTH_TOKEN)
Session/cookie leakage across tasks Each sessionId gets its own isolated BrowserContext (separate cookie jar, storage, cache)
Resource exhaustion MAX_SESSIONS cap + idle-session reaper (closes contexts unused for 30 min)
Silent/undetectable misuse Every tool call is written to a SQLite audit_log table with session, params, and result
Oversized responses blowing up context Text and screenshot payloads are size-capped
Drive-by downloads acceptDownloads: false by default

This covers the common attack surface, but you're still exposing a browser to an LLM. Keep ALLOWED_DOMAINS as narrow as your task allows, and run this on a host/container with no access to anything sensitive — treat it like you would a CI runner that executes untrusted code.

Persistent storage — what's actually persisted

Two things, both in SQLite at ./data/browser-mcp.db (path configurable via DATA_DIR):

  1. Browser state — cookies + localStorage per session, captured via Playwright's storageState() and restored on the next browser_navigate call for that sessionId. This is what lets a session stay logged in to a site across server restarts. Call browser_persist_session to save explicitly, or browser_close_session (which persists automatically).
  2. Audit log — every tool invocation, its params, and outcome, so you can review what the browser actually did later (browser_audit_log).

If you'd rather keep this in Supabase instead of local SQLite (e.g. so multiple server instances share state), swap storage.ts for Supabase calls — the function signatures are small and self-contained, so it's a drop-in replacement.

Setup

npm install
npx playwright install --with-deps chromium   # downloads the browser binary
cp .env.example .env
# edit .env: set MCP_AUTH_TOKEN and ALLOWED_DOMAINS
npm run build
npm start

For local iteration without building: npm run dev.

The server listens on POST http://localhost:8787/mcp (Streamable HTTP transport). Point your MCP client at that URL with:

Authorization: Bearer <your MCP_AUTH_TOKEN>

Tools exposed

  • browser_navigate(sessionId, url) — allowlist + SSRF-checked navigation
  • browser_get_text(sessionId, selector?) — read page/element text
  • browser_click(sessionId, selector)
  • browser_type(sessionId, selector, text)
  • browser_screenshot(sessionId) — base64 PNG
  • browser_persist_session(sessionId) — force-save cookies/localStorage
  • browser_close_session(sessionId) — persist + free browser resources
  • browser_list_sessions()
  • browser_audit_log(sessionId, limit?)

sessionId is any string you choose (e.g. "pranav-github-login") — reuse the same one to keep continuity (logged-in state, cookies) across calls.

Deploying on your existing server

  • Render: same pattern you used for the MongoDB MCP — set env vars in the dashboard (don't bake MCP_AUTH_TOKEN into the image), expose port 8787, and set the health check to GET /mcp returning 401 (expected, since it's unauthenticated) rather than a 200.
  • Put this behind HTTPS (Render/most PaaS do this for you) — the bearer token is meaningless over plain HTTP.
  • If the server also hosts other things, run this in its own container so the idle-session reaper and MAX_SESSIONS cap actually bound its resource use independently.

Extending

  • To let the LLM choose domains dynamically instead of a static allowlist, add an approval step (return a tool result asking for confirmation) rather than opening ALLOWED_DOMAINS wide.
  • To persist to Supabase instead of SQLite, replace the functions in src/storage.ts; the audit log schema maps directly to a Postgres table.
  • The MCP TypeScript SDK evolves — if npm install pulls a version with a different StreamableHTTPServerTransport API, check https://github.com/modelcontextprotocol/typescript-sdk for the current signature.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured