A Model Context Protocol (MCP) proxy for Playwright that adds persistent storage, session management, and optimized response handling.
The proxy consists of two UV-based Python components:
- MCP Client - A stdio MCP server that exposes Playwright tools to upstream clients
- HTTP Server - Manages the Playwright MCP subprocess, handles sessions, and persists data to SQLite
MCP Client --> MCP Client --> HTTP Server --> Playwright MCP
(upstream) (proxy) (FastAPI) (subprocess)
|
v
SQLite
- Persistent Storage: All requests and responses stored in SQLite with UUID references
- Session Management: UUID-based browser sessions that can be created and managed independently
- Optimized Responses: Returns metadata + ref_id instead of full payloads
- Content Retrieval: Get page snapshots and console logs by ref_id
- Diff-Based Content (Phase 2):
get_contentreturns only changes since last read- Hash-based change detection
- Cursor persistence across server restarts
reset_cursorparameter to get full content
- Session Recovery (Phase 7): Sessions survive server restarts
- Automatic state snapshots every 30s (URL, cookies, localStorage, sessionStorage, viewport)
- Orphaned session detection on startup
- Resume sessions with full state restoration
- Classification: recoverable, stale, or closed based on snapshot age
- Subprocess Management: Automatic health monitoring and restart for Playwright MCP
# Install in editable mode with UV
uv pip install -e .
# Or install with dev dependencies
uv pip install -e ".[dev]"Install as a global UV tool - commands will be available system-wide:
# Install from the current directory
uv tool install .
# Or install from a Git repository
uv tool install git+https://github.com/yourusername/playwright-mcp-proxy.git
# Commands are now available globally:
playwright-proxy-server
playwright-proxy-clientTo update later:
uv tool upgrade playwright-mcp-proxyTo uninstall:
uv tool uninstall playwright-mcp-proxyIf you prefer pipx:
# Install with pipx
pipx install .
# Or from Git
pipx install git+https://github.com/yourusername/playwright-mcp-proxy.git
# Commands available globally
playwright-proxy-server
playwright-proxy-client# Install to UV's global Python environment
uv pip install --system .# Using the installed script
playwright-proxy-server
# Or using Python module
python -m playwright_mcp_proxy.serverThe server will:
- Initialize the SQLite database at
./proxy.db - Spawn the Playwright MCP subprocess
- Listen on
http://localhost:34501
Add to your MCP client configuration (e.g., Claude Desktop, VS Code):
If installed globally (uv tool install or pipx):
{
"mcpServers": {
"playwright-proxy": {
"command": "playwright-proxy-client"
}
}
}If using local development install:
{
"mcpServers": {
"playwright-proxy": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/playwright-mcp-proxy",
"playwright-proxy-client"
]
}
}
}Or using the Python module directly:
{
"mcpServers": {
"playwright-proxy": {
"command": "python",
"args": [
"-m",
"playwright_mcp_proxy.client"
]
}
}
}# Create a new browser session
> create_new_session()
Created session: abc-123-def-456
# Navigate and take snapshot
> browser_navigate(url="https://example.com")
Request completed successfully
Ref ID: xyz-789
Page snapshot available. Use get_content('xyz-789')
# Get the page content
> get_content(ref_id="xyz-789")
[Full accessibility tree snapshot]
# Search within content
> get_content(ref_id="xyz-789", search_for="Example Domain")
- heading "Example Domain"
Sessions now survive server restarts! The proxy automatically captures browser state every 30 seconds and can restore sessions after crashes or restarts.
-
Automatic Snapshots: While sessions are active, the server captures:
- Current URL
- Cookies
- localStorage
- sessionStorage
- Viewport size
-
Startup Detection: When the server restarts, it automatically:
- Detects orphaned sessions (marked as "active" before shutdown)
- Classifies them based on snapshot age:
- recoverable: Recent snapshot (< 24h) - safe to resume
- stale: Old snapshot (> 24h) - may not work reliably
- closed: No snapshot available - cannot recover
-
Manual Resume: Users can list and resume sessions via tools
# Before restart - working in a session
> browser_navigate(url="https://example.com")
> browser_type(element="search box", ref="e1", text="test query")
# Server crashes or restarts...
# After restart - resume your session
> list_sessions(state="recoverable")
Session ID: abc-123-def-456
State: recoverable
URL: https://example.com
Snapshot age: 45 seconds
> resume_session(session_id="abc-123-def-456")
✓ Session resumed successfully
Restored URL: https://example.com
# Your browser is back at the same page with all state restored!
You can also use the HTTP endpoints directly:
# List recoverable sessions
curl http://localhost:34501/sessions?state=recoverable
# Resume a session
curl -X POST http://localhost:34501/sessions/abc-123-def-456/resumeSESSION_SNAPSHOT_INTERVAL: How often to snapshot (default: 30s)MAX_SESSION_AGE: Max age for recoverable sessions (default: 24h)MAX_SESSION_SNAPSHOTS: How many snapshots to keep (default: 10)AUTO_REHYDRATE: Auto-resume sessions on startup (default: false)
- Cookies captured via
document.cookie(no httpOnly/secure flags) - Cannot capture JavaScript heap, running timers, or pending requests
- Some sites may break if only storage is restored without full context
- Viewport size captured but not currently restored (Playwright limitation)
Configuration via environment variables (prefix: PLAYWRIGHT_PROXY_):
# Server
PLAYWRIGHT_PROXY_SERVER_HOST=localhost
PLAYWRIGHT_PROXY_SERVER_PORT=34501
# Database
PLAYWRIGHT_PROXY_DATABASE_PATH=./proxy.db
# Playwright
PLAYWRIGHT_PROXY_PLAYWRIGHT_BROWSER=chrome # chrome, firefox, webkit
PLAYWRIGHT_PROXY_PLAYWRIGHT_HEADLESS=false
# Subprocess Management
PLAYWRIGHT_PROXY_HEALTH_CHECK_INTERVAL=30
PLAYWRIGHT_PROXY_MAX_RESTART_ATTEMPTS=3
PLAYWRIGHT_PROXY_RESTART_WINDOW=300
PLAYWRIGHT_PROXY_SHUTDOWN_TIMEOUT=5
# Session Recovery (Phase 7)
PLAYWRIGHT_PROXY_SESSION_SNAPSHOT_INTERVAL=30 # Seconds between snapshots
PLAYWRIGHT_PROXY_MAX_SESSION_AGE=86400 # Max age (24h) for recoverable sessions
PLAYWRIGHT_PROXY_AUTO_REHYDRATE=false # Auto-resume sessions on startup
PLAYWRIGHT_PROXY_MAX_SESSION_SNAPSHOTS=10 # Keep last N snapshots per session
# Logging
PLAYWRIGHT_PROXY_LOG_LEVEL=INFOOr create a .env file (see .env.example).
create_new_session()- Create a new browser session, returnssession_idlist_sessions(state?)- List all sessions, optionally filtered by state (Phase 7)resume_session(session_id)- Resume a recoverable/stale session after restart (Phase 7)
get_content(ref_id, search_for?, reset_cursor?)- Get page snapshot from a previous request- Phase 2: Returns only changes since last read (hash-based diff)
- Use
reset_cursor=trueto get full content and reset diff tracking - Empty response means no changes detected
get_console_content(ref_id, level?)- Get console logs (filter by debug/info/warn/error)
All standard Playwright MCP tools are available:
browser_navigate(url)browser_snapshot()browser_click(element, ref)browser_type(element, ref, text, submit?)browser_console_messages(onlyErrors?)browser_close()- ... and more
Responses return metadata + ref_id instead of full content.
- sessions - Browser sessions (UUID, state, timestamps, recovery fields)
- requests - All proxied requests (ref_id, tool, params)
- responses - Full responses as blobs (result, page_snapshot, console_logs)
- console_logs - Normalized console entries (level, message, location)
- diff_cursors - For Phase 2 diff support
- session_snapshots - Phase 7 state snapshots (URL, cookies, storage, viewport)
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=playwright_mcp_proxy
# Run specific test file
uv run pytest tests/test_database.py# Check formatting
uv run ruff check .
# Auto-fix issues
uv run ruff check --fix .# Terminal 1: Start server
uv run playwright-proxy-server
# Terminal 2: Start client (stdio)
uv run playwright-proxy-client
# Terminal 3: Send MCP requests via stdio
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | uv run playwright-proxy-client- Core infrastructure
- SQLite persistence
- HTTP server with session management
- MCP client with tool proxying
- Subprocess lifecycle management
- Basic testing (6 tests)
- Diff-based content retrieval
-
get_contentreturns only changes since last read -
reset_cursorparameter - Hash-based change detection
- Cursor persistence across server restarts
- Comprehensive tests (8 additional tests)
- Session state persistence (URL, cookies, localStorage, sessionStorage, viewport)
- Automatic periodic snapshots every 30s
- Orphaned session detection on startup
- Session classification (recoverable/stale/closed)
- Restart recovery with session rehydration
-
list_sessions(state)tool -
resume_session(session_id)tool - Comprehensive tests (16 tests total)
- Check if port 34501 is available
- Verify Node.js is installed (for Playwright MCP)
- Check logs in console output
- Check
~/.npmhas@playwright/mcp@latestinstalled - Verify browser binaries are installed
- Review stderr logs
- Ensure HTTP server is running on localhost:34501
- Check firewall settings
- Verify configuration in MCP client
MIT
Contributions welcome! Please:
- Follow the existing code style (Ruff)
- Add tests for new features
- Update documentation
- Ensure backward compatibility
Areas for contribution:
- Integration tests for session recovery
- Performance optimizations
- Additional browser state capture (iframe support, web workers, etc.)
- Enhanced rehydration strategies
- Bug fixes and improvements
See CLAUDE.md for architecture details and development patterns.