Playwright Mcp Server Poc With Plus 100 Tc — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Playwright Mcp Server Poc With Plus 100 Tc (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
VentureDive QA Engineering Prepared by: Raheel Imran Date: May 2026
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:
cmd fixture that maps directly to @playwright/mcp tool names@modelcontextprotocol/sdk and drives the browser using real MCP protocol — no external API calls┌──────────────────────────────────────────────────────────────┐
│ 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) │
└──────────────────────────────────────────────────────────────┘npm install
npx playwright install chromiumnpm run dev
# → http://localhost:3000npm test
npm run test:report # opens playwright-report/index.htmlnpm run demo
# Starts @playwright/mcp server, connects as MCP client, runs 10 scenariosnpm run test:ui| 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 |
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', '[email protected]');
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');
});| 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 |
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 | |
|---|---|---|
[email protected] | Test@123 | Test User |
[email protected] | Admin@123 | Admin User |
Pre-seeded data: 5 tasks (3 active, 2 completed) and 4 categories.
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 |
@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.
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@latestAdd 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"]
}
}
}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"]
}
}
}Add the same block under mcpServers in their respective settings files.
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"]
}
}
}For headless/CI environments where stdio is not suitable:
npx @playwright/mcp@latest --port 8931Then point your MCP client at http://localhost:8931/mcp using the url form:
{
"mcpServers": {
"playwright": {
"url": "http://localhost:8931/mcp"
}
}
}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.
# Start the demo app first
npm run dev
# Then run the MCP demo (connects via stdio and runs 10 browser scenarios)
npm run demodemo/)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
…| 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 |
.
├── 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| 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 |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.