Playwright MCP Server
Enables browser automation through the MCP protocol, allowing AI agents to control a real browser using accessibility snapshots and natural language commands.
README
Playwright MCP Server — POC with 100+ Test Cases
VentureDive QA Engineering Prepared by: Raheel Imran Date: May 2026
Overview
This Proof of Concept (POC) demonstrates the Playwright MCP Server (@playwright/mcp) used as the browser automation engine for a complete test suite. It includes:
- A fully functional demo web application — TaskMaster Pro
- 166 Playwright test cases across 8 feature areas using reusable MCP-style commands
- A
cmdfixture that maps directly to@playwright/mcptool names - A live MCP server demo that connects via
@modelcontextprotocol/sdkand drives the browser using real MCP protocol — no external API calls - MCP server configuration for Claude Desktop and Claude Code
- An interactive HTML test report
Architecture
┌──────────────────────────────────────────────────────────────┐
│ Playwright MCP POC │
│ │
│ ┌───────────────────┐ MCP Protocol ┌────────────────┐ │
│ │ MCP Client │◄─────────────────►│ @playwright/mcp│ │
│ │ (run-demo.ts) │ stdio transport │ Server │ │
│ └───────────────────┘ └───────┬────────┘ │
│ │ │
│ Playwright Browser │
│ │ │
│ ┌────────▼─────────┐ │
│ │ TaskMaster Pro │ │
│ │ localhost:3000 │ │
│ └──────────────────┘ │
│ │
│ Playwright Test Runner (166 tests) │
│ └── tests/fixtures/browser-commands.ts ← reusable cmd │
│ ├── auth.spec.ts (25 tests) │
│ ├── navigation.spec.ts (20 tests) │
│ ├── dashboard.spec.ts (12 tests) │
│ ├── tasks.spec.ts (45 tests) │
│ ├── categories.spec.ts (14 tests) │
│ ├── profile.spec.ts (17 tests) │
│ ├── settings.spec.ts (17 tests) │
│ └── ui-components.spec.ts (16 tests) │
└──────────────────────────────────────────────────────────────┘
Quick Start
1. Install dependencies
npm install
npx playwright install chromium
2. Start the demo app
npm run dev
# → http://localhost:3000
3. Run all tests and generate HTML report
npm test
npm run test:report # opens playwright-report/index.html
4. Run the MCP server demo (browser driven via MCP protocol)
npm run demo
# Starts @playwright/mcp server, connects as MCP client, runs 10 scenarios
5. Interactive test runner
npm run test:ui
npm Scripts
| Script | Description |
|---|---|
npm run dev |
Start the TaskMaster Pro demo app on port 3000 |
npm test |
Run all 100+ tests (Chromium + Firefox) |
npm run test:ui |
Open Playwright interactive UI mode |
npm run test:report |
Open generated HTML report |
npm run test:headed |
Run tests in headed browser |
npm run test:debug |
Run tests with Playwright debugger |
npm run demo |
Run the MCP server demo (real MCP protocol) |
npm run mcp:start |
Start @playwright/mcp standalone server |
Reusable Browser Commands
All tests import from tests/fixtures/browser-commands.ts instead of @playwright/test directly.
Command names match @playwright/mcp tool names exactly, making the test code portable to any MCP client.
import { test, expect } from './fixtures/browser-commands';
test('example', async ({ cmd }) => {
await cmd.browser_navigate('/login.html');
await cmd.browser_type('email-input', 'testuser@test.com');
await cmd.browser_type('password-input', 'Test@123');
await cmd.browser_click('login-btn');
await cmd.browser_expect_url(/dashboard/);
await cmd.browser_take_screenshot('login-success.png');
});
Full command reference
| Command | MCP Tool | Description |
|---|---|---|
cmd.browser_navigate(url) |
browser_navigate |
Navigate to URL |
cmd.browser_navigate_back() |
browser_navigate_back |
Go back in history |
cmd.browser_click(testId) |
browser_click |
Click element by data-testid |
cmd.browser_type(testId, text) |
browser_type |
Fill input field |
cmd.browser_clear_and_type(testId, text) |
browser_type |
Clear then fill |
cmd.browser_select_option(testId, value) |
browser_select_option |
Select dropdown option |
cmd.browser_check(testId) |
browser_click |
Check a checkbox |
cmd.browser_uncheck(testId) |
browser_click |
Uncheck a checkbox |
cmd.browser_take_screenshot(filename?) |
browser_take_screenshot |
Capture screenshot |
cmd.browser_get_url() |
— | Get current URL |
cmd.browser_get_text(testId) |
— | Get element text |
cmd.browser_get_value(testId) |
— | Get input value |
cmd.browser_is_visible(testId) |
browser_snapshot |
Returns boolean |
cmd.browser_is_checked(testId) |
browser_snapshot |
Returns boolean |
cmd.browser_count(testId) |
browser_snapshot |
Count elements |
cmd.browser_wait_for(testId, state?) |
browser_wait_for |
Wait for element |
cmd.browser_wait_for_url(pattern) |
— | Wait for URL |
cmd.browser_set_storage(key, value) |
— (fixture-only) | Set localStorage via page.evaluate |
cmd.browser_evaluate(fn) |
— (fixture-only) | Run JS via page.evaluate |
cmd.browser_expect_url(pattern) |
— | Assert current URL |
cmd.browser_expect_visible(testId) |
— | Assert visible |
cmd.browser_expect_hidden(testId) |
— | Assert hidden |
cmd.browser_expect_text(testId, text) |
— | Assert text content |
cmd.browser_expect_count(testId, n) |
— | Assert element count |
cmd.browser_expect_value(testId, val) |
— | Assert input value |
cmd.browser_expect_checked(testId) |
— | Assert checkbox state |
cmd.browser_expect_disabled(testId) |
— | Assert disabled |
cmd.browser_expect_attr(testId, attr, val) |
— | Assert attribute |
Demo App — TaskMaster Pro
A fully self-contained web app using localStorage for all data persistence.
| Page | URL | Features |
|---|---|---|
| Login | /login.html |
Form validation, password toggle, remember-me |
| Register | /register.html |
Password strength, validation |
| Dashboard | /dashboard.html |
Stats, recent tasks, quick-add |
| Tasks | /tasks.html |
CRUD, filter, search, sort, bulk actions |
| Categories | /tasks.html#categories |
Create, edit, delete categories |
| Profile | /profile.html |
Edit name, avatar, change password |
| Settings | /settings.html |
Theme, notifications, language, export |
| 404 | /404.html |
Error page |
Default test credentials:
| Password | Role | |
|---|---|---|
testuser@test.com |
Test@123 |
Test User |
admin@test.com |
Admin@123 |
Admin User |
Pre-seeded data: 5 tasks (3 active, 2 completed) and 4 categories.
MCP Tools provided by @playwright/mcp
See the full categorized reference in MCP Server Setup → Available MCP tools below. Key tools used in this demo app:
| Tool | Description |
|---|---|
browser_navigate |
Navigate to a URL |
browser_snapshot |
Get accessibility tree — returns ARIA refs for click/type targets |
browser_click |
Click an element by ARIA ref |
browser_type |
Type text into a focused field |
browser_fill_form |
Fill multiple form fields in one call |
browser_select_option |
Select a dropdown value |
browser_take_screenshot |
Capture the current page as an image |
browser_localstorage_set |
Write a localStorage key (used for fast auth seeding) |
browser_evaluate |
Evaluate JavaScript on the page |
browser_wait_for |
Wait for an element or condition |
browser_network_requests |
Inspect captured network traffic |
browser_route |
Mock API responses for isolated testing |
browser_tabs |
List, open, close, or switch tabs |
browser_close |
Close the browser |
MCP Server Setup
@playwright/mcp exposes browser automation as MCP tools so any MCP-compatible client (Claude Code, Claude Desktop, VS Code, Cursor, Windsurf) can drive a real browser with no screenshots or vision models — just accessibility snapshots.
Claude Code (project-level)
A .mcp.json file is included at the project root. Claude Code picks it up automatically when you open this directory:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
Or install it manually via the CLI:
claude mcp add playwright npx @playwright/mcp@latest
Claude Desktop
Add the following to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
VS Code
One-liner via the VS Code CLI:
code --add-mcp '{"name":"playwright","command":"npx","args":["@playwright/mcp@latest"]}'
Or use the included .vscode/mcp.json — VS Code with the Copilot extension picks it up automatically:
{
"servers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
Cursor / Windsurf
Add the same block under mcpServers in their respective settings files.
Configuration options
Append flags to the args array to customise the server:
| Flag | Effect |
|---|---|
--headless |
Run browser without a visible window (default: headed) |
--browser <browser> |
Browser to use: chrome, firefox, webkit, msedge (default: Chromium) |
--isolated |
Keep browser profile in memory; do not persist to disk |
--port <n> |
Expose the server over HTTP/SSE instead of stdio |
--host <host> |
Host to bind to (default: localhost; use 0.0.0.0 for all interfaces) |
--vision |
Use screenshots instead of accessibility snapshots (requires vision model) |
--caps <caps> |
Comma-separated capability subset: tabs,pdf,history,wait,files,install |
--device <device> |
Emulate a device, e.g. "iPhone 15" |
--viewport-size <size> |
Set viewport, e.g. "1280, 720" |
--user-agent <ua> |
Override the browser user-agent string |
--storage-state <path> |
Load saved auth state (cookies/localStorage) from a JSON file |
--save-trace |
Save a Playwright Trace of the session to --output-dir |
--output-dir <path> |
Directory for screenshots, PDFs, and traces |
--proxy-server <proxy> |
Route traffic through a proxy, e.g. http://myproxy:3128 |
--no-sandbox |
Disable the browser sandbox (useful in some CI environments) |
--extension |
Connect to an existing browser tab instead of launching a new browser |
--config <path> |
Load advanced settings from a JSON config file |
Example — headless Firefox in isolated mode:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--headless", "--browser=firefox", "--isolated"]
}
}
}
Standalone server (HTTP transport)
For headless/CI environments where stdio is not suitable:
npx @playwright/mcp@latest --port 8931
Then point your MCP client at http://localhost:8931/mcp using the url form:
{
"mcpServers": {
"playwright": {
"url": "http://localhost:8931/mcp"
}
}
}
Available MCP tools
Navigation
| Tool | Description |
|---|---|
browser_navigate |
Navigate to a URL |
browser_navigate_back / browser_navigate_forward |
Browser history navigation |
browser_reload |
Reload the current page |
Interaction
| Tool | Description |
|---|---|
browser_click |
Click an element by ARIA ref |
browser_check / browser_uncheck |
Check or uncheck a checkbox |
browser_type |
Type text into a focused field |
browser_press_sequentially |
Type text one character at a time (for masked fields) |
browser_fill_form |
Fill multiple form fields by their labels in one call |
browser_select_option |
Select a dropdown value |
browser_hover |
Hover over an element |
browser_drag / browser_drop |
Drag-and-drop between elements |
browser_press_key / browser_keydown / browser_keyup |
Keyboard key events |
browser_handle_dialog |
Accept or dismiss browser dialogs |
browser_file_upload |
Upload a file to a file input |
browser_mouse_click_xy / browser_mouse_move_xy / browser_mouse_drag_xy |
Pixel-precise mouse control |
browser_mouse_down / browser_mouse_up / browser_mouse_wheel |
Low-level mouse events |
Inspection & Assertions
| Tool | Description |
|---|---|
browser_snapshot |
Get the page accessibility tree — primary way to read elements and obtain ARIA refs |
browser_take_screenshot |
Capture the current page as an image |
browser_annotate |
Capture a screenshot with annotated highlights |
browser_highlight / browser_hide_highlight |
Visually highlight an element on the page |
browser_generate_locator |
Generate a Playwright locator for a given element |
browser_verify_element_visible |
Assert an element is visible |
browser_verify_text_visible |
Assert specific text is visible on the page |
browser_verify_list_visible |
Assert a list of items is visible |
browser_verify_value |
Assert an element's value |
browser_wait_for |
Wait for an element or network condition |
Storage
| Tool | Description |
|---|---|
browser_evaluate |
Evaluate a JavaScript expression on the page |
browser_localstorage_get / browser_localstorage_set / browser_localstorage_list |
Read/write localStorage |
browser_localstorage_clear / browser_localstorage_delete |
Remove localStorage items |
browser_sessionstorage_get / browser_sessionstorage_set / browser_sessionstorage_list |
sessionStorage CRUD |
browser_sessionstorage_clear / browser_sessionstorage_delete |
Remove sessionStorage items |
browser_cookie_get / browser_cookie_set / browser_cookie_list |
Read/write cookies |
browser_cookie_clear / browser_cookie_delete |
Remove cookies |
browser_storage_state |
Export current cookies and storage to a file |
browser_set_storage_state |
Import previously saved storage state |
Network
| Tool | Description |
|---|---|
browser_network_requests |
List all captured network requests |
browser_network_request |
Get details for a single network request |
browser_network_clear |
Clear the captured request log |
browser_network_state_set |
Simulate online/offline/throttled network conditions |
browser_route |
Mock requests matching a URL pattern with a custom response |
browser_route_list |
List active route mocks |
browser_unroute |
Remove a route mock |
Tabs
| Tool | Description |
|---|---|
browser_tabs |
List, create (new), close, or switch to a tab by index |
Console
| Tool | Description |
|---|---|
browser_console_messages |
Get browser console output |
browser_console_clear |
Clear the console message log |
Recording & Tracing
| Tool | Description |
|---|---|
browser_start_tracing / browser_stop_tracing |
Record a Playwright Trace |
browser_start_video / browser_stop_video / browser_video_chapter |
Record session video |
browser_pdf_save |
Save the current page as a PDF |
Misc
| Tool | Description |
|---|---|
browser_resize |
Resize the browser window |
browser_get_config |
Get the current server configuration |
browser_run_code_unsafe |
Execute an arbitrary Playwright script (RCE-equivalent; trusted clients only) |
browser_close |
Close the browser |
How accessibility snapshots work: Instead of returning a screenshot,
browser_snapshotreturns a structured text tree of all visible elements with their roles, labels, and unique[ref=…]identifiers. LLMs reference these ids when callingbrowser_clickorbrowser_type— no vision model required.
Verify the server is working
# Start the demo app first
npm run dev
# Then run the MCP demo (connects via stdio and runs 10 browser scenarios)
npm run demo
MCP Demo (demo/)
demo/run-demo.ts connects to @playwright/mcp via real MCP stdio protocol using @modelcontextprotocol/sdk. It runs 10 browser scenarios with no external API dependencies.
npm run demo
╔══════════════════════════════════════════════════════════╗
║ Playwright MCP Server — Direct MCP Protocol Demo ║
╚══════════════════════════════════════════════════════════╝
Target: http://localhost:3000
Transport: stdio (@playwright/mcp subprocess)
Connecting to @playwright/mcp server…
Connected.
Available MCP tools (14):
• browser_navigate
• browser_snapshot
• browser_click
…
S01 ✓ PASS Login page loads via MCP browser_navigate
S02 ✓ PASS Fill login form using browser_type
S03 ✓ PASS Capture login page screenshot
…
Test Coverage
| Area | Tests | TC Range |
|---|---|---|
| Authentication | 25 | TC001–TC025 |
| Navigation | 20 | TC026–TC045 |
| Dashboard | 12 | TC046–TC057 |
| Task Management | 45 | TC058–TC102 |
| Categories | 14 | TC103–TC116 |
| Profile | 17 | TC117–TC133 |
| Settings | 17 | TC134–TC150 |
| UI Components | 16 | TC151–TC166 |
| Total | 166 |
Project Structure
.
├── demo-app/
│ ├── server.js Express static file server (port 3000)
│ └── public/
│ ├── index.html Entry point (redirect)
│ ├── login.html
│ ├── register.html
│ ├── dashboard.html
│ ├── tasks.html Tasks + Categories
│ ├── profile.html
│ ├── settings.html
│ ├── 404.html
│ ├── css/styles.css
│ └── js/utils.js Shared helpers + seed data
├── tests/
│ ├── fixtures/
│ │ └── browser-commands.ts Reusable MCP-style command fixture
│ ├── helpers/
│ │ └── auth.helper.ts Fast localStorage-based auth setup
│ ├── auth.spec.ts TC001–TC025
│ ├── navigation.spec.ts TC026–TC045
│ ├── dashboard.spec.ts TC046–TC057
│ ├── tasks.spec.ts TC058–TC102
│ ├── categories.spec.ts TC103–TC116
│ ├── profile.spec.ts TC117–TC133
│ ├── settings.spec.ts TC134–TC150
│ └── ui-components.spec.ts TC151–TC166
├── demo/
│ ├── scenarios.ts 10 MCP test scenario definitions
│ └── run-demo.ts MCP client demo (real MCP protocol)
├── playwright-report/ Generated HTML report (after npm test)
├── playwright.config.ts
├── package.json
└── tsconfig.json
Key Design Decisions
| Decision | Rationale |
|---|---|
data-testid attributes on all elements |
Tests don't break when CSS or text changes |
Reusable browser-commands.ts fixture |
Command names match @playwright/mcp tools — tests are portable |
loginViaStorage() helper |
Sets session via localStorage.setItem directly — 10× faster than UI login |
Sequential workers (workers: 1) |
Prevents localStorage conflicts between parallel tests |
retries: 1 locally, retries: 2 on CI |
Handles transient timing issues without masking real failures |
| No external API dependencies | MCP demo uses @playwright/mcp directly via stdio protocol |
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。