Playwright MCP
Playwright MCP brings Microsoft Playwright’s powerful browser automation capabilities to AI agents through the Model Context Protocol. Unlike screenshot-based approaches, it uses structured accessibility trees for fast, deterministic web interactions.
Philosophy
Why Accessibility Trees?
Traditional vision-based approaches have limitations:
- Token Heavy: Large screenshots consume context
- Ambiguous: Visual targeting can be unreliable
- Vision Required: Need vision-capable models
Playwright MCP solves these by:
- Structured Data: Accessibility tree instead of pixels
- Lightweight: Compact representations
- Deterministic: Precise element targeting
- No Vision Needed: Works with any LLM
MCP vs CLI+Skills
Playwright offers both MCP and CLI approaches:
| Aspect | MCP | CLI + Skills |
|---|---|---|
| State | Persistent sessions | Ephemeral invocations |
| Introspection | Rich tree access | Command-based |
| Best For | Exploratory, self-healing tests | High-throughput coding |
| Token Efficiency | Moderate | Higher (no tree loading) |
| Use Cases | Autonomous workflows | Quick automations |
Core Features
1. Structured Automation
Work with accessibility snapshots:
- Page Snapshots: Complete DOM accessibility tree
- Element References: Precise targeting via refs
- Semantic Understanding: Role-based element identification
2. Multi-Browser Support
| Browser | Support | Notes |
|---|---|---|
| Chromium | Full | Primary, most reliable |
| Firefox | Full | Good alternative |
| WebKit | Full | Safari testing |
| Chrome | Via CDP | Remote connection |
| Edge | Via CDP | Remote connection |
3. Rich Tool Set
Core Automation (15+ tools)
- Navigation: `browser_navigate`, `browser_navigate_back`
- Interaction: `browser_click`, `browser_type`, `browser_hover`
- Forms: `browser_fill_form`, `browser_select_option`
- Advanced: `browser_evaluate`, `browser_drag`, `browser_file_upload`
Browser Management
- `browser_close` - Close browser
- `browser_tabs` - Manage tabs
- `browser_resize` - Resize viewport
Debugging & Analysis
- `browser_snapshot` - Accessibility tree
- `browser_take_screenshot` - Visual capture
- `browser_console_messages` - Console logs
- `browser_network_requests` - Network inspection
4. Advanced Capabilities
Optional Features (via `—caps`)
- Vision: Coordinate-based mouse operations
- PDF: Generate and manipulate PDFs
- DevTools: Developer tools access
- Testing: Test assertions and locators
Installation
Standard Install
```json { “mcpServers”: { “playwright”: { “command”: “npx”, “args”: [“@playwright/mcp@latest”] } } } ```
Claude Code
```bash claude mcp add playwright npx @playwright/mcp@latest ```
Cursor
Click install or add manually:
- Settings → MCP → Add MCP Server
- Command: `npx @playwright/mcp@latest`
VS Code
```bash code —add-mcp ’{“name”:“playwright”,“command”:“npx”,“args”:[“@playwright/mcp@latest”]}’ ```
Docker
```json { “mcpServers”: { “playwright”: { “command”: “docker”, “args”: [“run”, “-i”, “—rm”, “—init”, “—pull=always”, “mcr.microsoft.com/playwright/mcp”] } } } ```
Configuration
Basic Options
| Option | Description | Default |
|---|---|---|
| `—browser` | Browser type | chromium |
| `—headless` | Run headless | false |
| `—viewport-size` | Viewport dimensions | 1280x720 |
| `—device` | Emulate device | None |
Browser Options
```json { “browser”: { “browserName”: “chromium”, “isolated”: false, “userDataDir”: ”~/.cache/ms-playwright/mcp-profile”, “launchOptions”: { “headless”: false, “channel”: “chromium” } } } ```
Network Configuration
```json { “network”: { “allowedOrigins”: [“https://trusted.com”], “blockedOrigins”: [“https://malicious.com”] }, “proxyServer”: “http://myproxy:8080” } ```
Advanced Options
| Option | Description |
|---|---|
| `—isolated` | In-memory profile, no disk save |
| `—storage-state` | Load cookies/storage from file |
| `—user-data-dir` | Persistent profile location |
| `—extension` | Connect to browser extension |
| `—cdp-endpoint` | Connect to existing browser |
Configuration File
Use a JSON config file for complex setups:
```bash npx @playwright/mcp@latest —config path/to/config.json ```
```json { “browser”: { “browserName”: “chromium”, “isolated”: true, “launchOptions”: { “headless”: true }, “contextOptions”: { “viewport”: { “width”: 1280, “height”: 720 } } }, “server”: { “port”: 8931, “host”: “0.0.0.0” }, “capabilities”: [“core”, “vision”, “pdf”], “outputMode”: “file”, “saveTrace”: true } ```
Tools Reference
Core Automation
browser_navigate
Navigate to a URL:
```typescript await browser_navigate({ url: “https://example.com” }); ```
browser_click
Click on an element:
```typescript await browser_click({ ref: “button-ref-123”, element: “Submit button”, doubleClick: false, modifiers: [“Control”] }); ```
browser_type
Type text into an input:
```typescript await browser_type({ ref: “input-ref-456”, element: “Email input”, text: “user@example.com”, submit: true, slowly: false }); ```
browser_fill_form
Fill multiple fields:
```typescript await browser_fill_form({ fields: [ { name: “email”, value: “user@example.com” }, { name: “password”, value: “secret123” }, { name: “remember”, value: true } ] }); ```
browser_hover
Hover over an element:
```typescript await browser_hover({ ref: “menu-item-ref”, element: “Account menu” }); ```
browser_drag
Drag and drop:
```typescript await browser_drag({ startRef: “draggable-ref”, startElement: “Source item”, endRef: “dropzone-ref”, endElement: “Target area” }); ```
Navigation & State
browser_navigate_back
Go back in history:
```typescript await browser_navigate_back(); ```
browser_wait_for
Wait for conditions:
```typescript await browser_wait_for({ text: “Success message”, textGone: “Loading…”, time: 30 }); ```
browser_tabs
Manage browser tabs:
```typescript await browser_tabs({ action: “list” | “close” | “select”, index: 0 }); ```
Page Analysis
browser_snapshot
Get accessibility tree:
```typescript const snapshot = await browser_snapshot({ filename: “page-snapshot.md” }); ```
Returns structured data: ```markdown
- button “Submit Form”
- input “Email Address”
- heading “Welcome” ```
browser_take_screenshot
Capture visual state:
```typescript await browser_take_screenshot({ filename: “screenshot.png”, fullPage: true }); ```
Debugging
browser_evaluate
Run JavaScript:
```typescript const result = await browser_evaluate({ function: `() => { return { title: document.title, url: window.location.href, count: document.querySelectorAll(‘.item’).length }; }` }); ```
browser_console_messages
Get console logs:
```typescript const messages = await browser_console_messages({ level: “error”, filename: “console.txt” }); ```
browser_network_requests
Monitor network:
```typescript const requests = await browser_network_requests({ includeStatic: true, filename: “network.log” }); ```
Forms & Dialogs
browser_select_option
Select dropdown option:
```typescript await browser_select_option({ ref: “select-ref”, element: “Country dropdown”, values: [“US”, “CA”, “UK”] }); ```
browser_handle_dialog
Handle alerts/confirms:
```typescript await browser_handle_dialog({ accept: true, promptText: “Enter your name” }); ```
browser_file_upload
Upload files:
```typescript await browser_file_upload({ paths: [“/path/to/file.pdf”] }); ```
Keyboard & Mouse
browser_press_key
Press keyboard keys:
```typescript await browser_press_key({ key: “Enter” }); ```
Supports: key names (ArrowLeft, Tab), characters, combinations.
browser_resize
Resize browser:
```typescript await browser_resize({ width: 1920, height: 1080 }); ```
Advanced Tools
browser_mouse_click_xy (Vision mode)
Coordinate-based clicks:
```typescript await browser_mouse_click_xy({ x: 500, y: 300 }); ```
Requires `—caps=vision`.
browser_pdf_save (PDF mode)
Save page as PDF:
```typescript await browser_pdf_save({ filename: “page.pdf” }); ```
Requires `—caps=pdf`.
User Profiles
Persistent Profile
Default behavior - data saved to disk:
Locations:
- macOS: `~/Library/Caches/ms-playwright/mcp-{channel}-profile`
- Linux: `~/.cache/ms-playwright/mcp-{channel}-profile`
- Windows: `%USERPROFILE%\AppData\Local\ms-playwright\mcp-{channel}-profile`
Isolated Profile
Each session in memory, lost on close:
```json { “mcpServers”: { “playwright”: { “command”: “npx”, “args”: [“@playwright/mcp@latest”, “—isolated”] } } } ```
Browser Extension
Connect to existing browser:
- Install “Playwright MCP Bridge” extension
- Configure with `—extension`
```json { “mcpServers”: { “playwright”: { “command”: “npx”, “args”: [“@playwright/mcp@latest”, “—extension”] } } } ```
Session Management
Save Session
```json { “saveSession”: true, “saveTrace”: true, “saveVideo”: { “width”: 1280, “height”: 720 } } ```
Storage State
Load authenticated state:
```bash npx @playwright/mcp@latest —storage-state=/path/to/auth.json ```
Best Practices
1. Use Accessibility References
Always use refs from snapshots:
```typescript // ❌ Bad: fragile selector await browser_click({ selector: “#submit-btn” });
// ✅ Good: stable reference const snapshot = await browser_snapshot(); await browser_click({ ref: “submit-ref” }); ```
2. Handle Dynamic Content
```typescript // Wait for element before interacting await browser_wait_for({ text: “Loading…” }); await browser_wait_for({ textGone: “Loading…” }); ```
3. Error Recovery
```typescript try { await browser_click({ ref: “button-ref” }); } catch (error) { // Re-snapshot and retry const snapshot = await browser_snapshot(); // Try new ref… } ```
4. Efficient Sessions
- Reuse browser for multiple tasks
- Use `—isolated` for clean tests
- Save/restore state for long workflows
Security
Sandboxing
Playwright MCP runs with sandboxing by default for security.
When sandboxing fails:
- Use `—no-sandbox` (less secure)
- Or connect to external browser
Data Isolation
- Workspaces: Access limited to configured roots
- File Access: Restricted to workspace directories
- Network: Configurable allowed/blocked origins
Secrets Management
Use `—secrets` for sensitive data:
```bash npx @playwright/mcp@latest —secrets=/path/to/.env ```
```env API_KEY=your-key PASSWORD=secret ```
Troubleshooting
Browser Not Found
```bash
Install browsers
npx playwright install
Or install specific browser
npx playwright install chromium ```
Connection Issues
- Check `—port` configuration
- Verify firewall settings
- Use `—console-level=debug` for logs
Slow Performance
- Use `—headless=true` for speed
- Reduce `—snapshot-mode` frequency
- Limit `—image-responses`
Comparison
Playwright MCP vs Chrome DevTools MCP
| Feature | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| Browsers | All (via Playwright) | Chrome/Chromium only |
| Approach | Accessibility tree | Direct protocol |
| Setup | Browser installation | Usually pre-installed |
| Cross-browser | Native | Chrome only |
| Best For | Cross-browser testing | Chrome-specific tasks |
When to Use Each
Use Playwright MCP when:
- Testing across multiple browsers
- Need Safari/WebKit testing
- Prefer Playwright’s API style
- Cross-browser compatibility matters
Use Chrome DevTools MCP when:
- Working exclusively with Chrome
- Need Chrome-specific features (CrUX)
- Chrome already installed
- Simpler setup preferred
Resources
- GitHub: https://github.com/microsoft/playwright-mcp
- Playwright Docs: https://playwright.dev
- MCP Protocol: https://modelcontextprotocol.io
- Playwright CLI+Skills: https://github.com/microsoft/playwright-cli
Summary
Playwright MCP provides AI agents with powerful, reliable browser automation through structured accessibility trees. Its multi-browser support, deterministic interactions, and rich tool set make it ideal for comprehensive web testing and automation scenarios. Whether you need cross-browser compatibility, persistent sessions, or precise element targeting, Playwright MCP offers a robust solution for web automation challenges.