Browser Pool MCP
This server provides a dynamic, isolated browser automation pool for concurrent agents via the MCP protocol and Playwright. Each agent gets its own browser instance by passing _agent_id, ensuring session isolation and conflict-free execution (omit _agent_id for a shared browser). It supports comprehensive automation actions:
Navigation: navigate to URLs, go back/forward, get current URL.
Interaction: click, type, press keys, hover, select options, drag & drop, file upload, handle dialogs.
Inspection: full-page/viewport screenshots, accessibility snapshots, console messages (filtered), network requests, JavaScript evaluation.
Waiting: wait for time, text to appear/disappear.
Tab & Window: list, create, switch, close tabs; resize and close browsers.
Pool Management: monitor per-agent status (
pool_status), close instances (browser_close), test async (pool_test).
Configure via environment variables (base port, max instances per wrapper, global max, idle timeout, debug logging). Supports on-demand spawning, graceful cleanup of idle/orphaned instances, and prevents termination of active browsers. Default max 10 concurrent browsers per wrapper, idle cleanup after 30 minutes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Browser Pool MCP open example.com in an isolated browser for agent-a and screenshot it"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
🖥️ Browser Pool MCP
Dynamic browser pool MCP server — every agent gets its own isolated browser.
English | 中文文档
A Model Context Protocol server that wraps
Microsoft's @playwright/mcp and
turns it into a dynamic browser pool: each unique caller gets its own
isolated Chrome instance, so multiple Claude Code sessions, subagents, or any
MCP clients can run browser automation concurrently without conflicts.
✨ Features
🧩 Per-agent isolation — each unique
_agent_idgets its own browser. No more"Browser is already in use"errors when multiple agents hit the browser at once.🚀 On-demand spawning — browsers are lazily started on first use (local CLI, ~1s), never pre-allocated.
🧹 Auto-cleanup — idle instances are killed after 30 min; orphaned instances from crashed wrappers are cleaned on startup.
🛡️ Never kills busy agents — when the pool is full, the wrapper evicts only idle instances; if all are busy it waits, so a running agent's browser is never yanked away.
🔁 Backward compatible — calling tools without
_agent_idshares one "default" browser, preserving original single-session behavior.🌐 Full Playwright toolset — all
@playwright/mcptools (navigate, click, type, screenshot, evaluate, tabs, network…), no feature loss.
Related MCP server: hanzi-browse
🧠 Architecture
Claude Code main session ──stdio──> playwright-pool-mcp (this server)
│
├── agent "A" ──SSE──> @playwright/mcp :9000 ──> Chrome A
├── agent "B" ──SSE──> @playwright/mcp :9001 ──> Chrome B
├── agent "C" ──SSE──> @playwright/mcp :9002 ──> Chrome C
└── "default" ──SSE──> @playwright/mcp :9003 ──> Chrome DThe wrapper does not control Chrome directly. It spawns @playwright/mcp
instances on demand and proxies MCP tool calls to them, adding per-agent routing.
🚀 Quick Start
Prerequisites
Node.js ≥ 18
npm
Install
git clone <your-repo-url> playwright-pool-mcp
cd playwright-pool-mcp
npm install
# First-time Chromium download (if needed):
npx playwright install chromiumConfigure Claude Code
User-level global config (~/.claude.json):
{
"mcpServers": {
"playwright-pool": {
"type": "stdio",
"command": "node",
"args": ["/path/to/playwright-pool-mcp/playwright-pool-script.js"],
"env": {
"BROWSER_POOL_BASE_PORT": "9000",
"BROWSER_POOL_MAX_INSTANCES": "10",
"BROWSER_POOL_GLOBAL_MAX": "12",
"BROWSER_POOL_INSTANCE_TIMEOUT_MS": "1800000",
"BROWSER_POOL_DEBUG": "0"
}
}
}
}Restart Claude Code. Tools appear as mcp__playwright-pool__*.
💡 Usage
Mode 1: Shared (backward compatible)
Omit _agent_id — all calls share one "default" browser:
mcp__playwright-pool__browser_navigate(url="https://example.com")
mcp__playwright-pool__browser_snapshot()Mode 2: Isolated per agent (recommended)
Pass _agent_id — each unique value gets its own browser:
subagent A: mcp__playwright-pool__browser_navigate(url="https://news.ycombinator.com", _agent_id="agent-a")
subagent B: mcp__playwright-pool__browser_navigate(url="https://github.com/trending", _agent_id="agent-b")
subagent C: mcp__playwright-pool__browser_navigate(url="https://www.baidu.com", _agent_id="agent-c")⚠️ Important: pass the same
_agent_idacross all calls from one agent to keep its browser state (cookies, login, navigation). Different agents use different values.
Subagent template
Create .claude/agents/web-worker.md:
---
name: web-worker
description: Run browser tasks (scraping / research / testing / automation)
tools: mcp__playwright-pool__*, Read, Bash
---
Use mcp__playwright-pool__* tools to operate the browser.
**Key rule: pass the `_agent_id` parameter on every browser tool call.**
The main conversation may dispatch multiple web-workers concurrently; different
workers must use different `_agent_id` values so each gets its own isolated browser.
Examples:
- mcp__playwright-pool__browser_navigate(url="...", _agent_id="worker-1")
- mcp__playwright-pool__browser_evaluate(function="...", _agent_id="worker-1")
Use the same `_agent_id` for all calls within one worker.🛠️ Tools
All tools accept an optional _agent_id parameter. Aligned 1:1 with @playwright/mcp v0.0.78.
ℹ️ Element targeting: interaction tools use
target(snapshot ref or CSS selector). Therefparameter is accepted as an alias fortarget(Claude Code's client maps it).
Tool | Description |
| Navigate to a URL |
| Go back |
| Accessibility tree (LLM-friendly) |
| Screenshot (PNG/JPEG) |
| Click element |
| Type text into element |
| Press keyboard key |
| Hover element |
| Select dropdown option |
| Drag & drop |
| Run JavaScript |
| Wait for condition |
| Find text in page snapshot |
| Fill multiple form fields (JSON array of |
| Manage tabs |
| Resize window |
| Handle alert/confirm |
| Upload files |
| Get console logs |
| Network activity |
| Mouse control (screen coordinates) |
| Run arbitrary code (dangerous) |
| Close browser for this agent |
| Pool status (per agent) |
⚙️ Configuration
All config via environment variables in ~/.claude.json — no code changes needed:
Variable | Default | Description |
|
| Starting port for browser instances |
|
| Max concurrent browsers per wrapper (≈300MB RAM each) |
|
| Global max browsers across ALL wrapper sessions (multiple Claude Code windows). File-lock based counter in |
|
| Idle timeout (30 min) |
|
| Set |
Changes take effect after restarting Claude Code.
💡 Global limit (
BROWSER_POOL_GLOBAL_MAX): each Claude Code window runs its own wrapper, andBROWSER_POOL_MAX_INSTANCESlimits only that wrapper. To cap browser instances across ALL sessions (e.g. two windows must share a total of 12), setBROWSER_POOL_GLOBAL_MAXto the same value in every session's config. Slots are counted via a lock-protected counter file (~/.browser-pool/global-count) and are released when instances close or the wrapper exits gracefully.
🔍 How It Works
Any browser tool call arrives → wrapper extracts
_agent_id(defaults to"default")Looks up the per-agent assignment map → reuse existing browser if alive
If none: check the global limit (
BROWSER_POOL_GLOBAL_MAX) → find a free port → spawn local@playwright/mcpCLI (node cli.js --port X --isolated)Mark the instance
busyduring the call, so eviction never kills an in-flight callPool full? Evict only idle instances (oldest first); if all busy, wait up to 60s
Idle > 30 min → auto-killed; wrapper startup scans for orphaned instances and cleans them (PPID-guarded, never kills another live session's browsers)
Global slot accounting: acquired before spawn, released when the instance closes or the wrapper exits gracefully
📦 Dependencies
@modelcontextprotocol/sdk— MCP protocol@playwright/mcp— browser automation enginezod— schema validation
📄 License
Available Tools
25 toolsbrowser_clickC
点击元素(element = a11y 引用,ref = CSS 选择器)
Inputs: ref (required), element (required), _agent_id.
browser_closeB
关闭该 agent 的浏览器
Inputs: _agent_id.
browser_console_messagesC
获取控制台消息
Inputs: level (required), _agent_id.
browser_dragC
把元素 A 拖到元素 B
Inputs: end_selector (required), start_selector (required), _agent_id.
browser_dropB
放下被拖拽的元素
Inputs: selector (required), _agent_id.
browser_evaluateC
在页面中执行 JavaScript(函数字符串)
Inputs: function (required), _agent_id.
browser_file_uploadD
上传文件
Inputs: paths (required), _agent_id.
browser_get_urlC
获取当前页面 URL
Inputs: _agent_id.
browser_handle_dialogC
处理 alert/confirm 弹窗
Inputs: accept (required), promptText (required), _agent_id.
browser_hoverC
悬停在元素上
Inputs: ref (required), element (required), _agent_id.
browser_network_requestsC
获取网络请求活动
Inputs: _agent_id.
browser_press_keyC
按下键盘按键
Inputs: key (required), _agent_id.
browser_resizeC
调整浏览器窗口大小
Inputs: width (required), height (required), _agent_id.
browser_screenshotC
截图(别名)
Inputs: fullPage (required), _agent_id.
browser_select_optionC
在下拉框中选择选项
Inputs: ref (required), values (required), element (required), _agent_id.
browser_snapshotB
获取页面可访问性快照(结构化,适合 LLM 阅读)
Inputs: _agent_id.
browser_tabsC
管理标签页(action: list|new|close|select)
Inputs: index (required), action (required), _agent_id.
browser_take_screenshotC
截图(默认 fullPage=false)
Inputs: fullPage (required), _agent_id.
browser_typeC
向元素输入文本
Inputs: ref (required), text (required), submit (required), element (required), +1 more.
browser_wait_forD
等待条件
Inputs: text (required), time (required), textGone (required), _agent_id.
pool_statusA
查看浏览器池状态(按 agent)
Inputs: no named parameters.
pool_testD
测试异步响应
Inputs: message (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 25 tools
Most tools have distinct purposes, but browser_take_screenshot and browser_screenshot are explicit aliases, causing ambiguity. Additionally, browser_drag and browser_drop could be confused as both relate to drag-and-drop operations.
The majority of tools follow a browser_verb pattern (e.g., browser_navigate, browser_click), but there are exceptions like browser_snapshot, browser_console_messages, and browser_network_requests which use nouns. The pair browser_take_screenshot and browser_screenshot also breaks consistency.
At 25 tools, the server is on the heavy side but still plausible for a comprehensive browser automation tool. However, the presence of a duplicate screenshot tool and a test tool (pool_test) suggests some redundancy.
The tool set covers a wide range of browser actions: navigation, interaction, screenshots, snapshots, tab management, dialog handling, file upload, and more. Minor gaps exist (e.g., no explicit cookie management or scrolling) but core workflows are well covered.
Maintenance
Related MCP Connectors
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
Whole browser tasks done in pilotfish's cloud for any MCP agent, signed in with your saved logins.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Cloud browsers for AI agents: get past bot detection, sign in with MFA, run web tasks at scale.
Related MCP Servers
- AlicenseCqualityDmaintenanceA dynamic browser pool MCP server that enables multiple concurrent, isolated Playwright sessions for Claude Code and other MCP clients. It manages on-demand instances on dynamic ports to resolve session conflicts and includes automatic cleanup of idle browsers.201MIT
- AlicenseNot gradedqualityDmaintenanceMCP server providing browser automation for AI agents with context-aware playbooks and skills for complex websites.41 npm179PolyForm Noncommercial 1.0.0

@meshbrow/mcp-serverofficial
AlicenseNot gradedqualityCmaintenanceMCP server for Meshbrow that gives AI agents full browser automation capabilities with stealth anti-detection, enabling natural language control of browser sessions, data extraction, and multi-browser fleets.MIT- AlicenseBqualityDmaintenanceEnables AI agents to control multiple independent browser instances in parallel with process-level isolation, supporting any backend MCP server for browser automation.271,223 npm19MIT