Playwright MCP: Complete Setup Guide & Browser Automation
Playwright MCP is the bridge between AI agents and real browsers. Instead of describing what a webpage looks like and hoping an AI can act on it, Playwright MCP gives Claude, Cursor, Codex, and Copilot direct, structured control over Chromium, Firefox, and WebKit — navigation, clicks, form fills, screenshots, and full DOM inspection, all through standard MCP tool calls.
This guide covers everything: installation for every major AI client, how the accessibility snapshot system works, headless vs. headed mode, persistent and isolated sessions, security hardening, Docker deployment, and common production pitfalls. If you've ever wanted to give an AI agent a browser, this is how you do it properly.
What Playwright MCP Actually Is
Microsoft's @playwright/mcp package is an MCP server that exposes Playwright browser automation as a set of typed tools. When an AI client connects to it, the agent gains tools like:
browser_navigate— load a URLbrowser_click— click an element by description or selectorbrowser_type— fill a text fieldbrowser_snapshot— capture the accessibility treebrowser_screenshot— take a visual screenshotbrowser_wait_for— wait for conditionsbrowser_evaluate— execute JavaScript in page context
Under the hood, every tool call maps to Playwright API calls. The MCP server handles JSON-RPC transport (stdio or SSE), manages browser lifecycle, and returns structured results the AI can reason about.
This is architecturally different from asking an AI to write Playwright scripts and run them yourself. The AI is the operator — it decides what to click, reads the result, and iterates. This enables genuine agentic web workflows: research, testing, form automation, monitoring, and more.
Unlike traditional automation frameworks, where you define every step upfront, Playwright MCP lets the agent adapt in real time — handling popups, redirects, and unexpected UI states without you writing fallback logic. The browser becomes a live environment that the AI navigates dynamically, not a script it executes blindly. That shift is what makes it genuinely useful for complex, multi-step tasks that break under rigid automation.
It also means the AI carries full context across steps — it knows what it clicked, what loaded, and what failed — so it can recover from errors the same way a human would. For developers, this removes an entire category of brittle glue code that traditional automation constantly requires.
┌─────────────────────────────────────────────────────────┐
│ AI Client (Claude / Cursor) │
│ │
│ "Fill out the signup form at example.com" │
└───────────────────────┬─────────────────────────────────┘
│ MCP Tool Calls (JSON-RPC / stdio)
┌───────────────────────▼─────────────────────────────────┐
│ Playwright MCP Server │
│ (@playwright/mcp — Node.js process) │
│ │
│ Tool Registry: navigate, click, type, snapshot, ... │
└───────────────────────┬─────────────────────────────────┘
│ Playwright API
┌───────────────────────▼─────────────────────────────────┐
│ Browser Engine (Chromium / Firefox) │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Browser Context (isolated or persistent) │ │
│ │ ┌───────────────────────────────────────────┐ │ │
│ │ │ Page / Tab │ │ │
│ │ └───────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Prerequisites
Before installing, make sure you have:
- Node.js 18+ — Playwright MCP is a Node.js package
- npm or npx — for running the server
- Playwright browser binaries — installed separately (
npx playwright install) - An MCP-compatible AI client (Claude Desktop, Cursor, VS Code Copilot, or OpenAI Codex environment)
Check your Node version:
node --version # Should be 18.x or higher
Install Playwright browser binaries (Chromium by default):
npx playwright install chromium
# Or install all browsers:
npx playwright install
This is the most commonly missed step. If browsers aren't installed, Playwright MCP fails with a cryptic "executable not found" error.
Installation
Playwright MCP is distributed as an npm package. You don't need a global install — npx handles it:
# Run directly (no global install needed)
npx @playwright/mcp@latest
# Or install globally if you prefer
npm install -g @playwright/mcp
For projects where you want to pin a version:
npm install --save-dev @playwright/mcp
Verify it runs:
npx @playwright/mcp --help
You should see a list of available flags including --browser, --headed, --port, and --config.
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
Configuration File
Before diving into client-specific setup, understand the config format. Playwright MCP accepts a JSON config file:
{
"browser": "chromium",
"headless": true,
"viewport": {
"width": 1280,
"height": 720
},
"userDataDir": "/path/to/profile",
"allowedOrigins": ["https://example.com", "https://staging.example.com"],
"blockedOrigins": ["https://ads.example.com"],
"timeout": 30000,
"locale": "en-US",
"timezoneId": "America/New_York",
"ignoreHTTPSErrors": false
}
Pass it with:
npx @playwright/mcp --config ./playwright-mcp.config.json
Key config options explained:
| Option | Default | Purpose |
|---|---|---|
browser | chromium | Browser engine: chromium, firefox, webkit |
headless | true | Run without visible window |
userDataDir | (temp dir) | Persistent profile directory |
allowedOrigins | (all) | Whitelist URLs the agent can visit |
blockedOrigins | (none) | Blacklist URLs |
timeout | 30000 | Default navigation timeout in ms |
ignoreHTTPSErrors | false | Allow invalid certs (dev only) |
viewport | 1280×720 | Browser window dimensions |
Setting Up with Claude Desktop
Claude Desktop reads MCP server configurations from a JSON file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Add Playwright MCP:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser", "chromium",
"--headless"
]
}
}
}
For headed mode (useful for debugging):
{
"mcpServers": {
"playwright-headed": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser", "chromium",
"--headed"
]
}
}
}
With a config file:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--config", "/Users/yourname/.config/playwright-mcp.json"
]
}
}
}
After editing, restart Claude Desktop completely. You'll know it's working when Claude responds to "take a screenshot of google.com" by actually doing it.
Important: The MCP server process is spawned by Claude Desktop on demand and communicates over stdio. There's no separate server process to manage.
Setting Up with Cursor
Cursor supports MCP servers through its settings. Open Settings → MCP (or edit .cursor/mcp.json in your project root for project-scoped config):
Global config (~/.cursor/mcp.json):
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"],
"env": {
"PLAYWRIGHT_BROWSERS_PATH": "/home/user/.cache/ms-playwright"
}
}
}
}
Project-scoped (.cursor/mcp.json at project root — useful for team projects):
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--config", "./.playwright-mcp.json"
]
}
}
}
With Cursor, Playwright MCP is most useful in Agent mode. You can instruct it to:
- Test your local dev server at
localhost:3000 - Scrape reference data from documentation sites
- Verify that a UI change actually renders correctly
- Run through a checkout flow on a staging environment
Cursor's AI can directly see tool results and iterate — asking for a snapshot, identifying a broken element, fixing the code, and verifying the fix all in one session.
Setting Up with OpenAI Codex
OpenAI Codex (the API-based coding agent) can use MCP servers when deployed in environments that support MCP. If you're using Codex through an orchestration framework that supports MCP (like LangChain with MCP adapters, or direct API usage with tool calling):
import subprocess
import json
# Launch Playwright MCP as a subprocess
server_process = subprocess.Popen(
["npx", "@playwright/mcp@latest", "--headless"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# JSON-RPC over stdio
def call_mcp_tool(process, tool_name: str, params: dict) -> dict:
request = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": params
}
}
message = json.dumps(request) + "\n"
process.stdin.write(message.encode())
process.stdin.flush()
response_line = process.stdout.readline()
return json.loads(response_line)
# Navigate to a page
result = call_mcp_tool(server_process, "browser_navigate", {
"url": "https://example.com"
})
For production Codex-based agents, use an MCP client library rather than raw subprocess communication.
Setting Up with GitHub Copilot (VS Code)
VS Code with GitHub Copilot Chat supports MCP servers in Agent mode. Configure via .vscode/mcp.json:
{
"servers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": ["@playwright/mcp@latest", "--headless"]
}
}
}
Or in VS Code's settings.json:
{
"mcp": {
"servers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
}
In VS Code Copilot's chat panel, switch to Agent mode and Playwright tools become available. This is particularly powerful for test-driven workflows: write a failing test, ask Copilot to fix the implementation, then verify with a browser screenshot — all in the editor.
Accessibility Snapshots: The Right Way for AI to See Pages
This is the most important concept in Playwright MCP that most tutorials gloss over.
When an AI agent needs to understand a webpage, it has two options:
- Screenshot — Take an image, pass it to a vision model
- Accessibility Snapshot — Get the structured accessibility tree as text
Playwright MCP defaults to accessibility snapshots, and this is deliberate. Here's why it matters:
Screenshot Approach:
Page → PNG image → Vision model → "I see a button labeled Submit"
✗ Uses vision tokens (expensive)
✗ Resolution-dependent
✗ Misses aria-labels, roles, interactive states
✗ Can't identify element selectors
Accessibility Snapshot:
Page → Accessibility Tree → Structured text → Direct element reference
✓ Token-efficient
✓ Resolution-independent
✓ Exposes roles, labels, states, relationships
✓ AI can reference elements by stable identifiers
A snapshot looks like this (what the AI actually receives):
browser_snapshot result:
- document [role=document]
- navigation [role=navigation]
- link "Home" [href=/]
- link "Products" [href=/products]
- link "Sign In" [href=/signin]
- main [role=main]
- heading "Welcome to Example" [level=1]
- paragraph "Your trusted platform for..."
- button "Get Started" [focused=false, disabled=false]
- form [role=form, label="Contact"]
- textbox "Email address" [required=true, value=""]
- textbox "Message" [required=true, value=""]
- button "Send" [type=submit]
The AI can now say: "click the 'Get Started' button" or "type into the 'Email address' textbox" — and Playwright MCP translates that into a precise selector match without needing coordinates.
Take a snapshot via the tool:
browser_snapshot → returns accessibility tree
browser_screenshot → returns base64 PNG (use when visual verification matters)
For most automation tasks, browser_snapshot should be your primary tool. Use browser_screenshot only when you need to visually verify rendering, catch CSS bugs, or deal with canvas-based UIs that don't have meaningful accessibility trees.
Headless vs. Headed Mode
| Mode | Flag | Use Case | Limitation |
|---|---|---|---|
| Headless | --headless (default) | CI/CD, production automation, background tasks | Can't load extensions, some anti-bot systems detect it |
| Headed | --headed | Debugging, development, extension testing | Requires display server, not suitable for servers without GUI |
| Headless with virtual display | Xvfb + --headed | CI on Linux with display emulation | More complex setup |
For headless on a Linux server without a display:
# Default headless - just works
npx @playwright/mcp --headless
# Headed with Xvfb (for extension testing in CI)
Xvfb :99 -screen 0 1280x720x24 &
export DISPLAY=:99
npx @playwright/mcp --headed
In production: always run headless unless you have a specific reason not to. Headed mode uses more memory (the GPU process, compositor, etc.) and requires OS-level display infrastructure.
Persistent Sessions
By default, Playwright MCP creates a fresh browser context for each server start — no cookies, no storage, no history. This is the isolated session mode.
Persistent sessions maintain state across sessions using a userDataDir:
{
"browser": "chromium",
"headless": true,
"userDataDir": "/home/user/.playwright-mcp-profile"
}
Or via CLI:
npx @playwright/mcp --user-data-dir /home/user/.playwright-mcp-profile
What gets persisted:
- Cookies and session tokens
- localStorage and sessionStorage values
- IndexedDB data
- Browser preferences
- Service worker registrations
Production workflow for authenticated sessions:
# Step 1: Run headed to log in manually
npx @playwright/mcp --headed --user-data-dir ./auth-profile
# Use Claude/Cursor to navigate to your app and log in
# Close the session when done
# Step 2: Future sessions automatically use saved auth
npx @playwright/mcp --headless --user-data-dir ./auth-profile
# Agent is already logged in
Security note: treat userDataDir like a password file. It contains session tokens. If your userDataDir is compromised, an attacker has access to every site the session is authenticated with. Store it outside your project directory, restrict file permissions to 700, and never commit it to version control.
Isolated Sessions
For security-sensitive workflows or parallel automation, isolated sessions are preferable:
{
"browser": "chromium",
"headless": true
// No userDataDir — new ephemeral context every time
}
Isolated sessions are ideal for:
- Processing untrusted URLs (web scraping from arbitrary sources)
- Test automation where clean state is required
- Multi-tenant systems where sessions must not bleed between users
- Any workflow where you don't want credentials cached
For parallel isolated sessions, run multiple server instances on different ports (if using SSE transport) or as separate stdio processes:
# Instance 1 - SSE on port 8931
npx @playwright/mcp --port 8931 --headless &
# Instance 2 - SSE on port 8932
npx @playwright/mcp --port 8932 --headless &
Browser Extensions
Playwright MCP supports loading Chrome extensions into Chromium. This requires:
- Headed mode OR persistent context
- Extension path pointing to unpacked extension directory
{
"browser": "chromium",
"headless": false,
"userDataDir": "./extension-profile",
"extensionPaths": ["/path/to/unpacked/extension"]
}
Or via CLI:
npx @playwright/mcp \
--headed \
--user-data-dir ./ext-profile \
--extension-path /path/to/extension
Common use cases for extensions:
- Password managers — maintain authenticated state through extension-based auth
- Ad blockers — cleaner pages for content extraction
- Custom network interceptors — for testing specific network conditions
- Internal tooling extensions — automating enterprise SaaS with companion extensions
Firefox/WebKit limitation: Extensions only work in Chromium. If you need Firefox or WebKit, you can't use browser extensions.
Docker Deployment
Running Playwright MCP in Docker is the cleanest approach for production — isolated OS, pinned dependencies, no conflicts with system Playwright installations.
Dockerfile:
FROM mcr.microsoft.com/playwright:v1.49.0-noble
# Set working directory
WORKDIR /app
# Install Playwright MCP
RUN npm install @playwright/mcp@latest
# Copy config
COPY playwright-mcp.config.json ./
# Expose port for SSE transport (optional)
EXPOSE 8931
# Run the MCP server
CMD ["node", "node_modules/.bin/playwright-mcp", \
"--config", "./playwright-mcp.config.json", \
"--port", "8931"]
playwright-mcp.config.json:
{
"browser": "chromium",
"headless": true,
"allowedOrigins": ["https://your-target-site.com"],
"timeout": 30000,
"viewport": {
"width": 1280,
"height": 720
}
}
docker-compose.yml:
version: '3.8'
services:
playwright-mcp:
build: .
ports:
- "8931:8931"
volumes:
- playwright-sessions:/app/sessions
environment:
- NODE_ENV=production
restart: unless-stopped
# Security: limit capabilities
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
# Memory limit (browsers are hungry)
mem_limit: 2g
volumes:
playwright-sessions:
Build and run:
docker build -t playwright-mcp .
docker-compose up -d
The Microsoft Playwright Docker image (mcr.microsoft.com/playwright) includes all browser binaries and system dependencies pre-installed. This avoids the painful apt-get install libgbm-dev libxshmfence-dev... dependency dance.
Docker networking note: When Playwright MCP runs in Docker and needs to access a local dev server on your host machine, use host.docker.internal instead of localhost in your URLs.
Security Hardening
Playwright MCP gives an AI agent a real browser. A real browser can visit any URL, execute JavaScript, access local resources, and interact with any authenticated service. This power requires deliberate security controls.
Origin Allowlisting
The single most important security control — restrict which URLs the agent can visit:
{
"allowedOrigins": [
"https://app.yourcompany.com",
"https://staging.yourcompany.com",
"http://localhost:3000"
]
}
With allowedOrigins set, attempts to navigate to URLs outside the whitelist fail immediately. This prevents prompt injection attacks where a malicious page tries to redirect the agent to an attacker-controlled site.
Blocking Dangerous Origins
{
"blockedOrigins": [
"https://webhook.site",
"https://requestbin.com"
]
}
Never Expose MCP Over Public Networks
MCP servers using SSE transport listen on a port. Never expose this port directly to the internet without authentication. If you need remote access:
# Nginx reverse proxy with basic auth
server {
listen 443 ssl;
server_name mcp.internal.yourcompany.com;
location / {
auth_basic "MCP Server";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://localhost:8931;
proxy_set_header Connection '';
proxy_http_version 1.1;
proxy_buffering off;
}
}
For production deployments at scale, see running MCP in production for patterns around authentication, monitoring, and zero-downtime operations.
JavaScript Execution Caution
The browser_evaluate tool can execute arbitrary JavaScript in the page context. In agentic workflows, be aware that a compromised or malicious page could craft content designed to trick the AI into executing harmful JS. Mitigations:
- Use
allowedOriginsto restrict which pages the agent visits - Don't give agents access to
browser_evaluateunless the workflow genuinely requires it - Log all
browser_evaluatecalls in production
Credential Hygiene
# Lock down persistent profile directory
chmod 700 /path/to/userDataDir
# Never store userDataDir inside your project repo
echo ".playwright-profile/" >> .gitignore
# Use environment variables for profile paths
npx @playwright/mcp --user-data-dir $PLAYWRIGHT_PROFILE_PATH
Real Automation Workflows
Workflow 1: Automated Form Testing
A QA agent verifies a signup form on every deploy:
Agent instruction: "Navigate to https://staging.app.com/signup.
Fill in the name field with 'Test User',
email with 'test@example.com',
password with 'SecurePass123!'.
Click the signup button and verify the success message appears."
Playwright MCP tool sequence:
browser_navigate→https://staging.app.com/signupbrowser_snapshot→ identify form fieldsbrowser_type→ fill each fieldbrowser_click→ submit buttonbrowser_snapshot→ verify success statebrowser_screenshot→ capture evidence
Workflow 2: Competitive Research Agent
# Agent task: "Collect pricing from competitor sites"
# Playwright MCP handles the browser interactions
instructions = """
Visit https://competitor-a.com/pricing
Extract all plan names and prices from the pricing table
Then visit https://competitor-b.com/pricing
Extract the same data
Return a comparison as JSON
"""
With allowedOrigins set to only the competitor domains, this stays scoped.
Workflow 3: CI/CD Visual Regression
In a GitHub Actions workflow:
name: Visual Regression Tests
on: [push]
jobs:
visual-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Playwright browsers
run: npx playwright install chromium
- name: Start dev server
run: npm run dev &
- name: Run AI visual test agent
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
node scripts/visual-test-agent.js
// scripts/visual-test-agent.js
import Anthropic from '@anthropic-ai/sdk';
import { spawn } from 'child_process';
// Launch Playwright MCP
const mcpServer = spawn('npx', ['@playwright/mcp@latest', '--headless']);
// Use Claude to drive visual tests via MCP
const client = new Anthropic();
const result = await client.messages.create({
model: 'claude-opus-4-5',
max_tokens: 4096,
messages: [{
role: 'user',
content: `Visit http://localhost:3000 and verify:
1. The hero section heading is visible
2. Navigation links are all present
3. Take a screenshot as evidence
Report PASS or FAIL with details.`
}]
// MCP integration wired via SDK's MCP client support
});
Testing Strategies
Playwright MCP complements, not replaces, traditional Playwright test scripts. Here's how to think about when to use each:
| Scenario | Use Playwright MCP | Use Raw Playwright |
|---|---|---|
| Exploratory testing / QA checks | ✓ | |
| One-off automation tasks | ✓ | |
| Stable regression test suite | ✓ | |
| Performance benchmarking | ✓ | |
| CI/CD deterministic tests | ✓ | |
| Dynamic UI investigation | ✓ | |
| Generating test scripts from interaction | ✓ |
A powerful workflow: use Playwright MCP to explore a UI and generate Playwright test code, then commit that code to your test suite. The AI handles discovery; the generated script handles repeatability.
Ask Claude: "Explore the signup flow at localhost:3000 and generate a Playwright test script that covers the happy path and the validation error case for an invalid email."
Performance Considerations
Memory: Each Chromium instance uses ~150–400MB RAM. Firefox uses slightly less. For high-volume automation, consider:
{
"browser": "chromium",
"headless": true,
"args": [
"--disable-dev-shm-usage",
"--disable-gpu",
"--no-sandbox"
]
}
Concurrency: Playwright MCP handles one task at a time per server instance. For parallel workloads, spawn multiple instances. A load balancer or orchestration layer routes requests.
Startup time: Browser cold start takes 1–3 seconds. For latency-sensitive workflows, keep the MCP server running rather than spawning it per request.
Snapshot vs. screenshot performance:
browser_snapshot→ typically 50–200msbrowser_screenshot→ 200–500ms (image encoding overhead)
Use snapshots by default. Reserve screenshots for moments when visual evidence is genuinely required.
Timeouts: The default navigation timeout is 30 seconds. For slow target sites, increase it. For fast internal apps, reduce it to fail faster:
{
"timeout": 10000
}
Troubleshooting Common Problems
"Browser executable not found"
Cause: Playwright browser binaries not installed.
Fix:
npx playwright install chromium
# Or if you installed @playwright/mcp globally:
playwright install chromium
MCP Server Doesn't Appear in Claude/Cursor
Cause: JSON syntax error in config file, wrong file path, or client not restarted.
Fix:
# Validate JSON syntax
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python3 -m json.tool
# Fix any errors, then fully quit and restart Claude Desktop
"Navigation timeout exceeded"
Cause: Target page is slow or network is unreliable.
Fix: Increase timeout in config:
{ "timeout": 60000 }
Or investigate if the URL is actually reachable from the MCP server's network context.
Agent Can't Find Elements
Cause: Page uses iframes, shadow DOM, or canvas — these aren't fully represented in the accessibility tree.
Fix: Use browser_screenshot to visually inspect the page. For iframes, the MCP server may need explicit frame switching support depending on version. Check the official changelog for frame handling updates.
"Access denied" or "Origin not allowed"
Cause: allowedOrigins is set and the URL doesn't match.
Fix: Add the origin to the allowlist in your config. Remember that origins include protocol + domain + port (e.g., http://localhost:3000 is different from http://localhost).
High Memory Usage
Cause: Browser context not being properly closed between tasks, or too many tabs open.
Fix: Configure the agent to explicitly close tabs after tasks. In Docker, set mem_limit. Add --disable-dev-shm-usage to Chromium args if running in containers with limited /dev/shm.
Extension Not Loading
Cause: Running in headless mode (default) or using Firefox/WebKit.
Fix: Switch to Chromium in headed mode with a persistent userDataDir.
Verifying Your Playwright MCP Server
Before trusting any MCP server in a production workflow, verify it exposes the tools it claims to, behaves correctly under error conditions, and doesn't have configuration issues.
MCPForge's verification tool lets you point at an MCP server and automatically enumerate its tools, test basic connectivity, and flag common misconfigurations. For Playwright MCP specifically, this confirms your tool list matches what you configured and that snapshot/screenshot tools respond correctly.
If you've built a custom wrapper around Playwright MCP — adding auth middleware, custom tools, or domain-specific behaviors — listing it in the MCPForge verified directory helps other teams discover and trust it.
Recent Protocol and Ecosystem Updates
As of late 2024 and into 2025, several important changes affect Playwright MCP deployments:
MCP 1.0 Specification stabilization: The core JSON-RPC protocol, tool discovery handshake, and capability negotiation patterns are now stable. If you're running Playwright MCP built against pre-1.0 MCP drafts, upgrade — there are breaking changes in error codes and capability advertisement.
Playwright 1.49+ changes: Recent Playwright versions improved accessibility tree fidelity for ARIA patterns and fixed edge cases in shadow DOM traversal. If your snapshots were missing elements, upgrading Playwright (and reinstalling browser binaries with npx playwright install) often fixes it.
@playwright/mcp SSE transport: The server-sent events transport mode is now production-stable, enabling remote connections without stdio. This makes centralized deployment (one MCP server, multiple AI clients) viable.
Vision mode improvements: The package now supports explicit --vision mode where the AI works primarily from screenshots rather than accessibility trees. This is useful for canvas-heavy apps (maps, design tools, games) but uses significantly more tokens.
Production Checklist
Before deploying Playwright MCP in any production or team environment:
- Playwright browser binaries installed and version-pinned
-
allowedOriginsconfigured to restrict navigable URLs -
headless: trueunless headed is explicitly required -
userDataDirset to a secure, non-repo path withchmod 700 - MCP server not exposed on public ports without authentication
- Docker image uses Microsoft's official Playwright base image
- Memory limits set on container (
mem_limit: 2gminimum) - Timeouts configured for your target environment's latency
-
ignoreHTTPSErrors: false(nevertruein production) - Server logs captured and monitored
- MCP server config validated through MCPForge Verify
- Tested with
browser_snapshotbeforebrowser_screenshotfor efficiency -
.playwright-profile/in.gitignore
Key Takeaways
Playwright MCP makes browser automation a first-class capability for AI agents — but it's not magic. The tools are only as reliable as your configuration, your allowed origins, and your understanding of how accessibility snapshots work.
Start with isolated sessions and allowedOrigins. Add persistent sessions only when your workflow genuinely needs stored auth. Run in Docker for any production deployment. And prefer browser_snapshot over browser_screenshot until you have a reason to reach for the visual approach.
The accessibility-first design isn't an arbitrary choice — it's what makes AI-driven browser automation reliable at scale. An agent that reads the accessibility tree will be more consistent than one that interprets screenshots, because the tree doesn't vary with viewport size, font rendering, or OS theme.
For teams running multiple MCP servers across different workflows, the patterns in running MCP in production cover the orchestration, monitoring, and zero-downtime deployment concerns that come with serious adoption.