Playwright MCP for Container Automation

Browsers don't run well in containers, MCP servers crash frequently, and connecting containerized environments to host browsers is a nightmare.
That's why I built playwright-mcp-wrapper.
The Problem
When developing inside Docker containers, you face three major challenges:
- You can't run browsers directly in containers - Browsers need display servers, GPU access, and system libraries that containers don't provide reliably
- MCP servers running on host need connection management - Your containerized development environment needs to connect to MCP servers on the host machine
- Frequent server crashes - Playwright MCP servers are unstable and crash mid-task
The typical solution? Run MCP servers on your host machine and connect to them from containers. But this creates a new problem: who manages the servers, keeps them running, and handles multiple browsers?
The Solution: playwright-mcp-wrapper
1. Persistent Process Management with PM2
Instead of manually starting/stopping MCP servers, the wrapper uses PM2 to:
- Auto-start all browser servers with a single command
- Auto-recover when servers crash
- Monitor server health
- Provide centralized logs
npm start # Start all browser servers
npm stop # Stop all servers
npm test # Test all endpoints
2. Multi-Browser Support with Dedicated Ports
The wrapper manages 6 different browser types, each on its own dedicated port:
- Chrome (8931)
- Brave (8932)
- Firefox (8933)
- Chromium (8934)
- WebKit (8935)
- Comet (8936)
Plus two additional persistent browser profiles on ports 8941-8942.
3. Seamless Container Integration
Local development:
{
"mcpServers": {
"playwright-chrome": {
"url": "http://localhost:8931/sse"
}
}
}
Inside Docker/DevContainer:
{
"mcpServers": {
"playwright-chrome": {
"url": "http://host.docker.internal:8931/sse"
}
}
}
That's it. The host.docker.internal hostname automatically resolves to your host machine from inside the container.
How It Works
The project uses an ecosystem.config.js file that defines PM2 apps for each browser:
module.exports = {
apps: [
{
name: "mcp-chrome",
script: "npx",
args: "-y @executeautomation/playwright-mcp-server ./chrome.json",
cwd: "./browser-configs",
autorestart: true,
watch: false
},
// ... more browsers
]
};
Each browser has its own JSON config file specifying the port and browser type:
{
"port": 8931,
"browserName": "chrome"
}
Why I built this
I develop exclusively inside DevContainers. Every time I needed browser automation, something would break. Server crashes mid-task, connections timed out, and I had to manually restart processes.
Now my workflow is simple: start the servers once on my host machine, point my DevContainer config at host.docker.internal, and forget about it. If a server crashes, PM2 restarts it. If I need a different browser, I just change the port number.
Installation
git clone https://github.com/ssv445/playwright-mcp-wrapper.git
cd playwright-mcp-wrapper
npm install -g pm2 playwright
npm install
npm start
Visit any browser's SSE endpoint to verify it's running:
curl http://localhost:8931/sse
If you develop in containers and need browser automation, the repo is at playwright-mcp-wrapper. Issues and PRs welcome.