KEEP IT HANDS-ON functional ✓ tested 2026-06-29
// sandboxed in macOS (host) · aarch64 ·install log ·functional log

Playwright MCP

by Microsoft Corporation · https://github.com/microsoft/playwright-mcp · Apache-2.0 · v0.0.76 · updated 2026-06-25

The canonical browser-driving MCP server, verified end-to-end against live pages with codegen and an accessibility-tree model that needs no vision.

5 / 5
quality 5/5
documentation 5/5
setup 5/5
value 5/5
ecosystem fit 5/5
// bottom line

Playwright MCP is the reference implementation for browser automation over MCP, maintained by Microsoft and downloaded 5 million times a week. The accessibility-snapshot approach is deterministic and token-cheap, the tool surface is honestly labeled (including an explicit RCE warning on the unsafe tool), and every action returns reusable Playwright TypeScript. The only real caveats are a still-0.0.x version number that pins against Playwright alpha builds and a headed-by-default mode that bites you on headless servers.

install via npx
$npx @playwright/mcp@latest
install via Claude Code
$claude mcp add playwright npx @playwright/mcp@latest
install via Codex
$codex mcp add playwright npx "@playwright/mcp@latest"

install if

  • Any agent or assistant that needs to read or interact with web pages. The accessibility-snapshot model works without a vision model and returns structured data an LLM can act on directly.
  • Developers building exploratory automation or self-healing test scripts. The codegen output turns an interactive session into a runnable Playwright file you can check into a repo.
  • Teams that want a single browser tool across many clients. One config block works in VS Code, Cursor, Claude Code, Claude Desktop, Codex, Copilot CLI, Cline, Goose, Windsurf, Gemini CLI, and a dozen other clients, all documented in the README.
  • Pipeline authors who need network mocking, storage inspection, or PDF export from an agent. The opt-in capability flags expose 45 additional tools beyond the 23-tool core.

What It Does

Playwright MCP is a Model Context Protocol server that exposes Playwright browser automation to LLMs. An agent connects to it over stdio or HTTP, calls tools like browser_navigate, browser_snapshot, and browser_click, and drives a real browser. The distinctive design choice is that it operates on Playwright's accessibility tree rather than screenshots: instead of asking a vision model to find a button in a pixel grid, it returns a structured YAML snapshot of the page where every interactive element has a stable reference (such as ref=e3) the agent cites back in its next action. The default core capability set ships 23 tools, and opt-in capability flags raise that to 68 tools spanning storage manipulation, network mocking, PDF generation, coordinate-based vision interactions, trace and video recording, and test assertions. The audience is any agent, coding assistant, or automation pipeline that needs to read or act on web pages, and the package is published by Microsoft as @playwright/mcp on npm.

The Good

The accessibility-snapshot model is deterministic and needs no vision model. I navigated to https://example.com and called browser_snapshot. The server returned a YAML tree starting with - generic [ref=e2]: containing - heading "Example Domain" [level=1] [ref=e3], the two paragraphs of body copy, and - link "Learn more" [ref=e6] with its URL. Every element carries a ref the agent passes back to browser_click or browser_type. There is no screenshot classification step, no coordinate guessing, and no dependency on a multimodal model. This is the core reason the package works with text-only clients like Claude Desktop and Gemini CLI.

Every tool call returns the equivalent Playwright TypeScript code, for free. When I called browser_navigate with the example.com URL, the response included a code block: await page.goto('https://example.com');. When I called browser_evaluate with () => document.title, the response showed await page.evaluate('() => document.title'); alongside the result "Example Domain". This codegen feature means a session of poking at the MCP server doubles as a way to produce a reusable, runnable Playwright script. No competing browser MCP I have reviewed ships this.

The tool surface is honestly labeled, including an explicit RCE warning. The tools/list response annotates every tool with a readOnlyHint: 31 tools are marked read-only (snapshots, screenshots, network logs, cookie and storage reads, assertions), and 37 are write (navigation, clicks, form fills, evaluation). The one dangerous tool, browser_run_code_unsafe, describes itself verbatim as "Unsafe: executes arbitrary JavaScript in the Playwright server process and is RCE-equivalent." That kind of blunt, in-band warning is what lets a client gate the tool before exposing it to an autonomous agent.

