Skip to main content
Docker provides an isolated environment for running Playwright MCP, which is recommended for production deployments and security-sensitive scenarios.
The Docker implementation currently only supports headless Chromium.

Spawned Container Mode

In this mode, the MCP client spawns a new Docker container for each session.
{
  "mcpServers": {
    "playwright": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "--init",
        "--pull=always",
        "mcr.microsoft.com/playwright/mcp"
      ]
    }
  }
}

Configuration Options

  • -i: Interactive mode (required for STDIO communication)
  • --rm: Automatically remove container when it exits
  • --init: Use an init process to handle signals properly
  • --pull=always: Always pull the latest image before running

Long-Lived Service Mode

For better performance and resource management, you can run the container as a long-lived service instead of letting the MCP client spawn it.

Starting the Service

docker run -d -i --rm --init --pull=always \
  --entrypoint node \
  --name playwright \
  -p 8931:8931 \
  mcr.microsoft.com/playwright/mcp \
  cli.js --headless --browser chromium --no-sandbox --port 8931 --host 0.0.0.0

Configuration

  • -d: Run in detached mode
  • --name playwright: Name the container for easier management
  • -p 8931:8931: Map port 8931 to host
  • --host 0.0.0.0: Bind to all interfaces inside the container
  • --no-sandbox: Required in most Docker environments

Client Configuration

Configure your MCP client to connect to the HTTP endpoint:
{
  "mcpServers": {
    "playwright": {
      "url": "http://localhost:8931/mcp"
    }
  }
}
The server will be accessible on host port 8931 and can be reached by any MCP client.

Building Custom Docker Image

You can build the Docker image yourself for customization or local development.

Clone and Build

# Clone the repository
git clone https://github.com/microsoft/playwright-mcp.git
cd playwright-mcp

# Build the image
docker build -t mcr.microsoft.com/playwright/mcp .

Dockerfile Overview

The Dockerfile uses a multi-stage build:
ARG PLAYWRIGHT_BROWSERS_PATH=/ms-playwright

# Base stage: minimal runtime dependencies
FROM node:22-bookworm-slim AS base
ARG PLAYWRIGHT_BROWSERS_PATH
ENV PLAYWRIGHT_BROWSERS_PATH=${PLAYWRIGHT_BROWSERS_PATH}
WORKDIR /app

# Install dependencies and Playwright system deps
RUN npm ci --omit=dev && \
    npx -y playwright-core install-deps chromium

# Browser stage: download Chromium
FROM base AS browser
RUN npx -y playwright-core install --no-shell chromium

# Runtime stage: final image
FROM base
ENV NODE_ENV=production
ENV PLAYWRIGHT_MCP_OUTPUT_DIR=/tmp/playwright-output

USER node
COPY --from=browser --chown=node:node ${PLAYWRIGHT_BROWSERS_PATH} ${PLAYWRIGHT_BROWSERS_PATH}
COPY --chown=node:node packages/playwright-mcp/cli.js packages/playwright-mcp/package.json ./

ENTRYPOINT ["node", "cli.js", "--headless", "--browser", "chromium", "--no-sandbox"]

Docker Compose

For more complex deployments, use Docker Compose:
docker-compose.yml
version: '3.8'

services:
  playwright-mcp:
    image: mcr.microsoft.com/playwright/mcp
    container_name: playwright-mcp
    ports:
      - "8931:8931"
    environment:
      - NODE_ENV=production
      - PLAYWRIGHT_MCP_OUTPUT_DIR=/tmp/playwright-output
    command: [
      "node",
      "cli.js",
      "--headless",
      "--browser", "chromium",
      "--no-sandbox",
      "--port", "8931",
      "--host", "0.0.0.0"
    ]
    volumes:
      - playwright-output:/tmp/playwright-output
    restart: unless-stopped

volumes:
  playwright-output:

Start with Docker Compose

docker-compose up -d

Environment Variables

Pass environment variables to configure the server:
docker run -d -i --rm --init \
  --name playwright \
  -p 8931:8931 \
  -e PLAYWRIGHT_MCP_HEADLESS=true \
  -e PLAYWRIGHT_MCP_BROWSER=chromium \
  -e PLAYWRIGHT_MCP_ISOLATED=true \
  mcr.microsoft.com/playwright/mcp

Volume Mounts

Output Directory

Mount a volume to persist output files:
docker run -d -i --rm --init \
  --name playwright \
  -p 8931:8931 \
  -v $(pwd)/output:/tmp/playwright-output \
  mcr.microsoft.com/playwright/mcp

Configuration File

Mount a configuration file:
docker run -d -i --rm --init \
  --name playwright \
  -p 8931:8931 \
  -v $(pwd)/config.json:/app/config.json \
  mcr.microsoft.com/playwright/mcp \
  node cli.js --config /app/config.json --port 8931 --host 0.0.0.0

Security Considerations

Always use --no-sandbox when running in Docker due to kernel restrictions. The container itself provides isolation.

Best Practices

Run as non-root

The official image runs as the node user for security.

Use isolated mode

Enable --isolated to prevent persistent state between sessions.

Restrict network access

Use Docker networks and firewalls to limit container connectivity.

Limit resources

Use Docker resource constraints (--memory, --cpus) to prevent resource exhaustion.

Troubleshooting

Container exits immediately

Ensure you’re using -i (interactive) flag for STDIO mode or properly configuring HTTP mode with --port and --host 0.0.0.0.

Connection refused

Verify that:
  • The container is running: docker ps
  • Port mapping is correct: -p 8931:8931
  • Server is bound to 0.0.0.0 not localhost
  • Firewall allows the connection

Browser crashes

Add --no-sandbox flag (required in most Docker environments) and ensure sufficient memory is available.