By Shyam Verma·

Playwright MCP for Container Automation

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:

  1. You can't run browsers directly in containers - Browsers need display servers, GPU access, and system libraries that containers don't provide reliably
  2. MCP servers running on host need connection management - Your containerized development environment needs to connect to MCP servers on the host machine
  3. 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.

Comments

Interested in Collaborating?

Whether it's a startup idea, a technical challenge, or a potential partnership—let's have a conversation.

20+
Years Experience
150K+
Websites Powered
2
Successful Exits
7x
Faster with AI