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.
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):
- Browser state — cookies + localStorage per session, captured via
Playwright's
storageState()and restored on the nextbrowser_navigatecall for thatsessionId. This is what lets a session stay logged in to a site across server restarts. Callbrowser_persist_sessionto save explicitly, orbrowser_close_session(which persists automatically). - 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 navigationbrowser_get_text(sessionId, selector?)— read page/element textbrowser_click(sessionId, selector)browser_type(sessionId, selector, text)browser_screenshot(sessionId)— base64 PNGbrowser_persist_session(sessionId)— force-save cookies/localStoragebrowser_close_session(sessionId)— persist + free browser resourcesbrowser_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_TOKENinto the image), expose port8787, and set the health check toGET /mcpreturning 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_SESSIONScap 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_DOMAINSwide. - 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 installpulls a version with a differentStreamableHTTPServerTransportAPI, check https://github.com/modelcontextprotocol/typescript-sdk for the current signature.
Recommended Servers
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.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.