Playwright MCP Server
Playwright MCP servers enable AI models to perform cross-browser automation, modern web testing, accessibility testing, and end-to-end testing workflows using Playwright's powerful browser automation capabilities.
Overview
The Playwright MCP Server enables AI models to perform browser automation using Microsoft's Playwright framework through the Model Context Protocol. Unlike traditional screenshot-based approaches, it uses structured accessibility snapshots for fast, deterministic, and LLM-friendly browser interactions.
Official & Community Implementations:
Official: Microsoft Playwright MCP - Fast, accessibility-tree based automation
Community: @executeautomation/playwright-mcp-server - Enhanced with code generation and API testing
Key Features
Cross-Browser Testing
Test across Chromium, Firefox, WebKit, and Microsoft Edge browsers
Accessibility-First
Uses structured accessibility trees instead of pixel-based input
Fast & Lightweight
No vision models needed, operates on structured data
Test Code Generation
Record actions and generate Playwright test scripts automatically
Available Tools
Quick Reference
Official server (Microsoft)
| Tool | Purpose |
|---|---|
browser_navigate | Navigate to a URL |
browser_snapshot | Capture an accessibility snapshot of the current page |
browser_click | Perform a click on a web page |
browser_type | Type text into an editable element |
browser_fill_form | Fill multiple form fields |
browser_evaluate | Evaluate a JavaScript expression on the page or an element |
browser_run_code_unsafe | Run a Playwright code snippet (RCE-equivalent) |
browser_take_screenshot | Take a screenshot of the current page |
browser_wait_for | Wait for text to appear or disappear, or a specified time to pass |
browser_tabs | List, create, close, or select a browser tab |
browser_console_messages | Return all console messages |
browser_network_requests | Return a numbered list of network requests since loading the page |
browser_file_upload | Upload one or multiple files |
browser_find | Search the accessibility snapshot for text or a regular expression |
Community server (Execute Automation)
| Tool | Purpose | Category |
|---|---|---|
playwright_navigate | Navigate to URL | Navigation |
playwright_click | Click elements | Interaction |
playwright_fill | Fill input fields | Forms |
playwright_select | Select dropdown options | Forms |
playwright_screenshot | Capture screenshots | Testing |
playwright_evaluate | Execute JavaScript | Scripting |
playwright_hover | Hover over elements | Interaction |
playwright_press_key | Press keyboard keys | Interaction |
playwright_drag | Drag and drop elements | Interaction |
playwright_upload_file | Upload files | Forms |
playwright_get_visible_text | Extract visible text | Content |
playwright_get_visible_html | Get page HTML | Content |
playwright_console_logs | Retrieve console logs | Debugging |
playwright_expect_response | Monitor HTTP responses | API Testing |
start_codegen_session | Start test recording | Code Gen |
end_codegen_session | Generate test file | Code Gen |
Detailed Usage
Community server tool names:
The examples in this section use the Execute Automation community server's playwright_* tool names. The official Microsoft server exposes the browser_* tools listed in Quick Reference above.
playwright_navigateβΆ
Navigate to a URL with configurable browser and viewport options.
// Basic navigation
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com"
}
});
// Navigate with specific browser
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com",
browserType: "firefox" // chromium, firefox, webkit, msedge
}
});
// Navigate with custom viewport
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com",
width: 1920,
height: 1080,
headless: false
}
});
Returns navigation status and page load confirmation.
playwright_clickβΆ
Click elements on the page using CSS selectors.
// Single click
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: "button.submit"
}
});
// Double click
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: ".expandable-item",
doubleClick: true
}
});
// Click and switch to new tab
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click_and_switch_tab",
arguments: {
selector: "a[target='_blank']"
}
});
// Click inside iframe
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_iframe_click",
arguments: {
iframeSelector: "#payment-iframe",
selector: "button.pay-now"
}
});
Returns click confirmation and element state.
playwright_screenshotβΆ
Capture screenshots of pages or specific elements.
// Viewport screenshot
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "homepage-view"
}
});
// Full page screenshot
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "full-page",
fullPage: true
}
});
// Element screenshot
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "header",
selector: "header.main-nav"
}
});
// Save as PNG file
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "dashboard",
savePng: true,
downloadsDir: "./screenshots"
}
});
Returns screenshot data or file path.
playwright_fillβΆ
Fill input fields, textareas, and contenteditable elements.
// Fill text input
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_fill",
arguments: {
selector: "input[name='email']",
value: "[email protected]"
}
});
// Fill password field
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_fill",
arguments: {
selector: "input[type='password']",
value: "SecurePass123!"
}
});
// Fill inside iframe
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_iframe_fill",
arguments: {
iframeSelector: "#contact-form-iframe",
selector: "textarea#message",
value: "Hello, this is a test message"
}
});
Clears existing value before filling.
playwright_selectβΆ
Select options from dropdown menus.
// Select by value
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_select",
arguments: {
selector: "select[name='country']",
value: "US"
}
});
// Select by label
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_select",
arguments: {
selector: "select#language",
value: "English"
}
});
Returns selected option value.
playwright_evaluateβΆ
Execute JavaScript code in the browser context.
// Get page title
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_evaluate",
arguments: {
script: "document.title"
}
});
// Extract data
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_evaluate",
arguments: {
script: `
Array.from(document.querySelectorAll('.product'))
.map(p => ({
name: p.querySelector('.name').textContent,
price: p.querySelector('.price').textContent
}))
`
}
});
// Modify page
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_evaluate",
arguments: {
script: `
document.querySelector('.modal').style.display = 'none';
return 'Modal hidden';
`
}
});
Returns the result of the JavaScript expression.
playwright_upload_fileβΆ
Upload files to file input elements.
// Single file upload
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_upload_file",
arguments: {
selector: "input[type='file']",
filePath: "/path/to/document.pdf"
}
});
// Multiple file upload
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_upload_file",
arguments: {
selector: "input[type='file'][multiple]",
filePath: [
"/path/to/image1.jpg",
"/path/to/image2.jpg"
]
}
});
Returns upload confirmation.
playwright_get_visible_textβΆ
Extract all visible text from the page (excludes hidden elements).
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_get_visible_text",
arguments: {}
});
Returns plain text content visible to users.
playwright_get_visible_htmlβΆ
Retrieve page HTML with filtering and cleaning options.
// Get clean HTML
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_get_visible_html",
arguments: {
removeScripts: true,
removeComments: true,
cleanHtml: true
}
});
// Get minified HTML
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_get_visible_html",
arguments: {
minify: true
}
});
Returns filtered HTML source code.
playwright_console_logsβΆ
Retrieve browser console logs with filtering options.
// Get all console logs
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_console_logs",
arguments: {}
});
// Search for specific logs
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_console_logs",
arguments: {
search: "error",
type: "error"
}
});
// Get limited logs and clear
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_console_logs",
arguments: {
limit: 50,
clear: true
}
});
Returns array of console messages with types and timestamps.
start_codegen_sessionβΆ
Start recording browser actions to generate Playwright test scripts.
use_mcp_tool({
server_name: "playwright",
tool_name: "start_codegen_session",
arguments: {
outputPath: "./tests",
testNamePrefix: "user-login",
includeComments: true
}
});
Returns session ID for tracking the recording.
end_codegen_sessionβΆ
Finalize recording and generate test file.
use_mcp_tool({
server_name: "playwright",
tool_name: "end_codegen_session",
arguments: {
sessionId: "session-123abc"
}
});
Returns generated test file path and content.
playwright_expect_responseβΆ
Monitor and validate HTTP responses during browser interactions.
// Monitor API endpoint
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_expect_response",
arguments: {
id: "api-check-1",
url: "https://api.example.com/users"
}
});
// Assert response value
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_assert_response",
arguments: {
id: "api-check-1",
url: "https://api.example.com/users",
value: { status: 200 }
}
});
Returns response data including status, headers, and body.
Installation
Microsoft Playwright MCP
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
With Browser Selection:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser", "firefox"
]
}
}
}
With Custom Configuration:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser", "chrome",
"--viewport-size", "1280x720",
"--user-data-dir", "./playwright-data"
]
}
}
}
Persistent Browser Profile:
Use --user-data-dir to persist login sessions and cookies across runs.
Configuration Options
Browser Selection
--browser <browser> # chrome, firefox, webkit, msedge
Viewport Configuration
--viewport-size <size> # e.g. "1280x720"
Device Emulation
--device <device> # For example: "iPhone 15"
Network Settings
--allowed-origins <origins> # Semicolon-separated trusted origins
--blocked-origins <origins> # Semicolon-separated blocked origins
--proxy-server <url> # Use proxy server
Session Management
--user-data-dir <path> # Persistent browser profile
--isolated # Ephemeral sessions
--storage-state <file> # Load cookies/localStorage
Recording & Debugging
--save-session # Save the session into the output directory
--timeout-action <ms> # Action timeout, default 5000
--timeout-navigation <ms> # Navigation timeout, default 60000
--timeout-settle <ms> # Settle wait after each action, default 500
Trace and video recording:
Trace and video recording are tools rather than CLI flags (--caps=devtools): browser_start_tracing / browser_stop_tracing and browser_start_video / browser_stop_video.
Common Use Cases
Community server tool names:
The examples in this section use the Execute Automation community server's playwright_* tool names.
1. End-to-End Testing
Automate complete user workflows:
// Navigate to login page
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://app.example.com/login"
}
});
// Fill credentials
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_fill",
arguments: {
selector: "input[name='email']",
value: "[email protected]"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_fill",
arguments: {
selector: "input[name='password']",
value: "TestPass123!"
}
});
// Submit form
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: "button[type='submit']"
}
});
// Verify login success
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "dashboard-logged-in",
fullPage: true
}
});
2. Cross-Browser Testing
Test across multiple browsers:
// Test in Chromium
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com",
browserType: "chromium"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "chromium-homepage"
}
});
// Test in Firefox
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com",
browserType: "firefox"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "firefox-homepage"
}
});
// Test in WebKit (Safari)
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com",
browserType: "webkit"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "webkit-homepage"
}
});
3. Test Code Generation
Record actions and generate test scripts:
// Start recording
use_mcp_tool({
server_name: "playwright",
tool_name: "start_codegen_session",
arguments: {
outputPath: "./tests",
testNamePrefix: "checkout-flow",
includeComments: true
}
});
// Perform actions (automatically recorded)
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://shop.example.com"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: ".add-to-cart"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: ".checkout-button"
}
});
// Generate test file
use_mcp_tool({
server_name: "playwright",
tool_name: "end_codegen_session",
arguments: {
sessionId: "session-123"
}
});
4. API Testing During Browser Interactions
Monitor network requests and validate responses:
// Navigate to page
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com/dashboard"
}
});
// Monitor API call
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_expect_response",
arguments: {
id: "user-api",
url: "https://api.example.com/users/me"
}
});
// Trigger action that makes API call
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_click",
arguments: {
selector: ".refresh-data"
}
});
// Assert API response
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_assert_response",
arguments: {
id: "user-api",
value: { status: 200 }
}
});
5. Visual Regression Testing
Capture screenshots for visual comparison:
// Baseline screenshot
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_navigate",
arguments: {
url: "https://example.com"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "baseline-homepage",
fullPage: true,
savePng: true,
downloadsDir: "./screenshots/baseline"
}
});
// Component screenshots
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "header",
selector: "header",
savePng: true,
downloadsDir: "./screenshots/components"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_screenshot",
arguments: {
name: "footer",
selector: "footer",
savePng: true,
downloadsDir: "./screenshots/components"
}
});
6. Accessibility Testing
Test keyboard navigation and screen reader compatibility:
// Navigate using keyboard
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_press_key",
arguments: {
key: "Tab"
}
});
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_press_key",
arguments: {
key: "Enter"
}
});
// Extract accessibility tree
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_evaluate",
arguments: {
script: `
const snapshot = await window.accessibility.snapshot();
return snapshot;
`
}
});
// Check for accessibility violations
use_mcp_tool({
server_name: "playwright",
tool_name: "playwright_console_logs",
arguments: {
search: "accessibility",
type: "warning"
}
});
Beyond testing: a signed-in browser as a general-purpose MCP
Most write-ups treat Playwright MCP as a testing tool. In daily use with several coding agents, it ended up doing more. Sign in to a web service once, and the agent can work with that service the same way you do. You don't need an MCP server, API key or OAuth app for each service.
How it works. By default, Playwright MCP keeps a persistent browser profile. Logins, cookies and site settings carry over from one session to the next. Sign in by hand once, change any one-time settings, and the agent picks up where you left off.
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--user-data-dir", "~/.mcp-browser-profile"]
}
}
}
Patterns that held up in practice
1. Read data from pages you already have open.
browser_evaluate runs JavaScript on the page, so you can pull out the content as structured JSON instead of a full snapshot. Some sites' terms forbid calling their unpublished internal endpoints, even from a page where you're signed in. Check the terms before making fetch() calls beyond what the page itself loads.
2. Extract structured data instead of reading snapshots. Return only the fields you need:
() => [...document.querySelectorAll('article')].map(a => ({
title: a.querySelector('h2')?.textContent?.trim(),
link: a.querySelector('a')?.href
}))
3. Run several steps in one call.
browser_run_code_unsafe runs a Playwright function with page. A loop with waits, scrolling and downloads becomes one tool call instead of twenty clicks, each with its own snapshot.
async (page) => {
const results = [];
for (let i = 0; i < 5; i++) {
await page.mouse.wheel(0, 2000);
await page.waitForTimeout(800);
results.push(await page.locator('article').count());
}
return results;
}
4. Drive web apps that have no API.
Use browser_file_upload, browser_fill_form and browser_type to put work in, browser_wait_for while it runs, and then an evaluate call to collect the result.
5. Check your own dev servers.
Open the page on localhost, then read browser_console_messages and browser_network_requests and take a screenshot. That catches errors that unit tests don't.
What we learned the hard way
- In real use, most calls ran scripts.
browser_evaluateandbrowser_run_code_unsafemade up about half of all calls; clicks and typing were a small share. - One profile can only be open in one browser at a time. Agents running at once can't share a signed-in profile. Give each its own
--user-data-dir, or use--isolated, which doesn't keep your logins. --isolatedmeans you're signed out. That's good for testing, but this whole approach depends on being signed in.- Scripts against the page break without an error. When a site changes its markup,
querySelectorAllreturns an empty list instead of failing. Return counts, and treat an empty result as an error. - The agent can do anything you can do on those sites.
browser_run_code_unsafeis, in the README's own words, "RCE-equivalent." A page that injects instructions into the agent's context can trigger actions with your logins. Keep the profile limited to services you're willing to give the agent. - Prefer small evaluate results over full snapshots. A short JSON result costs far fewer tokens than an accessibility snapshot of the same page.
Stay within the terms of service
Many web services ban automated access in their terms, even when it's your own account doing it. If they catch it, you can lose the account, not just get rate-limited. Before you point an agent at a service:
- Read the terms first. Look for "automated means," "scraping," "bots" or "unofficial clients." If the terms forbid it, don't automate that service.
- Use the official API or MCP when there is one. Use the browser only where no supported route exists.
- Keep it to your own account and your own data. Don't collect other users' data in bulk, and don't share a signed-in profile with other people.
- Work at human pace and volume. Leave delays between actions, keep sessions short, and don't run anything around the clock. If something would take a person hours of clicking, it's probably too much.
- Don't get around protections. If you hit a CAPTCHA, a rate limit, a "suspicious activity" warning or a block, stop. Don't solve or bypass it with automation.
- Leave paid limits and access controls alone. Don't use automation to exceed usage caps, unlock paid features or reach content you couldn't open by hand.
- Don't automate account-level actions. Sign up, sign in, change security settings and complete any verification yourself.
- Watch for warnings. An email about unusual activity, a forced logout or a new verification step means stop and back off.
Browser Support
| Browser | Engine | Platforms | Mobile |
|---|---|---|---|
| Chromium | Blink | Windows, macOS, Linux | β |
| Firefox | Gecko | Windows, macOS, Linux | β |
| WebKit | WebKit | macOS, Linux | β |
| Microsoft Edge | Blink | Windows, macOS, Linux | β |
Best Practices
- Use Accessibility Selectors: Leverage
role,aria-label, andtextselectors for robust tests - Wait for Elements: Playwright auto-waits, but explicit waits improve reliability
- Isolate Tests: Use
--isolatedmode to prevent state leakage between tests - Record Traces: Enable tracing for debugging failed tests
- Test Across Browsers: Run tests on Chromium, Firefox, and WebKit
- Screenshot on Failure: Capture screenshots when assertions fail
- Monitor Console: Check console logs for JavaScript errors
- Use Code Generation: Record complex flows to generate test code
Performance Tips
- Headless Mode: Use headless browsers for faster test execution
- Parallel Execution: Run tests in parallel across multiple browsers
- Reuse Browser Context: Share browser context across tests when possible
- Disable Resources: Block images/fonts for faster page loads in tests
- Set Timeouts: Configure appropriate timeouts for different operations
- Cache User Data: Use persistent profiles to avoid repeated logins
Troubleshooting
Common Issues
Issue: Browser fails to launch
- Install Playwright browsers:
npx playwright install - Check system dependencies:
npx playwright install-deps - Verify Node.js version (18+ required)
Issue: Elements not found
- Wait for element to be visible
- Check selector syntax (CSS, text, role-based)
- Verify element isn't in iframe or shadow DOM
Issue: Screenshots are blank
- Ensure page has loaded completely
- Check viewport size is appropriate
- Verify element selector is correct
Issue: Timeouts occurring
- Increase timeout with
--timeout-actionor--timeout-navigation - Check network connectivity
- Verify page isn't stuck loading resources
Issue: Cross-browser differences
- Test on actual target browsers
- Use browser-specific selectors if needed
- Check for browser-specific CSS/JS issues
Security Considerations
Security Warning:
Playwright can execute arbitrary JavaScript and access local files. Only use with trusted URLs and scripts.
Security Best Practices
- Validate URLs: Only navigate to trusted, verified URLs
- Sanitize Inputs: Validate all user-provided selectors and scripts
- Use Isolated Mode: Enable
--isolatedfor untrusted content - Don't Rely on Origin Filters:
--allowed-origins/--blocked-originsonly filter browser requests; per the README they are not a security boundary and do not affect redirects - Review Scripts: Audit JavaScript executed via
evaluate - Secure Storage: Protect session storage and cookie files
- Container Isolation: Run in Docker for additional security
Limitations
- Docker: Only supports headless Chromium in containers
- File Uploads: Requires local file system access
- Browser Extensions: Limited support for extensions
- WebRTC: May have issues with real-time communication
- Download Handling: Requires configuration for file downloads
- iOS Safari: No direct iOS Safari testing (use WebKit as proxy)
Resources
- Official Playwright Documentation
- Playwright MCP GitHub
- Execute Automation MCP Docs
- Playwright Test Generator
- Accessibility Testing Guide
- Browser Contexts & Pages
Sources
Related Articles & Guides
Accessibility Scanner MCP Server
Accessibility Scanner MCP servers enable AI models to perform WCAG compliance checks, capture annotated screenshots, and generate detailed accessibility reports.
Auth0 MCP Server
Auth0 MCP server enables AI models to interact with Auth0 identity and access management, including applications, APIs, actions, logs, and forms.
AWS MCP Server
Interact with Amazon Web Services through your AI assistant using the AWS API MCP Server.