The install and test story is clean. npx @playwright/mcp@latest --version printed Version 0.0.76 on the first run with no manual browser step. The full JSON-RPC handshake (initialize, notifications/initialized, tools/list) completed against a server started with node cli.js --headless. The repo's own integration suite ran 8 of 8 tests green in 3.2 seconds, covering navigate, click, the capabilities switch, the snapshot tool list, legacy option parsing, and CommonJS library import. There are tagged releases going back through v0.0.74, v0.0.75, and v0.0.76.

The documentation tells you when not to use it. The README opens with a side-by-side comparison of the MCP server versus the Playwright CLI plus SKILLS approach, and recommends the CLI for high-throughput coding agents because CLI invocations are more token-efficient than loading large tool schemas and verbose accessibility trees. A project that explains its own limitations in the first section is signaling editorial honesty, not marketing.

The Bad

The version is still 0.0.x and the dependency is pinned to a Playwright alpha build. package.json lists playwright and playwright-core at 1.61.0-alpha-1781023400000. The MCP source lives in the upstream microsoft/playwright monorepo and this repo rolls it forward on alpha builds via node roll.js. For most users this is invisible because npx @playwright/mcp@latest resolves the right version, but anyone pinning a version in production is pinning against an alpha-tagged Playwright, and the 0.0.x semver means breaking changes to the tool surface are not gated by a major bump.

Headed mode is the default, which fails silently on headless servers. Out of the box the server launches a visible browser window. On a CI runner, a Docker container, or any environment without a display, the first browser_navigate call will fail unless you passed --headless. This is documented in the options table, but it is the single most common first-run failure for server deployments, and making headless the default (or auto-detecting a missing display) would remove the footgun.

The repo is a publishing wrapper, not a self-contained codebase. The src/ directory contains only a README.md. The real TypeScript source for all 68 tools lives at microsoft/playwright under packages/playwright-core/src/tools/, and the CONTRIBUTING.md directs contributors to clone the monorepo. Reading cli.js shows a bundled file. This is good architecture (single source of truth, no duplication), but a developer who clones playwright-mcp expecting to read or modify the tool implementations will find nothing to edit.

browser_run_code_unsafe ships in the default core tool set. The tool is honestly named and described, but it is enabled with no capability flag required. A client that connects and blindly exposes all tools to an autonomous agent is handing it arbitrary code execution in the server process. There is no built-in tool allowlist or default-deny posture; the burden is entirely on the client to filter. The Security section of the README says "Playwright MCP is not a security boundary," which is correct, but a safer default would exclude the unsafe tool unless explicitly opted in.

The full 68-tool surface requires discovering the --caps flags. The default tools/list returns 23 core tools. The remaining 45 tools (storage, network mocking, PDF, vision coordinates, devtools tracing, test assertions) are gated behind --caps=storage,network,pdf,vision,devtools,testing,config, and the README's main configuration table only highlights vision, pdf, and devtools. An agent that needs to mock a network request or read localStorage may not realize those tools exist unless someone reads the collapsed details sections.

Smoke Test Results

Tested on macOS host (aarch64), Node v24.13.1, npm 11.8.0. The repo was shallow-cloned (452 KB) into /tmp/pwmcp-rev, dependencies installed with npm install (97 packages, 1 second), and the Chromium headless shell was installed via npx playwright install chromium (93.4 MB).

Run A. Fresh sandbox, no deps preinstalled

$ cd /tmp && git clone --depth 1 https://github.com/microsoft/playwright-mcp.git pwmcp-rev

PASS (452 KB)

$ cd pwmcp-rev && node cli.js --version

FAIL (Cannot find module 'playwright-core/lib/utilsBundle')

$ cd pwmcp-rev && npm install --no-audit --no-fund

PASS (97 packages, 1s)

$ node cli.js --version

PASS (Version 0.0.76)

Pass rate: 3 of 4. The single failure is expected: the repo ships a prebuilt cli.js that requires playwright-core, which is not vendored and must be installed with npm install. This matches how the package is published (the npm tarball bundles everything, but a git clone does not).

