playwright-e2e-mcp
This server gives AI agents a Playwright/pytest test-doctor toolkit for running suites, diagnosing failures, applying verified fixes, and auditing test health.
Run and monitor Playwright/pytest tests, including background runs, filtered/rerun-failed runs, changed-file runs, and progress/status checks.
Diagnose failures deeply using stack traces, expected vs actual, failed requests, console errors, and DOM snapshots at failure.
Suggest, apply, and verify fixes for locators or expected text, reverting edits that still fail and refusing fixes when the element is truly missing.
Load CI reports from/blob reports or GitHub Actions/GitLab job URLs so local diagnosis works on CI failures.
Detect flakiness by rerunning tests, distinguishing races, shared-state issues, and test-order dependencies, with replay seeds.
Analyze run history to rank flaky, broken, slow, and regressed tests and identify the commit where each went bad.
Bisect failures to find the first bad commit in a temporary worktree.
Quarantine flaky tests with owner, reason, and expiry while keeping them reported.
Enforce a heal guard that blocks or warns on fixes that pass by deleting assertions, skipping tests, weakening checks, adding hard waits, or using
.only.Check mocks against live APIs to find drifted fields, changed types, new nulls, or removed endpoints.
Audit test code for flake risks and optionally apply safe mechanical fixes with verification.
Inspect live pages for verified locators, DOM inventory, ARIA snapshots, and selector validation.
Audit accessibility and performance, compare visual state, generate E2E tests, and save authenticated login sessions with 2FA support.
Provides a GitHub Action and ci command that post Playwright test diagnoses, flaky verdicts, and fix diffs to job summaries and pull requests.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@playwright-e2e-mcp run the failing checkout test and fix its broken locator"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
An MCP server and agent skill that gives Claude, Cursor, VS Code Copilot, Codex, Gemini and any other MCP client a full Playwright toolkit: a test runner, a failure detective and a fixer that checks its own work. Browser MCPs let an AI click around a page. This one lets it keep your test suite green, for TypeScript and Python suites, on your laptop and in CI. Free, MIT, no account.
❌ Without it / ✅ With it
Without it, your agent sees Timeout 5000ms exceeded waiting for getByTestId('checkout'),
guesses a new selector, edits the test and hopes. Or it "fixes" the test by deleting the
assertion that caught a real bug.
With it, your agent reads the page as it was when the test failed (from the Playwright trace), swaps in a locator proven unique on that page, re-runs the test and keeps the edit only if it passes. When the button is really gone, it says so: that's an app bug, not a test to patch. And a heal guard blocks any "fix" that went green by checking less.
flowchart LR
A["run-test<br/>or load-report (CI)"] --> B["get-failure<br/>DOM at failure, requests, console"]
B --> C{"suggest-fix"}
C -->|"locator proven on the page"| D["apply + re-run"]
D -->|green| E["✅ fixed and verified"]
D -->|still red| F["↩️ edit reverted"]
C -->|"element really gone"| G["🐞 reported as an app bug"]
D -.-> H["check-test-change<br/>blocks fixes that check less"]Related MCP server: tuxedo-qa
⚡ Quick start
Run this in your project root. It adds the server to every MCP client config it finds (Claude Code, Cursor, VS Code, Gemini CLI, Codex), installs the agent skill and leaves your other servers alone:
npx -y playwright-e2e-mcp init # --client all | cursor,vscode … · --dry-run
npx -y playwright-e2e-mcp doctor # checks Node, Playwright, browsers, client setup and updatesThen restart your client and ask:
Run my Playwright tests and fix whatever fails.Or let your agent install it. Paste this into any coding agent:
Install the playwright-e2e-mcp server and skill by following https://raw.githubusercontent.com/xsignon-secure/E2E/main/llms-install.md
Or add the standard config by hand (works in most clients):
{
"mcpServers": {
"playwright-e2e": {
"command": "npx",
"args": ["-y", "playwright-e2e-mcp"]
}
}
}Needs: Node.js 22+, and a project with @playwright/test and a browser
(npx playwright install chromium) or with pytest-playwright.
The server uses its working directory as the project root; if your client starts it elsewhere,
add "env": { "PW_MCP_PROJECT_ROOT": "/path/to/your/project" }.
Server and skill, as a plugin:
/plugin marketplace add xsignon-secure/E2E
/plugin install playwright-e2e-mcp@xsignon-secureOr the server only:
claude mcp add playwright-e2e -- npx -y playwright-e2e-mcpDownload the .mcpb extension from the latest release
and double-click it. It ships its own dependencies, so no Node setup is needed. On install it
asks for your project root: choose the project folder, not your home directory.
You can also add the standard config to claude_desktop_config.json.
Click Install in Cursor,
or go to Settings → MCP → Add new MCP server and paste the standard config. For one
project only, put it in .cursor/mcp.json.
Only fixing failing tests? Install the core tools only: the seven-tool fix loop
(--tools=core), about 2.3k tokens of tool definitions instead of 12.1k.
Click the Install in VS Code button above, or run:
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","playwright-e2e-mcp"]}'codex mcp add playwright-e2e -- npx -y playwright-e2e-mcpA Playwright run with retries can take longer than Codex's default 60 s tool timeout. Raise
the timeouts in ~/.codex/config.toml:
[mcp_servers.playwright-e2e]
command = "npx"
args = ["-y", "playwright-e2e-mcp"]
startup_timeout_sec = 60
tool_timeout_sec = 600Server and skill, as an extension:
gemini extensions install https://github.com/xsignon-secure/E2EOr paste the standard config into .gemini/settings.json (Qwen Code: .qwen/settings.json).
Add the standard config to the client's MCP config file (Cline: MCP Servers → Configure).
Clients that take a command, such as Zed, run npx with the arguments -y playwright-e2e-mcp.
Freebuff / Codebuff: drop an mcp.json with the standard config into your project's .agents/
folder. This repo ships one in .agents/mcp.json; Freebuff asks you to trust
a repository's .agents/ on first run.
Some clients only accept a remote HTTPS server. This repo ships a Streamable HTTP bridge you can host for free on Vercel, with OAuth sign-in for claude.ai connectors (dynamic registration and Client ID Metadata Documents). See Hosted endpoint. On Vercel the page tools (inspect a page, check selectors, accessibility and Web Vitals audits) run on a bundled Chromium against public URLs. Running and fixing your own tests needs your project, so use the local install for that.
Route | How |
Skill only, any agent |
|
MCP Registry |
|
Docker |
|
Straight from GitHub, no npm |
|
Release tarball |
|
Local checkout |
|
Installed with | To update |
| Restart your MCP client. npx (npm 10, which comes with Node 22) asks npm for the latest version on each launch and fetches it. |
|
|
|
|
GitHub Action | Change the tag (Dependabot's |
Docker |
|
Claude Desktop bundle ( | Download the new bundle from the latest release and open it |
Git clone |
|
Agent skill copied by | Run the same command again |
npx -y playwright-e2e-mcp doctor tells you whether a newer version is out and prints the
command for your setup. Upgrade notes for each release are on the
releases page.
💬 What you can ask
You ask your AI… | It does this | |
🏃 | "Run my tests" | Runs the suite and reports every failure with file, line, cause and a fix hint. One root cause breaking 30 tests shows up as one problem. |
🔍 | "Why did this fail?" | Reads Playwright's trace: the page at the moment of failure, the broken request, the console error. No guessing. |
🛠️ | "Fix it" | Swaps in a locator proven unique on that page, re-runs the test and undoes the edit if it's still red. If the element is really gone, it tells you it's an app bug. |
☁️ | "Why did CI fail?" | Loads the CI job's report (sharded blob reports too) and its traces, so the same diagnosis and fixes work on CI failures. |
🎲 | "Is this test flaky?" | Re-runs it with retries off, alone and in shuffled order, and names the race, the shared state or the test it depends on, with the seed that reproduces it. |
🎯 | "Which commit broke this?" | Bisects git history in a throwaway worktree and names the first bad commit, its diff and the failure there. |
📈 | "What's been breaking lately?" | Ranks flaky, newly broken and slow tests from the run history and names the commit where each went bad. |
🧊 | "Quarantine this flaky test" | Keeps it running and reported but stops it failing the build, with an owner and an expiry date. |
🛡️ | "Did that fix cheat?" | Compares the changed tests with git and blocks a fix that passes by deleting assertions, skipping tests or adding |
✍️ | "Write a test for this flow" | Walks the steps on the live page, writes a spec with real locators and assertions on where the flow landed, and runs it once to prove it passes. |
🔑 | "Log in and save the session" | Signs in once, 2FA codes included (generated from your TOTP secret), checks the session and saves it. The password never passes through the chat. |
♿ | "Check this page for accessibility" | Runs axe-core (WCAG 2.2 AA) and returns each problem with a verified locator and a ready regression test. |
⚡ | "Why is this page slow?" | Measures Web Vitals (LCP, CLS, INP, TBT) on desktop or a throttled phone, names the slow and shifting elements, and hands back a budget test. |
🐍 | "Run my pytest suite" | Runs |
✨ What you get
🩺 A fix loop that proves itself
Fixes are verified, not guessed.
suggest-fixpicks a locator proven unique on the DOM at failure, writes it, re-runs the test and reverts if it's still red. Strict-mode violations get the locator of the intended match; changed copy gets the new expected text.Honest about real bugs. When the element is really gone, it refuses to patch the test and reports an app bug.
Heal guard.
check-test-change(andplaywright-e2e-mcp guardin CI) blocks a "fix" that went green by deleting an assertion, skipping the test, adding.only, swallowing the error or moving an assertion under anif, and warns on weaker matchers, hard waits, forced clicks, early returns and raised timeouts.runtime: truealso runs the old and new version and blocks a test that now executes fewer assertions, which catches what no code scan can. Works for pytest-playwright files too.Asks before it writes. Applying a fix, writing a test, quarantining or replacing a visual baseline shows you the exact diff and waits for your yes in clients that support MCP questions (
PW_MCP_CONFIRM_WRITES).
🔬 Flaky tests, history and the breaking commit
Flaky verdicts with evidence.
diagnose-flakytells a race from shared state from a test-order dependency, and gives the seed that replays it.Quarantine with an owner and an expiry. The test keeps running and being reported; it stops blocking the build until the date you set.
Memory of every run.
analyze-historyranks flaky, regressed, broken and slow tests and names the commit where each went bad. Share one history across every CI job and laptop with the free, self-hosted history server (onedocker run, dashboard included).bisect-failurefinds the first bad commit without touching your checkout.audit-testsfinds flake risks in the test code (hard waits, one-shot assertions, missingawaits, fragile selectors, clicks right aftergotoon a server-rendered app), ranks them by real flakiness and applies the safe rewrites with a verifying run.
⚡ Hydration races and stale mocks
The "too fast" click. On Next.js, Nuxt, Remix, Astro and other server-rendered apps the HTML is clickable before JavaScript attaches its handlers, so a test clicks, the step passes and nothing happens.
inspect-pagenames the framework and measures how long controls were on screen before hydration;get-failureanddiagnose-flakyflag a click made while the page's scripts were still downloading and hydration errors in the console; each comes with the wait to add.Mocks that drifted from the API.
check-mocks(andplaywright-e2e-mcp mocksin CI) finds everyroute.fulfillJSON body androuteFromHARrecording, calls the real endpoint (GET only) and reports the fields the mock relies on that the API no longer sends, changed types, new nulls and removed endpoints, so a green suite stops hiding a broken contract.
🔗 CI runs by URL, remote browsers, Python fixes and AI chat UIs
Paste the CI run, skip the download. Give
load-reporta GitHub Actions run or GitLab job URL. It fetches the report and traces with your ownGITHUB_TOKEN/GITLAB_TOKEN, maps them onto your checkout, andget-failureandsuggest-fixwork on that run.{ "report": "https://github.com/acme/shop/actions/runs/123456789" }Any browser, anywhere. The page tools take
connect: a Playwright server (npx playwright run-server), a browser grid or device cloud, or a Chrome over CDP. Keys stay in the environment as{{env:…}}, never in chat, and only go to hosts you named inPW_MCP_CONNECTorPW_MCP_CONNECT_HOSTS.{ "url": "https://staging.example.com", "connect": "wss://grid.example.com/playwright?key={{env:E2E_GRID_KEY}}" }Fixes for pytest suites.
suggest-fixnow patchestest_*.pyfiles in Python syntax and re-runs the test with pytest before keeping the change:- page.get_by_test_id("checkout-button").click() + page.get_by_role("button", name="Checkout").click()AI chat and streaming UIs. The agent skill shows how to test answers that stream in: mock the model's stream, wait for the "done" signal instead of the text, and check shape rather than exact wording against a live model.
await expect(page.getByRole('button', { name: 'Stop' })).toBeHidden(); await expect(page.getByTestId('message').last()).toHaveText('Hello, world!');
🤖 CI that comments with working fixes
GitHub Action that writes the diagnosis to the job summary, keeps one PR comment up to date and posts each verified fix as a suggested change reviewers apply with one click.
CI templates for GitHub Actions, GitLab, Azure DevOps, CircleCI, Bitbucket and AWS CodeBuild, and a plain
cicommand for anything else.Diagnose CI locally:
load-reportmaps a CI job's report and traces onto your checkout.
🌐 Page tools with locators that already work
inspect-pagereturns a compact map of verified Playwright locators (about 570 tokens for a storefront page, against 2,300 for a Playwright MCP snapshot), or the full DOM inventory, or the accessibility snapshot with a readytoMatchAriaSnapshotassertion.Reaches the hard screens: saved logins, headers, click and fill steps, popups and new tabs, API mocks (500s, empty lists, slow calls), HAR record and replay, phone and tablet presets, Chromium, Firefox, WebKit, Chrome and Edge.
Look without changing anything:
blockWritesstops POST, PUT, PATCH and DELETE requests from reaching a real backend, andblockResourcesskips images, fonts and trackers for faster, private page checks.offline: truecuts the network after load to test offline states.Accessibility, Web Vitals and visual diffs that return locators and ready tests, not just a score.
🚀 Built for agents in 2026
Lean on context. Start with
--tools=auto(about 2.4k tokens of tool definitions instead of 12.1k) and the agent loads the page, audit or history tools when it needs them, or pick a profile:core,triage,inspect,author.Interactive test report in MCP Apps clients (Claude, ChatGPT, Cursor): filter failures, see expected vs. received, re-run or "Ask to fix" in one click.
Current MCP: the stateless 2026-07-28 revision (2025 clients still work), structured results with output schemas, tool annotations for accurate safety prompts, the skill served over the Skills extension, and a Server Card for discovery.
Everywhere you work: npm, Claude Code plugin, Claude Desktop bundle, Gemini CLI extension, Docker image on GHCR, and an HTTP bridge with OAuth for remote-only clients.
🧰 Tools
Tool | Purpose |
| Run Playwright tests and return stats, failures grouped by root cause, diagnostics and hints; |
| Progress or final result of a background run; can wait for it or cancel it |
| Deep analysis of one failure: stack, expected/actual, DOM snapshot at failure (from the trace), failed requests, console errors, next steps |
| Load a run from CI (JSON report, sharded blob reports, or straight from a GitHub Actions run or GitLab job URL), map its paths onto the checkout and find the traces, so every other tool works on it |
| Patch a failure with a locator proven unique on the DOM at failure or the new expected text; |
| Heal guard: BLOCK deleted assertions, skipped or removed tests, |
| Mock drift: compare every |
| Run a test 2–10 times with retries off and return |
| Quarantine a flaky test with an owner, a reason and an expiry (default 14 days); it keeps running but stops failing |
| Rank flaky, regressed, broken and slow tests, group failures by cause, show stability by day and the commit where each test went bad |
| Find the commit that broke a test: binary-search git history in a temporary worktree (your checkout is untouched) |
| Audit the test code for flake risks, ranked by real flakiness; |
| List tests ( |
| Open a URL (optionally signed in, after steps) and return verified locators, the full element inventory, or the ARIA snapshot with a ready assertion; reports the framework and the hydration gap on server-rendered pages |
| Check a CSS selector, Playwright selector or locator expression on a live page: match count and a sturdier verified locator for each match |
| Scaffold a test with the project's real selectors, or walk a flow on the live page and write a spec that is run once to prove it passes |
| Log in once and save the session with |
| axe-core (WCAG 2.2 AA) violations, worst first, with verified locators and a regression check |
| Lab Web Vitals (LCP, CLS, TBT, FCP, TTFB, INP), optionally as a throttled phone; names the LCP and shifting elements and returns a budget test |
| Visual regression: screenshot before/after a change and report what moved and how colors shifted |
With --tools=auto, a load-tools tool turns on more tools mid-session. Two prompts,
fix-failing-test and triage-flaky-tests, package the main workflows as slash commands. Every
argument and example output is in the tool reference.
run-test{ "testFiles": ["tests/checkout.spec.ts"] }, or{ "background": true }for a long suite andget-run-status{ "waitSeconds": 30 }until it finishes. For a failure from CI, callload-reportwith the run URL{ "report": "https://github.com/acme/shop/actions/runs/123" }(needsGITHUB_TOKEN; GitLab job URLs needGITLAB_TOKEN), or with the artifacts you downloaded{ "report": "ci-artifacts/results.json" }.get-failure{ "index": 1 }to read the code frame, expected/actual, the DOM snapshot at failure, the failed network requests and the page's console errors.suggest-fix{ "index": 1 }for a locator or copy change: review the diff, then{ "index": 1, "apply": true }to write it and verify with a re-run. If it reports the element is missing, fix the app, not the test.For anything it cannot patch:
inspect-page{ "url": "…" }(addstorageStateoractionsto reach the right screen), thenvalidate-selectorto prove the new locator before editing.If a failure looks intermittent:
diagnose-flaky{ "runs": 3 }for fresh evidence, andanalyze-history{ "view": "commits" }to see where it went bad.Re-run only what failed with
run-test{ "lastFailed": true }until green.
To write a new test, call generate-e2e-test with a description and the steps of the flow;
it walks them on the live page, writes the spec and runs it once.
🤖 CI: GitHub Action, GitLab and any CI
The same diagnosis runs without an agent. On a pull request the Action re-runs each failing test with its suggested fix and posts the fixes that pass as suggested changes on the failing lines, so a reviewer applies one with the Commit suggestion button:
permissions:
contents: read
pull-requests: write # for the PR comment and the suggested fixes
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with: { node-version: 24 }
- run: npm ci && npx playwright install --with-deps chromium
- uses: xsignon-secure/E2E@v0.15.0
with:
flaky-runs: 3 # 0 skips the flaky verdict
suggest: 2 # suggest-fix diffs for the first 2 failures
# guard: true # fail the job if a test was made to pass by checking lessReady-to-copy workflows: GitHub Actions (artifact upload, heal guard, history server), GitLab CI (heal guard on merge requests and a merge request comment), Azure DevOps, CircleCI, Bitbucket Pipelines and AWS CodeBuild (heal guard on pull requests, reports as artifacts).
Any other CI (Jenkins, Buildkite, TeamCity):
npx -y playwright-e2e-mcp ci --flaky-runs 3 --suggest 2 --output report.md. Exit code0passed,1tests failed,2the run itself failed. Quarantined, unexpired failures don't fail it.Heal guard without the Action:
npx -y playwright-e2e-mcp guard --base origin/main(exit 1 on BLOCK;--strictfails on warnings too).Mock drift check:
npx -y playwright-e2e-mcp mocks --base-url https://staging.example.comagainst a preview or staging deploy (exit 1 on drift;--mapgives wildcard routes a real URL,--header "Authorization: Bearer $TOKEN"signs the calls).Team history across machines: run the free history server and give the Action
history-urlandhistory-token; every CI run lands in one history thatanalyze-historyon your laptop and the server's dashboard both read.
Action inputs: project-root, args, flaky-runs, suggest, comment, review,
verify-fixes, guard, history-token, history-url, fail-on-failure, version,
github-token. Outputs: exit-code, report, guard.
🐍 Python projects (pytest-playwright)
When the project has no Node Playwright but has pytest settings (pytest.ini, pyproject.toml,
setup.cfg, tox.ini) or a conftest.py, the tools run python -m pytest instead.
run-testruns the suite, a file,tests/test_cart.py::TestCart::test_addortests/test_cart.py:42(the test at that line).grepbecomes-k,browserbecomes--browser,retriesuses pytest-rerunfailures. Failures that finished are kept even when the run is killed.get-failureshows the message, the code frame, expected vs actual and, from the trace pytest-playwright keeps (--tracing retain-on-failureis added for you), the failed action, the DOM at failure, network and console.list-tests,analyze-history,quarantineand thecicommand work as for Node.check-test-change(the heal guard) readstest_*.pyfiles: deletedasserts andexpects,@pytest.mark.skip/xfail,try: … except: passaround an assertion, weaker matchers,wait_for_timeout,force=True.check-mocksreadsroute.fulfill(json=…),body=json.dumps(…)andbody='{…}'.suggest-fixpatches.pyfiles too: the new locator is written in Python syntax (get_by_role("button", name="Buy")) and verified with a pytest re-run. It checks the locator on the DOM at failure with Node Playwright, like the page tools.diagnose-flakyrepeats pytest tests (one pytest process per run) for the same per-test verdicts.isolate: trueruns them in parallel with pytest-xdist (-n) first, then alone.orderneeds Playwright's shuffle and is Node only.audit-testsreadstest_*.py/*_test.pywith Python rules:wait_for_timeout,time.sleep, one-shotassert loc.is_visible()(rewritten toexpect(loc).to_be_visible()withfix: true), un-awaited calls inasync deftests,force=True,networkidle,query_selector, layout selectors,timeout=0.generate-e2e-testwritestests/generated/test_<name>.pywith Python locators. Withstepsit walks the flow, writes the module and runs it once with pytest. The start URL comes frompageUrlorbase_urlin your pytest config (pytest-base-url).The page tools and
suggest-fixdrive the browser with Node Playwright. A Python project needs nothing extra: the server brings its ownplaywright-core. If it reports a missing browser, run the command it gives once (npx -y playwright@<version> install chromium).
Results come from a small pytest plugin the server loads with -p from its temp folder; nothing
is installed in your project. It uses your Python: PW_MCP_PYTHON, else .venv, venv or env
in the project, else python3 / python.
pip install pytest-playwright && playwright install chromium⚙️ Configuration
Pick your tools. --tools= (or PW_MCP_TOOLS) takes profiles and tool names:
auto (core loop plus load-tools, about 2.4k tokens), core (the seven-tool fix loop, about
2.3k), triage, inspect, author, or all twenty (about 12.1k, the default).
Environment variable | Default | Purpose |
| server cwd | Default project root for every tool |
| all | Which tools to expose, as tool names and/or profiles, comma separated (same as the |
| on |
|
| both |
|
| off |
|
|
| Ask before a tool changes your files ( |
|
| Show an interactive test report next to |
| on |
|
| — | Default |
| — | Default remote browser for the page tools (same as |
| — | Comma separated hosts ( |
| — | Only for |
| — | Your GitHub Enterprise or self-managed GitLab hosts (comma separated) that |
| project venv, then | The Python that runs a pytest-playwright suite |
| — | Default for the page tools' |
| off |
|
| random | Comma-separated seeds for |
| — | Extra environment variables |
| — | Optional: your team's history server (free, self-hosted) and a token from it. CI runs are uploaded with |
| on |
|
| — | Extra directories a caller may pass as |
| — | HTTP bridge only: bearer token that unlocks all tools: 16+ characters, 32+ recommended (see Hosted endpoint) |
| localhost + Vercel hostnames when there is no token | HTTP bridge only: comma-separated |
|
| HTTP bridge only: wrong tokens or access keys one client address may send in 15 minutes before it gets |
| any https host | HTTP bridge only: comma-separated hosts OAuth apps may return to, e.g. |
|
| HTTP bridge only: accept OAuth clients that identify with a Client ID Metadata Document (an https |
| off (on for Vercel) | HTTP bridge only, so the sign-in limit counts per client, not per proxy. |
| — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. |
|
| HTTP bridge only: how many test runs and browser probes may run at once |
| off (on for the HTTP bridge) |
|
| on for Vercel | Launch the page tools on the bundled serverless Chromium ( |
|
|
|
|
|
|
Logs always go to stderr; stdout is reserved for the MCP protocol. Unrecognized values
fall back to the default, so a typo in LOG_LEVEL logs at info and one in LOG_FORMAT
logs as text rather than silencing the server.
📊 Benchmark
bench/token-benchmark.mjs breaks a checkout button's test id on a
storefront page and fixes it two ways: with this server (run-test → suggest-fix → apply) and
with Playwright MCP plus a shell (playwright test, browser_navigate + browser_snapshot, edit,
re-run). Latest result (full output):
Step | playwright-e2e-mcp ( | playwright-e2e-mcp (all tools) | Playwright MCP + shell |
Tool definitions the model reads (every request) | 2,266 | 11,480 | 4,558 |
Run the failing test | 257 | 257 | 323 |
Find the element / propose the fix | 232 | 232 | 2,286 |
Apply + verify (re-run) | 230 | 230 | 34 |
Total for one fix | 2,985 | 12,199 | 7,201 |
Looking at the storefront page | Tokens |
| 571 |
Playwright MCP | 2,286 |
Tokens are characters ÷ 4 and count what the model reads (each tool's name, description and input
schema). Tool definitions are sent with every request, so with all 20 tools loaded they outweigh
the saving on the work itself: use --tools=core when you only fix failing tests, or
--tools=auto to start at 2,427 tokens and load more on request. The Playwright MCP route is a
lower bound: it assumes the agent picks the right locator from the snapshot on the first try,
which the server does for it here. Run 2026-11-01 with Playwright 1.64.1; re-run with
npm run build && node bench/token-benchmark.mjs.
A real run-test call served over stdio by npx -y playwright-e2e-mcp against the bundled
examples/sample-test.spec.ts (actual output, unedited):

🤝 Works alongside your browser MCP
Microsoft's Playwright MCP, Chrome DevTools MCP and similar servers are great for driving a page step by step. This server doesn't replace them or Playwright's own Test Agents in VS Code. Use a browser MCP to explore, and this one to run, diagnose and fix the suite, with fixes that are verified, a guard against fixes that cheat, flaky verdicts with evidence and the commit that broke a test.
💚 Free and open source
MIT licensed. Use it, change it, ship it in commercial work. No paid tier, no feature held back, including the team history server, which you host yourself.
No account, no API key, no sign-up.
npx -y playwright-e2e-mcp initis the whole setup.No telemetry. It never phones home. Your tests, traces and run history stay on your machine unless you point it at your own history server. The only other requests are
doctorasking npm for the latest version number when you run it (--offlineskips it),load-reportdownloading a CI run's artifacts when you give it a run URL, and a remote browser you name withconnect.Free dependencies only: the MCP SDK (Apache-2.0), zod (MIT), axe-core (MPL-2.0) and playwright-core (Apache-2.0). Test runs use the Playwright your project already has.
🆕 Recent releases
0.15: pytest-playwright suites get
diagnose-flaky(with pytest-xdist forisolate),audit-tests(Python flake rules andexpect(...)rewrites) andgenerate-e2e-test(writes and verifiestest_*.py).-nruns no longer count each pytest result twice.0.14.1: security fix: behind a reverse proxy the sign-in limit can no longer be dodged with a forged
X-Forwarded-For;{{env:…}}secrets in an agent-chosenconnectURL only go to hosts you named. CI templates for Azure DevOps, CircleCI, Bitbucket and AWS CodeBuild, andcheck-mocksreads JSON bodies written as strings (body='{"id": 1}').0.14:
run-testchanged: true(only tests affected by your changes),suggest-fixverifyAllProjects(keep a fix only if every browser passes),maskfor dynamic regions incompare-visual-state,blockResourcesandofflinefor page tools, and a guard when the server starts in your home folder.0.13.1: security fix:
load-reportonly sendsGITHUB_TOKEN/GITLAB_TOKENto github.com, gitlab.com and hosts inPW_MCP_CI_HOSTS, never along a redirect. Page tools andsuggest-fixnow work in pytest projects installed from npm or Docker (the server shipsplaywright-core).0.13:
load-reporttakes a GitHub Actions or GitLab run URL, remote browsers and device clouds withconnect,suggest-fixpatches pytest files, guidance for testing AI chat and streaming UIs.0.12: hydration-race detection,
check-mocksfor mocks that drifted from the API, heal guard that checks at run time and reads pytest files.0.11: compact
inspect-page(571 tokens instead of 3,600),--tools=autoto load tools on request, smaller tool definitions.0.10: asks before changing your files, interactive test report in MCP Apps clients, Client ID Metadata Document sign-in for the hosted endpoint.
0.9: the team history server is free, self-hosted and in this repo.
0.8: pytest-playwright suites, popups and new tabs,
blockWrites, MCP 2026-07-28, update check indoctor.0.7: saved logins with 2FA, heal guard, flaky-test quarantine.
📚 More documentation
Tool reference: every argument, example outputs, edge cases handled
Hosted endpoint: the HTTP bridge for ChatGPT and claude.ai connectors
History server: shared CI run history with a dashboard, self-hosted
Architecture: how the server is built and the design decisions behind it
Security: the security model and how to report a vulnerability
Development: building, tests, Docker, signing and releasing
🙌 Contributing
Issues, ideas and pull requests are welcome. Start with a good first issue, read CONTRIBUTING.md and the code of conduct.
License
MIT. If this saves you a debugging session, a ⭐ on the repo helps other Playwright users find it.
Available Tools
20 toolsanalyze-historyAnalyze run historyARead-onlyIdempotent
Analyze the local run history (.playwright-e2e-mcp/history.jsonl, written by every run and load-report): 'flaky' ranks tests that flip pass/fail and lists broken or regressed ones; 'patterns' groups failures by cause; 'test' shows one test's timeline; 'slow' ranks durations and slowdowns; 'trend' shows stability per day; 'commits' names the commit where each failing or flaky test went bad.
Inputs: test, view, limit, source, +2 more.
audit-accessibilityAudit page accessibilityARead-onlyIdempotent
Run axe-core on a live page (WCAG 2.2 AA by default) and return violations worst first, each with the offending elements as verified Playwright locators, the fix, and a regression check to paste into a spec. Accepts storageState/headers/actions to audit pages behind a login or after a step.
Inputs: url (required), har, device, routes, +18 more. Returns: ok, url, error, violations
audit-performanceAudit page performanceARead-onlyIdempotent
Measure a page's lab Web Vitals (LCP, CLS, TBT, FCP, TTFB, and INP when actions interact) in headless Chromium, optionally as a throttled phone and as the median of several runs. Rates them against Google thresholds or your budgets, names the LCP element and shifting elements as verified locators, lists heavy and render-blocking requests, and returns a budget check for the spec. Accepts storageState/headers/actions/routes.
Inputs: url (required), har, runs, device, +20 more. Returns: ok, url, error, metrics
audit-testsAudit tests for flake risksADestructive
Audit the Playwright test code for flake risks (hard waits, one-shot assertions instead of web-first ones, missing awaits, .only, force clicks, networkidle, element handles, layout selectors, acting right after goto on a server-rendered app before it hydrates) and rank files by how flaky their tests have been in the run history. fix: true rewrites the mechanical ones, re-runs the touched files and restores them if the run fails. TS/JS specs and pytest-playwright modules.
Inputs: fix, limit, config, filter, +6 more. Returns: ok, error, total, applied, +3 more
bisect-failureFind the commit that broke a testAIdempotent
Find the commit that broke a test: binary-search the git history between a good and a bad commit, running the test at each step in a temporary worktree (your checkout is untouched), and report the first bad commit with its diff summary and failure. good defaults to the newest commit where the run history saw the test pass.
Inputs: test (required), bad, good, grep, +6 more. Returns: ok, error, steps, status, +1 more
check-mocksCheck mocks against the live APIARead-onlyIdempotent
Catch network mocks that drifted from the real API: finds route.fulfill JSON bodies (TS/JS and pytest specs) and routeFromHAR files, GETs each mocked endpoint on the live server (baseUrl) and reports fields the mock has that the API no longer sends, changed types, new nulls and endpoints that are gone. Only GET is sent; write mocks are listed, not replayed.
Inputs: urls, filter, baseUrl, headers, +2 more. Returns: ok, error, total, status, +1 more
check-test-changeCheck a test fix (heal guard)AIdempotent
Heal guard: check that changed tests were not made to pass by checking less. Compares spec files with a git ref (default HEAD = uncommitted changes) or one proposed file (file + after). BLOCK on deleted assertions, skipped/removed tests or .only; WARN on weaker matchers, waitForTimeout, force: true, swallowed errors, raised timeouts or retries. Run it after any AI fix, before committing.
Inputs: base, file, after, files, +2 more. Returns: ok, error, total, status, +1 more
compare-visual-stateCompare visual stateADestructiveIdempotent
Visual regression check: screenshot a live page (or element), compare it to a stored baseline, and report how many pixels changed, WHERE they changed (bounding regions), and the average color shift ("blue → red"). First call saves the baseline; later calls compare. Writes a red-highlighted diff image for review.
Inputs: url (required), name (required), har, mask, +22 more.
diagnose-flakyDiagnose flaky testADestructiveIdempotent
Repeat failing tests (Playwright or pytest-playwright) with retries disabled and return a per-test, evidence-based verdict: CONSISTENTLY FAILING (real bug), FLAKY (pass/fail counts, error-signature variance, duration spread) or NOT REPRODUCING. Runs all repetitions in one process by default. isolate: true also re-runs the failures with one worker to tell parallelism bugs (shared state) from flakiness inside the test; order: true (Playwright 1.64+) runs the files in random orders to catch tests that depend on what ran before them. Defaults to the tests that failed in the most recent run.
Inputs: runs, order, config, headed, +7 more. Returns: ok, error, tests, verdict
generate-e2e-testGenerate an E2E testADestructive
Scaffold a Playwright test (a .spec.ts, or a test_*.py module in a pytest-playwright project) from a description using the project's REAL selectors. Scans the agent's recent file changes (git working tree / last commit, mtime fallback), extracts data-testid / role / label / placeholder / id locators with their source locations, optionally cross-checks them against the live page, writes a ready-to-run spec, and returns next steps. With steps it walks the flow on the live page instead: each step must work there, the spec replays them, asserts the URL and aria snapshot where the flow landed, and is run once to prove it passes.
Inputs: description (required), file, steps, write, +11 more.
get-failureAnalyze a test failureARead-onlyIdempotent
Analyze one failure from the most recent run-test execution: full message and code frame, expected vs actual, stack trace, failed network requests (4xx/5xx and dead endpoints), console errors, failure kind (assertion/timeout/browser-crash/syntax/config/server-unreachable) and concrete next steps. Use run-test first.
Inputs: index, projectRoot. Returns: ok, error, index, total, +1 more
get-run-statusCheck a background runAIdempotent
Progress (tests done/total, failures so far) or the final result of a run-test background run; the result becomes the last run for get-failure. waitSeconds waits; cancel stops it. Default: the latest run.
Inputs: runId, cancel, waitSeconds. Returns: ok, run, error, runId, +1 more
inspect-pageInspect live page DOMARead-onlyIdempotent
Open a URL in a fresh headless browser and return its elements with Playwright locators proven unique on the page (role + name first), CSS selectors, visibility, text and console messages. Each call starts clean (no cookies kept): put every step to reach a state, login included, in actions, or open it signed in with storageState/headers. By default it returns the compact locator map; view 'elements' gives the full DOM inventory and view 'aria' returns the accessibility snapshot plus a ready toMatchAriaSnapshot assertion.
Inputs: url (required), har, view, device, +19 more.
list-testsList available testsARead-onlyIdempotent
List the Playwright tests available in the project (file, line, full title, projects), with optional filtering. Uses playwright test --list when Playwright works and falls back to a source scan when the install or config is broken, reporting why.
Inputs: limit, config, filter, testDir, +1 more. Returns: ok, error, tests, total, +1 more
load-reportLoad a CI reportA
Load a Playwright run that happened elsewhere (a CI job's JSON report, a folder of blob reports from shards, or a GitHub Actions / GitLab CI run URL) so get-failure, suggest-fix and diagnose-flaky work on it like a local run. CI paths are mapped onto this checkout and traces are found in the unpacked test-results artifact; the run is recorded in the history with its commit.
Inputs: report (required), branch, commit, record, +3 more.
quarantineQuarantine flaky testsAIdempotent
Quarantine flaky tests: they keep running and being reported, but their failures stop failing run-test and the ci command until the entry expires (default 14 days, max 90). add needs owner and reason; list shows what is quarantined and what expired; remove ends it. Stored in playwright-quarantine.json (commit it).
Inputs: days, file, test, index, +5 more. Returns: ok, error, total, status, +1 more
run-testRun E2E testsADestructiveIdempotent
Run the project's Playwright tests: stats plus each failure's file:line, kind and message. Diagnoses missing installs, dead dev servers, syntax errors, crashes and timeouts (kills the tree, keeps partial results). Reports progress; background: true returns a run id for long suites. Runs are recorded for analyze-history.
Inputs: args, grep, config, headed, +11 more. Returns: ok, run, error, runId, +1 more
save-loginSave a login sessionAIdempotent
Log in once and save the session as a storageState file (default playwright/.auth/.json) for tests and the page tools. If a saved session still passes verify it is reused; expired ones log in again. Secrets stay out of chat: fill values use {{env:E2E_PASSWORD}} and {{totp}} (authenticator code from totpSecretEnv).
Inputs: url (required), name, path, reuse, +8 more. Returns: ok, url, path, error, +3 more
suggest-fixSuggest (and apply) a fixADestructive
Patch a failure from the last run: a drifted locator is matched against the DOM at failure (trace, or live url) and replaced with one proven unique; a locator that matches several elements (strict mode) gets the unique one for the intended match; changed copy gets the new expected text. Returns a diff and confidence; apply: true writes it, re-runs the test and reverts if still red. Refuses when the element is truly missing (app bug).
Inputs: url, apply, index, config, +8 more. Returns: ok, fix, error, applied, +2 more
validate-selectorValidate selector or locatorARead-onlyIdempotent
Check a CSS selector, Playwright selector or locator (getByRole/getByTestId…, .first(), .filter(), frameLocator() for iframes) on a live page: validity, match count (actions need exactly 1), sample matches and a sturdier verified locator for each. Counts once after load: use waitFor or actions for late elements. Accepts storageState/headers/actions.
Inputs: url (required), selector (required), har, device, +15 more. Returns: ok, url, error, valid, +3 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Most tools target clearly distinct phases (run, inspect, generate, fix, audit), and the long descriptions actively spell out boundaries. A few pairs are genuinely adjacent and could still be mispicked: audit-tests vs check-test-change (both audit spec code), diagnose-flaky vs analyze-history (both about flakiness), and inspect-page vs validate-selector (both return verified locators for a live page).
Nearly everything follows a predictable kebab-case verb_noun pattern (run-test, get-failure, audit-accessibility, suggest-fix). The only outlier is the bare verb 'quarantine', which is a minor deviation rather than a convention break.
20 tools sits at the heavy end, but the domain genuinely spans running, debugging, auditing, generating, visual/a11y/perf checks, and session handling, so most tools earn their place. A few (audit-tests/check-test-change, inspect-page/validate-selector) could arguably merge, which keeps it from a 5.
Coverage of the E2E lifecycle is strong: run, list, inspect, generate, heal, bisect, flake-diagnose, history, quarantine, mocks, a11y, perf, visual, and login persistence. Minor gaps remain around directly editing/managing spec files or test config beyond generation, but no core workflow is a dead end.
Maintenance
Related MCP Connectors
Approved test intent, reviewed Playwright automation and run evidence, inside your editor.
Finds what's broken in your product, explains why, and fixes it from your agent.
Agents that test your web and mobile app like real users, on every pull request.
QA platform for agents: coverage signals, in-repo test plans, verified tests and release governance.
Related MCP Servers
- AlicenseAqualityDmaintenanceGenerates intelligent Playwright locators with reliability rankings, creates Page Object Models, and runs test automation scripts directly from your IDE or AI assistant.55 npm1MIT
- AlicenseAqualityBmaintenanceEnables AI assistants to create, run, autocorrect, and monitor Playwright tests for your app with a local dashboard, credential vault, and public status page.16MIT

QualityMax QA MCPofficial
AlicenseAqualityBmaintenanceEnables coding agents to independently verify web changes by scanning pages, inspecting UI structure, generating Playwright reproductions, and executing tests with structured QA evidence.485 npm4MIT- AlicenseAqualityBmaintenanceEnables AI coding assistants to generate, score, run, and auto-heal Playwright E2E tests while enforcing domain-driven page object architecture and anti-flakiness rules.8MIT