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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。