Run B. Sandbox with deps preinstalled

$ node cli.js --headless --browser chromium < handshake-stdin

PASS: initialize returns {name: "Playwright", protocolVersion: "2025-06-18"}

$ tools/list (default, no caps)

PASS: 23 core tools returned

$ tools/list (--caps=vision,pdf,devtools,storage,network,testing,config)

PASS: 68 tools returned, 31 read-only, 37 write

$ npx playwright test --project=chrome --reporter=line

PASS (8 of 8 tests, 3.2s)

Pass rate: 4 of 4. The badge number is 4 of 4. The server handshake is correct, the tool count matches the README, and the integration suite is green.

Run C. Tools respond (functional verification)

$ browser_navigate {url: "https://example.com"}

PASS: returns Page Title "Example Domain" and codegen await page.goto('https://example.com');

$ browser_snapshot {}

PASS: returns YAML accessibility tree with refs e2-e6, heading "Example Domain", body paragraphs, and the iana.org link

$ browser_evaluate {function: "() => document.title"}

PASS: returns "Example Domain"

$ browser_navigate {url: "https://www.wikipedia.org"} then browser_evaluate title

PASS: returns "Wikipedia" (cross-origin navigation works)

$ npx @playwright/mcp@latest --version

PASS: Version 0.0.76 (canonical npm install path works without cloning)

Functional pass rate: 5 of 5. The server drives a real browser against live pages, returns structured snapshots with stable element refs, generates Playwright code for every action, and the published npm package works identically to the git checkout.

What the runs tell you

Playwright MCP installs in one command, passes its own test suite, and was verified end-to-end driving a real Chromium against two live websites. The accessibility-snapshot tool returned structured, ref-stamped page data, and the codegen output means every interactive session also produces a reusable script. The only setup wrinkle is that a raw git clone needs npm install before the CLI runs, which is normal for a package that is meant to be consumed via npm rather than cloned.

Setup Walkthrough

  1. Install for your MCP client. For Claude Code: claude mcp add playwright npx @playwright/mcp@latest. For a generic config file, use {"mcpServers":{"playwright":{"command":"npx","args":["@playwright/mcp@latest"]}}}. No clone or build step is needed.
  2. Pick a browser. The default is the Chrome channel (your installed Google Chrome). For headless or server use, add --headless and optionally --browser chromium to use Playwright's bundled Chromium, which auto-installs on first run.
  3. Enable extra tools only if you need them. Add --caps=pdf,vision,devtools for screenshots-as-images, coordinate clicks, PDF export, and tracing. Add storage, network, testing, or config for cookie and localStorage tools, request mocking, assertion tools, or the resolved-config inspector.
  4. For Docker, run docker run -i --rm --init --pull=always mcr.microsoft.com/playwright/mcp and point your client at it. The image ships headless Chromium only.

Gotcha: the server launches a visible browser by default. On a headless host you must pass --headless or the first navigation will fail with no obvious cause. Gotcha two: a persistent profile can only be used by one browser instance at a time, so concurrent clients need --isolated or distinct --user-data-dir values.

Alternatives

  1. microsoft/playwright-cli (CLI plus SKILLS) - the sibling project Microsoft recommends for coding agents. Same Playwright engine, but exposed as token-efficient CLI commands wrapped in agent skills instead of MCP tool schemas. Prefer it when context budget matters more than persistent browser state.
  2. CursorTouch/Windows-MCP - a computer-use MCP for Windows desktop automation rather than web pages. Use it when you need to drive native applications, not browsers.
  3. A raw Playwright script - if you already know exactly what pages and selectors you need, a hand-written Playwright test is more deterministic and cheaper than an agent session. The MCP server earns its keep when the agent must explore an unknown page structure first.
// review provenance
reviewed by
GearScope
tested
2026-06-29 · macOS (Apple Silicon)
last verified
2026-06-29
depth
HANDS-ON
sponsorship
none, ever
// share this review
// feedback
was this review helpful?

Want the next one?

Five honest reviews and a verdict you can trust. Every Friday. No spam, no affiliate links.