Skip to main content
Glama

npm npm downloads CI MCP Registry License: MIT

Install in Cursor Install in VS Code Add to Claude Desktop

An MCP server and agent skill that gives your AI assistant (Claude, Cursor, VS Code Copilot, Gemini, Codex) a full Playwright toolkit: a test runner, a failure detective and a fixer that checks its own work. Other tools let an AI click around a browser. This one lets it keep your test suite green.

❌ 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 around a real bug.

With it, your agent reads the page as it was when the test failed, 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 tells you it's an app bug.

run-test ──────┐
load-report ───┴─▶ get-failure ──▶ suggest-fix (apply + re-run) ──▶ green
 (CI job report)        │                 └─ refuses when the element is really gone (app bug)
                        └─ DOM at failure, failed requests, console errors
every run ──▶ analyze-history (flaky / broken / slow / which commit broke it)
test code ──▶ audit-tests (flake risks, ranked by history, verified rewrites)
red at HEAD ─▶ bisect-failure (runs it across git history, names the breaking commit)

Related MCP server: tuxedo-qa

Key features

  • Fixes are proven, not guessed. Every fix is re-run before it's kept, and undone if the test is still red.

  • Honest. It won't paper over a real bug to make a test pass.

  • Works on CI failures too. Load a CI job's report and traces and get the same diagnosis and fixes.

  • Flakiness with evidence. Names the flaky test, whether it's a race, shared state or test order, and the seed that reproduces it.

  • Lean. With the core tool set, finding and fixing a broken locator took about 5,500 tokens versus about 7,900 with Playwright MCP plus a shell. All 19 tools add about 16k tokens of definitions to every request, so load only the profiles you use (benchmark).

  • Free and open source. MIT, no account, no API key, no telemetry. Every tool is free; an optional paid Pro only adds hosted CI history.

🚀 What only this MCP does

Most testing MCPs let an AI drive a browser: Microsoft's Playwright MCP, Chrome DevTools MCP, ExecuteAutomation's mcp-playwright and the Selenium MCP. They're great for clicking through a page. None of them, as of October 2026, does the following. This one does:

Capability

What you get

🛡️ A guard against "fixes" that check less

check-test-change compares a changed test with its old self and blocks a fix that went green by deleting an assertion, skipping the test or adding .only; it warns on weaker matchers, hard waits, forced clicks and swallowed errors. The same check runs in CI as guard

🧊 Quarantine with an owner and an expiry

quarantine keeps a flaky test running and reported while its failure stops blocking the build, with who fixes it, why, and the date it blocks again

🎯 Find the commit that broke a test

bisect-failure runs the test across your git history, in a temporary worktree that leaves your checkout alone, and names the first bad commit with its diff and the failure

🧪 Flake-risk audit of your test code

audit-tests finds hard waits, one-shot assertions, missing awaits and fragile selectors. It ranks them by how flaky those tests really were, then applies the safe rewrites and re-runs them to prove them

✅ Fixes that prove themselves

suggest-fix swaps in a locator proven unique on the DOM at failure, re-runs the test and reverts if it's still red. It refuses to patch over a real app bug

🔬 Flaky-test verdicts with evidence

diagnose-flaky repeats tests with retries off and tells a race from shared state from test order, naming the test it depends on and the seed that reproduces it

📈 Memory of every run

analyze-history ranks flaky, regressed and broken tests, groups failures by cause, tracks slow tests and names the commit where each one went bad

🏗️ Diagnose CI failures locally

load-report loads a CI job's report and traces (sharded too), so the same diagnosis and verified fixes work on failures from CI

💬 One-click fixes on pull requests

The GitHub Action verifies each fix in CI and posts it as a suggested change reviewers apply with one click

♿⚡ Audits that hand back tests

Accessibility (axe-core) and Web Vitals audits return verified locators for each problem plus a ready regression or budget test

It works alongside a browser MCP rather than replacing it: that one drives the page, and this one keeps your suite green.

What you can ask

You ask your AI…

It does this

🏃

"Run my tests"

Runs the suite and reports every failure with its 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 the page, re-runs the test, and undoes the edit if it's still red. If the button is really gone, it tells you it's an app bug instead of hiding it.

🎲

"Is this test flaky?"

Re-runs it many ways (repeated, alone, in random order) and names the exact test and seed that cause the flake.

📈

"What's been breaking lately?"

Keeps a local run history and separates flaky, newly broken and always-broken tests; shows the slowest tests, stability by day and the commit where each test went bad.

☁️

"Why did CI fail?"

Loads the CI job's report (or merges sharded blob reports), maps its paths onto your checkout and finds the traces in the downloaded artifact, so the same diagnosis and fixes work on CI failures.

✍️

"Write a test for this flow"

Walks the steps on the live page first, writes a spec that replays them with assertions on where the flow landed (URL and accessibility snapshot), and runs it once to prove it passes.

♿

"Check this page for accessibility"

Runs axe-core (WCAG 2.2 AA) and returns each problem with a ready-to-paste locator and regression test.

⚡

"Why is this page slow?"

Measures Web Vitals (LCP, CLS, INP, TBT) on desktop or a throttled phone, names the slow element and the elements that jump, and hands back a budget test.

🧪

"Show me the error state"

Mocks API responses (500s, empty lists, slow calls) so the AI can inspect, audit or measure states that are hard to reach.

🔑

"Log in and save the session"

Logs in once (password from an environment variable, authenticator code generated from the TOTP secret), checks the session works and saves it for tests and page tools; reuses it until it expires. The password never passes through the chat.

🛡️

"Did that fix cheat?"

Compares the changed tests with git and blocks a fix that passes by deleting assertions or skipping tests.

🧊

"Quarantine this flaky test"

Keeps it running and reported, stops it failing the build, with an owner and an expiry date.

🔐

"Test the page after login"

Works behind sign-in with saved sessions, headers and click/fill steps, in Chromium, Firefox or WebKit, and can record or replay network traffic from a HAR file.

🤖

"Do it in CI"

A GitHub Action and ci command post the diagnosis, flaky verdict and fix diffs on your PR.

Requirements

  • Node.js 22 or newer

  • A project that uses @playwright/test, with a browser installed (npx playwright install chromium)

  • Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Codex, Gemini CLI or any other MCP client

Getting started

Fastest: run this in your project root. It adds the server to every client config it finds (Claude Code, Cursor, VS Code, Gemini CLI, Codex) and installs the agent skill, leaving 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 and client setup

Or let your agent do 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

Standard config works in most clients:

{
  "mcpServers": {
    "playwright-e2e": {
      "command": "npx",
      "args": ["-y", "playwright-e2e-mcp"]
    }
  }
}

The server uses its working directory as the project root. If your client starts it somewhere else (such as your home directory), 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-secure

Or the server only:

claude mcp add playwright-e2e -- npx -y playwright-e2e-mcp

Download 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.

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-mcp

A 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 = 600

Server and skill, as an extension:

gemini extensions install https://github.com/xsignon-secure/E2E

Or 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.

Drop an mcp.json with the standard config into your project's .agents/ folder. This repo ships one in .agents/mcp.json, so opening the checkout attaches the server workspace-wide. 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. 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

npx skills add xsignon-secure/E2E

MCP Registry

io.github.xsignon-secure/E2E (listing); registry-aware clients find it there

Straight from GitHub, no npm

npx -y github:xsignon-secure/E2E#v0.7.0 (pin a release tag)

Release tarball

npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.7.0/playwright-e2e-mcp-0.7.0.tgz

Docker

docker run -i --rm -v "$PWD:/work" ghcr.io/xsignon-secure/playwright-e2e-mcp (published on each release; see Development)

Local checkout

"command": "node", "args": ["/path/to/E2E/dist/index.js"]

Your first prompt

Restart your client, then ask:

Run my Playwright tests and fix whatever fails.

Your agent should run the suite, read the failure, and propose a fix it has re-run. To check the setup without your own tests, ask it to run examples/sample-test.spec.ts from this repo.

What's new in 0.7

  • Log in once, safely: save-login signs in (2FA codes included) with secrets read from the environment, checks the session and saves it as a storageState file; it reuses the session until it stops working.

  • Heal guard: check-test-change and playwright-e2e-mcp guard block a test "fix" that passes by checking less (deleted assertions, skipped tests, .only).

  • Flaky-test quarantine: quarantine stops a known flaky test from failing the build for a set time, with an owner and a reason, while it keeps running and being reported.

What's new in 0.6

  • Find the commit that broke a test: bisect-failure runs the test across git history in a temporary worktree and names the first bad commit, its changes and the failure there.

  • Flake-risk audit: audit-tests finds hard waits, one-shot assertions, missing awaits and fragile selectors, ranked by real flakiness, and applies the safe rewrites with a verifying run.

  • One-click fixes on pull requests: the GitHub Action proves each fix in CI and posts it as a suggested change.

  • doctor: npx playwright-e2e-mcp doctor checks Node, Playwright, browsers and client setup.

  • Structured results: every tool returns JSON next to its Markdown, with output schemas.

  • Phones, tablets, Chrome and Edge: device presets and channel for every page tool, and a Docker image on ghcr.io.

  • Node 22 or newer is now required, and the hosted endpoint limits guessing of its key.

All release notes

Tools

Tool

Purpose

run-test

Run Playwright tests and return stats, failures, diagnostics and hints; reports progress, and background: true returns a run id for long suites

get-run-status

Progress or final result of a background run; can wait for it or cancel it

get-failure

Deep analysis of one failure: stack, expected/actual, DOM snapshot at failure (from the Playwright trace), failed requests, console errors, next steps

load-report

Load a run from CI: a JSON report or a folder of sharded blob reports; CI paths are mapped onto the checkout and traces found in the unpacked artifact, so get-failure, suggest-fix and diagnose-flaky work on it, and the run joins the history with its commit

suggest-fix

Patch a failure: a drifted locator is replaced with one proven unique on the DOM at failure, an ambiguous one (strict mode violation) gets the unique locator of the intended match, changed copy gets the new expected text; apply: true writes it, re-runs the test and reverts if still red

inspect-page

Open a URL headlessly (optionally signed in, after steps) and return elements with verified Playwright locators, CSS selectors, visibility, text and console output, or the accessibility snapshot with a ready toMatchAriaSnapshot assertion

list-tests

List available tests (file, line, full title, projects) with filtering

validate-selector

Check a CSS selector, Playwright selector or locator expression against a live page: validity, match count, and a sturdier verified locator for each match

generate-e2e-test

Scaffold a Playwright test from a description using the project's real selectors and verified locators from the live page, or walk a flow step by step on the live page and write a spec that is run once to prove it passes

compare-visual-state

Visual regression: screenshot before/after a change and report what moved and how colors shifted

audit-accessibility

Run axe-core (WCAG 2.2 AA by default) on a page, signed in or after steps, and return violations worst first with verified locators for the offending elements and a regression check

audit-performance

Measure lab Web Vitals (LCP, CLS, TBT, FCP, TTFB, INP during steps), optionally as a throttled phone and the median of several runs; rate them or check budgets, name the LCP and shifting elements as verified locators, list heavy and render-blocking requests, and return a budget test

diagnose-flaky

Run a failing test 2–10 times with retries disabled and return an evidence verdict: CONSISTENTLY FAILING, FLAKY or NOT REPRODUCING; tells parallelism and test-order bugs from races

analyze-history

Rank flaky, regressed and broken tests from the local run history, group failures by cause, list the slowest tests, show stability by day, name the commit where each test went bad, or show one test's timeline

audit-tests

Audit the 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), ranked by how flaky those tests have been in the run history; fix: true rewrites the mechanical ones, re-runs the files and reverts if they fail

save-login

Log in once and save the session (storageState): steps with {{env:E2E_PASSWORD}} and {{totp}} (authenticator code from a secret in the environment), a check that the session works, and reuse until it expires; secrets never pass through the chat

check-test-change

Heal guard: compare changed tests with git (or a proposed fix with the file) and BLOCK deleted assertions, skipped or removed tests and .only; WARN on weaker matchers, hard waits, force: true, swallowed errors and raised timeouts or retries

quarantine

Quarantine a flaky test with an owner, a reason and an expiry (default 14 days): it keeps running and being reported, but its failure no longer fails run-test or ci until the entry expires. Stored in playwright-quarantine.json

bisect-failure

Find the commit that broke a test: binary-search 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, what it changed and how the test failed

Two prompts package the main workflows for clients that show them as slash commands: fix-failing-test and triage-flaky-tests.

Every argument and example output is in the tool reference. All tools carry MCP tool annotations (readOnlyHint, destructiveHint, …), so clients can show accurate safety prompts.

Only need the fix loop? --tools=core (or PW_MCP_TOOLS=core) exposes seven tools and cuts the tool-definition context by about three quarters. Other profiles: triage, inspect, author.

  1. run-test { "testFiles": ["tests/checkout.spec.ts"] }, or { "background": true } for a long suite and get-run-status { "waitSeconds": 30 } until it finishes. For a failure from CI, download the job's artifacts and call load-report { "report": "ci-artifacts/results.json" } instead.

  2. 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.

  3. 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.

  4. For anything it cannot patch: inspect-page { "url": "…", "view": "locators" } (add storageState or actions to reach the right screen), then validate-selector to prove the new locator before editing.

  5. If a failure looks intermittent: diagnose-flaky { "runs": 3 } for fresh evidence, and analyze-history to see how the test behaved across earlier runs ({ "view": "commits" } names the commit where it went bad).

  6. After changing CSS or components: compare-visual-state { "url": "…", "name": "checkout" }.

  7. Re-run only what failed with run-test { "lastFailed": true } until green.

To write a new test, find the locators with inspect-page { "view": "locators" }, then 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. To check a page's speed or accessibility, use audit-performance and audit-accessibility.

CI: GitHub Action and ci command

The same diagnosis runs without an agent. playwright-e2e-mcp ci runs the suite (auto-retry once, so flaky tests are reported as flaky, not failed), optionally drafts suggest-fix diffs and a flaky verdict for the failures, and writes one Markdown report to stdout, to --output, and to the GitHub job summary when GITHUB_STEP_SUMMARY is set. Exit code 0 passed, 1 tests failed, 2 the run itself failed.

npx -y playwright-e2e-mcp ci --flaky-runs 3 --suggest 2 --output report.md
npx -y playwright-e2e-mcp ci --help

As a GitHub Action, it adds the report to the job summary and keeps one PR comment up to date when the run fails. On a pull request it also 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 (only on lines the PR changed; the rest stay in the report):

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.7.0
    with:
      flaky-runs: 3      # 0 skips the flaky verdict
      suggest: 2         # suggest-fix diffs for the first 2 failures
      # args: --browser chromium tests/checkout

A complete, ready-to-copy workflow is available in examples/github-actions/playwright-e2e.yml, including artifact upload and commented options for guard: true and Pro Cloud.

Inputs: project-root, args, flaky-runs, suggest, comment, review, verify-fixes, guard, pro-key, pro-url, fail-on-failure, version, github-token. Outputs: exit-code, report, guard.

Quarantined tests (playwright-quarantine.json, see quarantine) are honoured here too: when every failure is quarantined and unexpired, ci exits 0 and the report lists them.

Heal guard in CI. guard: true checks the PR's changed tests against the base branch first and fails the job if a test was made to pass by checking less. Without the Action:

npx -y playwright-e2e-mcp guard --base origin/main   # exit 1 on BLOCK; --strict fails on warnings too

Configuration

Environment variable

Default

Purpose

PW_MCP_PROJECT_ROOT

server cwd

Default project root for every tool

PW_MCP_TOOLS

all

Which tools to expose, as tool names and/or profiles, comma separated (same as the --tools= flag). Profiles: core (run, status, failure, fix, flaky, heal guard, list), triage (run, status, failure, CI report, flaky, history, test audit, bisect, quarantine, heal guard, list), inspect (page, selector, accessibility, performance, visual, login), author (list, page, selector, generate, run, login, heal guard). All nineteen tool definitions cost about 16k tokens of context per request; core costs about 5k (12k and 2.6k with PW_MCP_OUTPUT_SCHEMAS=0)

PW_MCP_OUTPUT_SCHEMAS

on

0 leaves the output schemas out of the tool list to save context. Results still carry structuredContent (see Structured results)

PW_MCP_STORAGE_STATE

—

Default storageState file (inside the project) for the page tools

PW_MCP_SHUFFLE_SEEDS

random

Comma-separated seeds for diagnose-flaky's order pass, to replay the orders a diagnosis reported

PW_MCP_LOGIN_ENV

—

Extra environment variables save-login may type through {{env:NAME}}, comma separated. Without it only E2E_*, TEST_*, PW_*, PLAYWRIGHT_* and LOGIN_* are allowed

PW_MCP_PRO_KEY / PW_MCP_PRO_URL

—

Optional, paid: Pro key and Pro Cloud address. CI runs are uploaded with playwright-e2e-mcp upload (or the Action's pro-key / pro-url inputs) and analyze-history merges them with local runs. Unset (the default), nothing is ever sent anywhere

PW_MCP_HISTORY

on

0 stops recording runs to .playwright-e2e-mcp/history.jsonl

PW_MCP_ALLOWED_ROOTS

—

Extra directories a caller may pass as projectRoot (:-separated, ; on Windows). Anything outside these and the default root is rejected

PW_MCP_HTTP_TOKEN

—

HTTP bridge only: bearer token that unlocks all tools: 16+ characters, 32+ recommended (see Hosted endpoint)

PW_MCP_ALLOWED_HOSTS

localhost + Vercel hostnames when there is no token

HTTP bridge only: comma-separated Host allowlist; * accepts any

PW_MCP_MAX_FAILED_AUTH

20

HTTP bridge only: wrong tokens or access keys one client address may send in 15 minutes before it gets 429

PW_MCP_OAUTH_REDIRECT_HOSTS

any https host

HTTP bridge only: comma-separated hosts OAuth apps may return to, e.g. claude.ai,chatgpt.com; .example.com covers subdomains; localhost always works

PW_MCP_TRUST_PROXY

off (on for Vercel)

HTTP bridge only: 1 trusts X-Real-IP / X-Forwarded-For from a reverse proxy in front, so the sign-in limit counts per client, not per proxy

PW_MCP_PASSTHROUGH_ENV

—

HTTP bridge only: comma-separated extra variables passed to test runs (e.g. BASE_URL)

PW_MCP_MAX_CHILDREN

4

HTTP bridge only: how many test runs and browser probes may run at once

PW_MCP_BLOCK_PRIVATE_URLS

off (on for the HTTP bridge)

1 makes the URL tools refuse loopback, private-network and cloud-metadata addresses, including redirects and subresources

PW_MCP_SERVERLESS_CHROMIUM

on for Vercel

Launch the page tools on the bundled serverless Chromium (@sparticuz/chromium, Linux x64, Node 22+); 0 turns it off, 1 turns it on elsewhere

LOG_LEVEL / MCP_LOG_LEVEL

info

debug | info | warn | error | silent; LOG_LEVEL wins when both are set

LOG_FORMAT / MCP_LOG_FORMAT

text

text, or json (also ndjson) for one structured JSON object per line — ready for a log ingester

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. With LOG_FORMAT=json each line is a single object (time, level, message plus context):

{"time":"2026-10-07T08:00:00.000Z","level":"info","message":"server ready","name":"playwright-e2e-mcp"}

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 (core tools)

playwright-e2e-mcp (all tools)

Playwright MCP + shell

Tool definitions (sent with every request)

4,826

16,121

5,225

Run the failing test

244

244

323

Find the element / propose the fix

232

232

2,286

Apply + verify (re-run)

230

230

34

Total for one fix

5,532

16,827

7,868

Tokens are characters ÷ 4. The work itself (run, diagnose, fix, verify) takes about 700 tokens here versus about 2,600 with Playwright MCP, but tool definitions are sent with every request: with all 19 tools loaded they outweigh that saving, so set PW_MCP_TOOLS=core (or another profile) when you only fix failing tests. 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-10-28 with 0.7.0 and Playwright 1.64.1; re-run with npm run build && node bench/token-benchmark.mjs.

Demo

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):

run-test result: 4 passed, 0 failed, 5.1s

Free and open source

  • MIT licensed. Use it, change it, ship it in commercial work; no fees, no feature held back. The optional Pro plan adds a hosted service (CI run history across machines), not tools; nothing here needs it.

  • No account, no API key, no sign-up. npx -y playwright-e2e-mcp init is the whole setup.

  • No telemetry. It never phones home; your tests, traces and run history stay on your machine unless you set a Pro key and upload them.

  • Free dependencies only: the MCP SDK (Apache-2.0), zod (MIT), axe-core (MPL-2.0) and the Playwright your project already has (Apache-2.0).

  • Free to host yourself, too: the HTTP bridge deploys to a free Vercel account (see Hosted endpoint).

What it does not do: it doesn't drive an exploratory browsing session step by step, and it doesn't replace Playwright's own Test Agents inside VS Code. Use Playwright MCP for interactive browsing and this server for running, diagnosing and fixing the suite. They work side by side.

More documentation

License

MIT. If this saves you a debugging session, a ⭐ on the repo helps other Playwright users find it.

Available Tools

19 tools
analyze-historyAnalyze run historyA
Read-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.

NameRequiredDescriptionDefault
testNoFilter: substring of file or title
viewNoDefault 'flaky'; 'slow' ranks durations, 'trend' is per day, 'commits' names the commit each test went bad
limitNo
sourceNoWith a Pro key: 'both' (default) merges this machine's runs with CI runs from Pro Cloud; 'cloud' or 'local' for one side
lastRunsNoRuns to analyze (default 30)
projectRootNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so the safety profile is covered. The description adds meaningful context beyond that: the data comes from a local file that every run and load-report writes, implying history is unavailable before any run exists. It omits behavior on empty/truncated history and how cloud merging affects results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The artifact and its provenance are front-loaded, followed by a compact semicolon-delimited mode list; every clause carries information. The single dense sentence is slightly harder to scan than a short bullet-style enumeration would be, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, zero-required-parameter tool with no output schema, the description covers the data source and all six modes, which is what an agent needs to choose a view. It stops short of describing result shape or the empty-history case, but the annotations and schema carry the rest.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, so the schema already documents view, source, lastRuns, and the test filter. The description adds real meaning for 'patterns' and 'test' views that the schema's enum description lacks, but says nothing about limit, projectRoot, or the default 30-run window, leaving the coverage gap partly unfilled.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource, names the exact backing artifact (.playwright-e2e-mcp/history.jsonl) and its provenance (written by every run and load-report), then enumerates the six analysis modes. An agent can distinguish this from diagnose-flaky or get-failure without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Each view is mapped to the question it answers ('flaky' ranks flipping tests, 'patterns' groups by cause, 'test' shows one timeline), which effectively tells the agent which mode to select. It does not state when to prefer a sibling tool such as diagnose-flaky, nor any preconditions like 'requires prior runs'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit-accessibilityAudit page accessibilityA
Read-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.

NameRequiredDescriptionDefault
harNo
urlYesFull URL of the page to audit (http/https)
deviceNoPlaywright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)
routesNoNetwork mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request
actionsNoSteps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows
browserNoEngine (default chromium)
channelNoBranded Chromium to launch instead of the bundled one (must be installed)
headersNoExtra HTTP headers, e.g. Authorization
waitForNoWait for this selector first
selectorNoCSS selector: audit only this part of the page
standardNoRule set: WCAG level (default wcag22aa, i.e. 2.0–2.2 A+AA), 'best-practice' adds axe's extra rules, 'all' runs everything
viewportNo
minImpactNoHide violations below this impact (default: minor, show all)
timeoutMsNoOverall audit limit in ms (default 60000)
waitUntilNoNavigation wait condition (default load)
projectRootNoProject whose Playwright launches the browser (default: server root)
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
actionTimeoutMsNoHow long each action waits for its element (default 10000); keep timeoutMs above the total

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
urlNo
errorNo
violationsNo

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered. The description adds useful behavior beyond them — result ordering (worst first), what each violation carries, and the auth/multi-step entry paths — but says nothing about runtime cost, rate/timeout limits, or failure modes of a live-page audit. Solid additive value, not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both front-loaded: capability and return value first, conditional entry paths second. No filler, and every clause carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 18-parameter tool with nested objects and an output schema, the description covers the essential mental model: what is audited, how results are ordered, and how to reach authenticated or multi-step pages. Minor gaps (timeout budget, projectRoot/browser selection, selector scoping) are fully documented in the schema, so nothing blocking is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 89%, so the schema already documents nearly every parameter including defaults and enums. The description only gestures at the storageState/headers/actions trio by purpose (login, post-load state) rather than adding syntax or interaction details like the one-fresh-browser-per-call constraint. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and engine ("Run axe-core on a live page") plus the default rule set (WCAG 2.2 AA) and the return shape (violations worst first with verified Playwright locators, fix, regression check). The accessibility-audit domain is unmistakably distinct from siblings like audit-performance and audit-tests, so an agent can select it without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence gives concrete usage contexts: pages behind a login (storageState/headers) or states reachable only after steps (actions). What is missing is explicit routing away from alternatives — nothing says "use audit-performance for timing" or when not to run this, so it stops short of the top band.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit-performanceAudit page performanceA
Read-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.

NameRequiredDescriptionDefault
harNo
urlYesFull URL of the page to measure (http/https)
runsNoLoad the page this many times and report the median (default 1)
deviceNoPlaywright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)
routesNoNetwork mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request
actionsNoSteps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows
browserNoEngine (default chromium)
budgetsNoFail the audit when a metric exceeds its budget (default: rate against Google thresholds)
channelNoBranded Chromium to launch instead of the bundled one (must be installed)
headersNoExtra HTTP headers, e.g. Authorization
waitForNoWait for this selector first
settleMsNoKeep observing after load for late paints and shifts (default 1500)
throttleNo'mobile': phone viewport, 4x CPU slowdown and slow 4G like Lighthouse mobile; 'none' (default): desktop, unthrottled
viewportNo
timeoutMsNoLimit per run in ms (default 60000)
waitUntilNoNavigation wait condition (default load)
cpuSlowdownNoOverride the CPU slowdown factor
projectRootNoProject whose Playwright launches the browser (default: server root)
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
actionTimeoutMsNoHow long each action waits for its element (default 10000); keep timeoutMs above the total

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
urlNo
errorNo
metricsNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/openWorldHint/idempotentHint, and the description adds meaningful context beyond them: this is a lab (headless Chromium) measurement, INP is only reported 'when actions interact', and results include rated verdicts against Google thresholds or custom budgets. It stops short of disclosing cost/runtime (each call launches a browser, so multi-run audits are slow) or that it requires a Playwright project context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Effectively one long sentence that front-loads the verb, the measured metrics, and the outputs before trailing capabilities, which is well adapted to a 20-parameter tool. It is dense and slightly run-on, and 'in headless Chromium' partially duplicates the browser parameter, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still usefully previews what comes back (ratings, locators, request lists, budget verdict) and covers measurement conditions and the optional auth/mock/interaction inputs. It omits practical prerequisites (a Playwright project root, long runtimes for multi-run medians) that an agent would want before invoking it repeatedly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 90%, so the schema already carries the parameter documentation burden. The description calls out useful capability clusters (storageState/headers for auth, actions for reaching state, routes for mocking, throttled phone, median of runs), but it adds no syntax or constraint detail beyond what the schema already says. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Measure a page's lab Web Vitals') and enumerates the exact metrics plus the derived artifacts (LCP element locators, shifting elements, heavy/render-blocking requests, budget check). This is clearly distinguishable from siblings like audit-accessibility, inspect-page, and run-test.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the mention of budgets and 'the spec' hints at CI/pre-ship gating and the throttled/median options hint at mobile profiles, but the description never says when to choose this over audit-accessibility or run-test, nor does it state prerequisites or exclusions. An agent must infer the fitting scenario.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit-testsAudit tests for flake risksA
Destructive

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) 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.

NameRequiredDescriptionDefault
fixNoRewrite the mechanical findings (web-first assertions, missing awaits, .only), re-run the touched files and restore them if the run fails
limitNoMax findings to list (default 50); the summary counts all
configNoplaywright.config path or 1-based index, for the verify run
filterNoCase-insensitive substring filter on the file path
verifyNoWith fix: re-run the touched files (default true)
testDirNoAudit only this directory (inside the project); defaults to the config testDir
timeoutMsNoWall-clock limit for the verify run
historyRunsNoHow many recent runs of the local history to weigh in (default 50)
minSeverityNoReport findings at or above this severity (default low)
projectRootNoProject directory; defaults to the server working directory

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
totalNo
appliedNo
findingsNo
verifiedNo
truncatedNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations flag destructiveHint=true and openWorldHint=true; the description earns credit by explaining exactly what destruction looks like (rewrites mechanical findings, re-runs touched files, restores on failure) — a rollback guarantee the annotations cannot convey. It stops short of noting that without fix:true the call is a non-mutating scan, and says nothing about auth or project prerequisites.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the audit purpose and its risk taxonomy, then the fix behavior. The parenthetical list is long but each item is load-bearing; no filler sentences or restated title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the mutation path is fully described including the restore-on-failure safety net. What's missing is setup context — that a Playwright project/config and local history must exist for the ranking and verify steps to work.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all ten parameters are self-documenting; baseline is 3. The description reinforces fix and hints that history weighting exists, but adds no syntax or interaction detail beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (audit Playwright test code for flake risks), enumerates the exact anti-patterns it looks for, and adds a second dimension (ranking files by historical flakiness). This is clearly distinguishable from siblings like diagnose-flaky (single failure) and analyze-history (run data only).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains what fix:true does but never states when to reach for this tool versus diagnose-flaky, analyze-history, or suggest-fix, nor any when-not conditions. Usage is implied (scan-and-optionally-repair) rather than prescribed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bisect-failureFind the commit that broke a testA
Idempotent

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.

NameRequiredDescriptionDefault
badNoA commit or ref where it fails (default HEAD)
goodNoA commit or ref where the test passed. Defaults to the newest commit in the run history where it passed
grepNoTest title (or part of it) to run inside the file; keeps the search on one test
testYesThe failing spec file, e.g. "tests/cart.spec.ts" (a :line suffix also works, but lines move between commits; prefer grep)
configNoplaywright.config path or 1-based index
repeatNoRun the test this many times per commit; any failure marks the commit bad (default 1; raise it for a flaky failure)
projectNoPlaywright project name to run in
maxStepsNoMost commits to test besides the two ends (default 12, enough for 4,000 commits)
projectRootNoProject directory (inside a git repository); defaults to the server working directory
stepTimeoutMsNoTime limit for each test run (default 180000)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
stepsNo
statusNo
firstBadNo

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=true, but the description adds important behavior not in annotations: it runs in a temporary worktree so 'your checkout is untouched', and it reports the first bad commit with diff summary and failure. It could still mention cost/duration or that it requires a git repo with runnable tests, hence 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action and results, and the second sentence packs the semantics of defaults and worktree isolation without waste. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is not required, and the description already says what is reported (first bad commit, diff summary, failure). Combined with rich parameter descriptions and annotations, an agent has enough to call this correctly and understand its side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description still adds meaning beyond schema: it explains where the 'good' default comes from (newest commit where run history saw the test pass) and implies the scope of the search. The schema already covers the remaining parameters, so this is appropriately above baseline but not exhaustive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and goal ('find the commit that broke a test') and explains the mechanism: binary-search git history between good and bad commits, running the test in a temporary worktree. This is clearly distinguishable from siblings like get-failure (report lookup) or analyze-history (history analysis).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context: 'repeat' should be raised for flaky failures, 'good' defaults to the newest passing commit from run history, and the schema description prefers grep over :line. It does not explicitly name alternatives (e.g., analyze-history or diagnose-flaky) or say when not to use it, so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check-test-changeCheck a test fix (heal guard)A
Read-onlyIdempotent

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.

NameRequiredDescriptionDefault
baseNoGit ref to compare with: 'HEAD' (default: uncommitted changes), 'origin/main' (the whole branch)
fileNoWith after: the spec file a fix would change
afterNoWith file: the fix's full new file content, checked before it is written
filesNoOnly these files (default: every changed spec file and playwright config)
projectRootNoProject directory (default: server root)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
totalNo
statusNo
findingsNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered; the description adds genuine value by disclosing the outcome model — hard BLOCK on deleted assertions, skipped/removed tests and .only, versus WARN on weaker matchers, waitForTimeout, force: true, swallowed errors and raised timeouts/retries. It does not say what the response contains, but an output schema exists to cover that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tightly packed sentences, front-loaded with the guard's purpose before modes and severity rules. The BLOCK/WARN enumeration is dense but every item carries decision-relevant information, and nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given full schema coverage and the presence of an output schema, the description supplies everything an agent needs to decide to call it: purpose, trigger, mode selection and severity semantics. Minor gap: it never clarifies scope boundaries (which files are scanned by default beyond spec files and playwright config) or whether projectRoot affects that scope.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains base, file, after, files and projectRoot. The description only adds the framing that 'file + after' is a paired mode and that base defaults to uncommitted changes, both of which are already in the schema text — baseline 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('check that changed tests were not made to pass by checking less') and immediately frames it as a guard against a concrete failure mode, which distinguishes it from siblings like suggest-fix or audit-tests. The two comparison modes (git ref vs. proposed file) further sharpen what the tool actually does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger: 'Run it after any AI fix, before committing,' plus mode selection guidance ('base' defaulting to HEAD for uncommitted changes, or file + after for a proposed fix). It does not name a sibling alternative or state when not to use it, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare-visual-stateCompare visual stateA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
harNo
urlYesFull URL of the page (or element target) to capture
nameYesBaseline id, e.g. "checkout-page" or "submit-button"
actionNo'baseline' overwrites the stored baseline; 'compare' (default) compares against it
deviceNoPlaywright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)
routesNoNetwork mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request
actionsNoSteps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows
browserNoEngine (default chromium)
channelNoBranded Chromium to launch instead of the bundled one (must be installed)
headersNoExtra HTTP headers, e.g. Authorization
waitForNoWait for this selector before capturing
fullPageNoCapture the full scrollable page (default false)
selectorNoCapture only this element (selector or locator)
viewportNo
timeoutMsNo
toleranceNoPercent of pixels that may differ before reporting a change (default 0.1)
waitUntilNo
projectRootNoProject directory; defaults to the server working directory
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
pixelThresholdNoCombined per-pixel channel delta considered different (default 60)
actionTimeoutMsNoHow long each action waits for its element (default 10000); keep timeoutMs above the total

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, openWorldHint=true and idempotentHint=true; the description adds useful output context (diff image with red highlights, bounding regions, color shift). However, it never warns that saving a baseline overwrites the stored one (a destructive act), nor mentions network/auth requirements implied by openWorldHint. It also says 'first call saves the baseline', which conflicts subtly with the schema default action='compare'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the core purpose and the report contents; every sentence carries information. Minor waste in the parenthetical color example, and the baseline sentence muddies rather than clarifies the action semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully enumerates the return contents (pixel count, regions, color shift, diff image), which is the biggest gap it needed to fill. It falls short on the baseline lifecycle and destructive overwrite semantics, which matter for a 21-parameter mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 81% and 21 parameters are documented in the schema, so the baseline score is 3. The description adds no parameter-level meaning (e.g. tolerance vs pixelThreshold interplay, when to supply storageState or actions) beyond hinting at page-vs-element capture via 'live page (or element)'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource combination ('Visual regression check: screenshot a live page (or element), compare it to a stored baseline') and describes what is reported: pixel count, bounding regions, and average color shift. This clearly separates it from siblings like inspect-page or run-test, and an agent can identify it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'First call saves the baseline; later calls compare' gives some lifecycle context, but it does not name when to prefer this tool over siblings such as inspect-page or run-test, nor when not to use it. It also sits awkwardly against the schema's `action` parameter whose default is 'compare', leaving the agent unsure whether baseline creation is automatic or must be requested explicitly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagnose-flakyDiagnose flaky testA
DestructiveIdempotent

Repeat failing tests 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.

NameRequiredDescriptionDefault
runsNoHow many times to run the tests (default 3)
orderNoAlso run the target files in `runs` random orders (Playwright 1.64+ --shuffle, one worker) to find tests that depend on what ran before them; returns the seed that reproduces it and the likely culprit test
configNoplaywright.config path or 1-based index when the project has several configs
headedNoRun with a visible browser window
browserNoPlaywright project name to run
isolateNoAlso tell parallelism bugs from real flakiness: repeat in parallel (fully parallel, `workers` default 4), then repeat the failing tests with one worker
workersNo
testFilesNoTests to diagnose ("file:line" supported). Defaults to the tests that failed in the most recent run.
timeoutMsNoHard wall-clock limit per run (default 120000); one --repeat-each process gets this × runs
projectRootNoProject directory; defaults to the server working directory
separateProcessesNoStart a fresh Playwright process per run instead of one --repeat-each process (slower; use when the flake depends on global setup or a cold start)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
testsNo
verdictNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing the execution model: repetitions run in one process by default, timeoutMs is per run and multiplied by runs for a single --repeat-each process, and separateProcesses exists for cold-start/global-setup flakes. It never addresses the destructiveHint=true implication (tests may mutate state) or permission requirements, which is the main remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and verdict taxonomy in the first sentence, then adds the two opt-in modes in a compact clause structure. It is dense and slightly long, but nearly every clause carries actionable information; only the repeated restatement of the default failed-test set is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter diagnostic tool with an output schema and annotations already present, this covers the default behavior, the two special modes, process model, and timeout semantics. An agent can call it correctly with zero configuration and understands what each verdict means.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 91%, yet the description still adds semantic value: isolate distinguishes shared-state parallelism bugs from in-test flakiness, order uses Playwright 1.64+ shuffle and returns a reproducing seed plus culprit, and defaults are restated for testFiles and runs. The 10x timeout multiplication for one process is a genuinely non-obvious clarification.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (repeat failing tests with retries disabled) and the exact output produced (per-test verdict: CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING). This clearly separates it from siblings like run-test and bisect-failure, which do not produce evidence-based flakiness verdicts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the default target set (tests that failed in the most recent run) and when to reach for the isolate and order modes, including the diagnostic question each answers. It does not explicitly say when to prefer this over bisect-failure or run-test, so the alternatives routing is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate-e2e-testGenerate an E2E testA
Destructive

Scaffold a Playwright test 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.

NameRequiredDescriptionDefault
fileNoExact spec path (*.spec.ts / *.test.ts) inside the project instead of the default location
stepsNoWalk the flow: run these steps on the live page first, then write a spec that replays them and asserts the end state
writeNoWrite the file to disk (default true)
configNoplaywright.config path or 1-based index
verifyNosteps: run the written spec once to prove it passes (default true)
pageUrlNoPage the test starts on (default: baseURL from playwright.config)
projectNosteps: Playwright project for the verification run
testDirNoDirectory for the generated spec (default: detected testDir or tests/)
overwriteNoReplace an existing spec at the target path (only specs this tool generated)
timeoutMsNo
assertScopeNosteps: CSS scope of the end-state aria snapshot (default 'body')
descriptionYesWhat the test should cover, e.g. "login with valid credentials"
liveInspectNoVerify discovered selectors against the live page (default true when a URL is known)
projectRootNoProject directory; defaults to the server working directory
storageStateNosteps: signed-in session file, also used by the spec

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (destructive, openWorld, non-idempotent), the description discloses real side effects: it writes a spec to disk, optionally runs that spec once to prove it passes, hits the live page, and overwrites only specs it generated. It does not cover prerequisites (Playwright/browser availability), what happens on failure of the verification run, or timeout behavior, so it stops short of full disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action before the mechanism, so the agent gets the headline immediately. The second sentence is dense with nested parentheticals and could be split, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 15 parameters, no output schema, and two operating modes that write files and execute a browser, this is a complex tool and the description covers both modes plus the returned 'next steps'. The main gaps are failure semantics of the verification run and any environment prerequisites, which matter for a destructive, open-world tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 93%, so the baseline is 3 and the schema carries parameter meaning. The description still adds value the schema cannot: it explains the semantic coupling between `steps`, `verify`, `assertScope`, `storageState`, and the end-state assertions the generated spec will contain, which tells the agent how those parameters interact.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and artifact: 'Scaffold a Playwright test from a description using the project's REAL selectors', then enumerates the concrete mechanism (git scan, locator extraction, live cross-check, spec write). It also carves out a distinct second mode ('with `steps` it walks the flow on the live page instead'), so an agent can tell this apart from run-test, validate-selector, or inspect-page without reading any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Mode selection is explicit: no `steps` produces a scaffolded spec from discovered selectors; with `steps` the tool walks the flow live, then replays and verifies it. What is missing is routing to siblings — nothing says when to prefer inspect-page or validate-selector, or that run-test is for re-running an existing spec rather than generating one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get-failureAnalyze a test failureA
Read-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.

NameRequiredDescriptionDefault
indexNo1-based failure index from the last run (default 1)
projectRootNoOnly used to re-read the stored report

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
indexNo
totalNo
failureNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/closed-world; the description adds the important behavioral fact that the tool only reads the most recent run-test execution, so it is state-dependent on a prior call. It stops short of saying what happens when no run exists or how failures are indexed across runs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action and scope, followed by a short prerequisite directive. The dense enumeration of returned artifacts is high-value rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return shapes, yet it usefully summarizes them and flags the run-test dependency. The remaining gap is error-state behavior (no prior run, out-of-range index) and how it relates to overlapping siblings such as suggest-fix.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, including the 1-based index and the 'only used to re-read the stored report' note for projectRoot, so the schema carries parameter meaning. The description only adds the contextual fact that the index refers to the last run, which is a marginal gain over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Analyze one failure from the most recent run-test execution') and enumerates exactly what comes back: message, code frame, expected vs actual, stack trace, network/console errors, failure kind, next steps. The failure-kind taxonomy (assertion/timeout/browser-crash/syntax/config/server-unreachable) makes it unmistakable versus siblings like suggest-fix or bisect-failure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use run-test first' states the prerequisite explicitly, and 'most recent run-test execution' tells the agent which run is targeted. It does not name alternatives or exclusions (e.g., when to prefer suggest-fix or bisect-failure for recurring failures), so it falls short of a full when/when-not statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get-run-statusCheck a background runA
Idempotent

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.

NameRequiredDescriptionDefault
runIdNo
cancelNo
waitSecondsNoWait up to this long for it to finish

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
runNo
errorNo
runIdNo
statusNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare non-readOnly, idempotent, non-destructive, so the description doesn't need to re-establish safety. It does add useful behavior beyond that: cancel actually stops the run, waitSeconds blocks, and the final result becomes the last run consumed by get-failure — a cross-tool side effect worth knowing. Missing are the cost of polling/blocking limits and error behavior for an unknown runId.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short clauses with no filler, and the primary payload (progress/final result) is front-loaded. The telegraphic style ('waitSeconds waits; cancel stops it') and the dangling 'Default: the latest run' cost a bit of clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be described, and the description still sketches what progress contains (tests done/total, failures so far). What remains thin is the polling/blocking contract and error cases; for a 3-param, 0-required polling tool this is close to complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33% (only waitSeconds is documented in-schema), so the description must compensate — and it does, covering all three parameters: waitSeconds waits, cancel stops the run, and the default (no runId) means the latest run. It does not give the runId format or the origin of the runId, which keeps it below 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names the specific verb/resource (progress or final result of a run-test background run) and scopes it to runs started by the run-test sibling. The relationship to get-failure is stated, so an agent can place it in the workflow. Slightly clipped phrasing ('Progress ... or the final result') keeps it from being a model 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is strongly implied: call this after run-test to poll progress, and the default is the latest run. However, there is no explicit when-to-use/when-not statement and no alternative named for the same job (e.g., versus get-failure directly).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

inspect-pageInspect live page DOMA
Read-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. view 'locators' is the compact map; view 'aria' returns the accessibility snapshot plus a ready toMatchAriaSnapshot assertion.

NameRequiredDescriptionDefault
harNo
urlYesFull URL of the page to open (http/https)
viewNo'locators': compact map of interactive elements (cheapest); 'aria': accessibility snapshot + toMatchAriaSnapshot check (scoped by selector); 'elements' (default): DOM inventory
deviceNoPlaywright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)
routesNoNetwork mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request
actionsNoSteps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows
browserNoEngine (default chromium)
channelNoBranded Chromium to launch instead of the bundled one (must be installed)
headersNoExtra HTTP headers, e.g. Authorization
waitForNoWait for this selector first
selectorNoCSS selector: inspect matches instead of the whole DOM
viewportNo
timeoutMsNoOverall inspection limit in ms (default 45000)
waitUntilNoNavigation wait condition (default domcontentloaded)
includeHtmlNoInclude the rendered HTML (truncated)
projectRootNoProject whose Playwright launches the browser (default: server root)
maxHtmlCharsNoHTML cap when includeHtml is set (default 20000)
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
actionTimeoutMsNoHow long each action waits for its element (default 10000); keep timeoutMs above the total

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, openWorld), and the description adds genuinely non-obvious traits beyond them: a fresh browser per call with no cookie persistence, locators proven unique on the page, and console messages included in the result. It does not discuss failure modes or limits on page complexity, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action and output, then the state-isolation caveat, then view modes. Dense but each sentence earns its place; the parenthetical detail in sentence one makes it slightly heavy but not wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 19 parameters, nested objects, and no output schema, the description does useful work by summarizing the return shape (locators with role+name priority, CSS selectors, visibility, text, console messages) and warning about browser state isolation. It leaves deeper parameter behavior to the schema, which is reasonable given high coverage, but a few more words on the actions flow would close the gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 89%, so the schema carries most parameter meaning and the baseline is 3. The description adds context for 'view' ('locators' is the cheapest compact map) and hints at the actions-vs-storageState tradeoff, but does not illuminate the remaining 19 parameters such as har, routes, or timeoutMs beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Open a URL in a fresh headless browser') and then enumerates what comes back: elements, unique Playwright locators, CSS selectors, visibility, text, console messages. This is far more specific than a title restatement and clearly separates it from sibling test-authoring tools like validate-selector or generate-e2e-test, though no sibling is named directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives real operating guidance: each call starts clean with no cookies, so either encode the full path in 'actions' or reuse a session via storageState/headers. Also steers view selection ('locators' is the compact map, 'aria' returns the snapshot plus assertion). It stops short of naming explicit alternatives or exclusions among the sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list-testsList available testsA
Read-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.

NameRequiredDescriptionDefault
limitNoMax tests to return (default 500)
configNoplaywright.config path or 1-based index when the project has several configs
filterNoCase-insensitive substring filter on "file › title"
testDirNoRestrict scanning to this directory (inside the project)
projectRootNoProject directory; defaults to the server working directory

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
testsNo
totalNo
truncatedNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, closed-world), so the real added value is the disclosed dual strategy: `playwright test --list` with a source-scan fallback when the install or config is broken, plus a reason being reported. That is genuinely useful behavioral context an agent cannot get from the annotations, though it doesn't say what the fallback loses (e.g., whether projects line up).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero waste. The primary behavior is front-loaded and the fallback caveat is packed into a compact second clause without redundant restatement of the name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and the description still sketches them. Combined with the fallback disclosure it is close to complete; the only soft spot is that multi-config resolution behavior (the `config` index parameter) is left entirely to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every one of the five parameters is already documented in the schema and baseline 3 applies. The description only adds the notion of 'optional filtering' and the returned tuple of fields; it adds no semantics for config, testDir, projectRoot, or the default limit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb plus resource ('List the Playwright tests available in the project') and it even enumerates the returned fields (file, line, full title, projects). It is clearly distinguishable in practice from run-test or audit-tests, but it never names a sibling or states that boundary explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied — an agent can infer this is a discovery step before run-test, but the description never says when to reach for it versus audit-tests, diagnose-flaky, or analyze-history. The 'optional filtering' phrase hints at narrowing results without stating when that matters.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

load-reportLoad a CI reportA

Load a Playwright run that happened elsewhere (a CI job's JSON report, or a folder of blob reports from shards) 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.

NameRequiredDescriptionDefault
branchNo
commitNoCommit the run tested (default: read from the report metadata)
recordNoAdd the run to the local history for analyze-history (default true)
reportYesPlaywright JSON report inside the project (e.g. ci-artifacts/results.json), or a folder of blob reports (*.zip) from sharded jobs
timeoutMsNoLimit for merging blob reports (default 120000)
traceDirsNoFolders inside the project where the job's test-results artifact was unpacked (default: the report's folder and its parent)
projectRootNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare that this is a non-read-only, non-destructive, non-idempotent operation. The description adds important behavioral context beyond that: CI paths are mapped onto the checkout, traces are found in the unpacked test-results artifact, and the run is recorded in local history with its commit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded, moving immediately from the load operation to the supporting behavior. Every clause adds useful information with no repetition or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a seven-parameter tool with no output schema, the description supplies the key mental model: importing an external run, mapping paths, locating traces, and recording history. It leaves minor gaps around branch/projectRoot and record=false behavior, but the overall context is sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, so most parameters are already documented. The description adds value by clarifying the report format (JSON file or blob folder), trace directory discovery, and that the commit is recorded with the run, though it does not cover branch or projectRoot.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: loading a Playwright run that happened elsewhere, from either a CI JSON report or a folder of blob reports. It also names the downstream tools enabled by it (get-failure, suggest-fix, diagnose-flaky), making its role distinct from run-test.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly explains when to use this tool: when you have a CI job's JSON report or sharded blob reports and want them treated like a local run. It does not explicitly exclude alternatives or say when not to use it, but the context is sufficiently clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

quarantineQuarantine flaky testsA
Idempotent

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).

NameRequiredDescriptionDefault
daysNoadd: how long it counts (default 14, max 90)
fileNoSpec file, relative to the project
testNoThe test as 'file › title' (as get-failure and analyze-history print it), or use file + title
indexNoadd: the Nth failure of the last run instead of test/file/title
ownerNoadd: who will fix it (name or @handle)
titleNoTest title, or its last parts ('Checkout › pays by card')
actionNo'list' (default), 'add' or 'remove'
reasonNoadd: why it is flaky, or the issue link
projectRootNoProject directory (default: server root)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
errorNo
totalNo
statusNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing the actual side effect (failures stop failing run-test and ci), the expiry window (default 14, max 90 days), and persistence in playwright-quarantine.json with a commit instruction. The write-to-file behavior is consistent with readOnlyHint=false and idempotentHint=true, and nothing contradicts destructiveHint=false since removal is scoped and reversible.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

About 60 words, front-loaded with the core effect, then per-action semantics, then storage location. Every clause carries information: expiry limits, required fields, persistence file, and the commit reminder.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter, multi-action mutation tool with full schema coverage, an output schema, and annotations, the description supplies the missing pieces: action semantics, expiry behavior, the file that must be committed, and which fields add requires. An agent can call this correctly without further information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3; the description adds real value by stating that add needs owner and reason, which the schema does not enforce (zero required parameters). It also reiterates the days default/max and the add/list/remove action semantics, mapping parameters to actions rather than just restating them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description defines a specific verb+resource ('Quarantine flaky tests') and explains precisely what quarantine means: tests keep running and reporting, but failures no longer fail run-test or the ci command. That definition implicitly separates it from siblings like diagnose-flaky or get-failure, though no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Each action has a clear role: add requires owner and reason, list shows quarantined and expired entries, remove ends an entry. The context (a known flaky test) is clear, but there is no explicit exclusion such as 'use diagnose-flaky first to confirm flakiness' or advice on when quarantine is inappropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run-testRun E2E testsA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
argsNoExtra Playwright flags from an allowlist, as --flag or --flag=value (e.g. --repeat-each=3, --shard=1/2, --trace=on)
grepNoOnly run tests whose title matches this regex
configNoplaywright.config path or 1-based index when the project has several configs
headedNoRun with a visible browser window
browserNoPlaywright project name to run (matched against playwright.config projects)
retriesNo
workersNo
testFilesNoTest files/directories relative to the project root; "file:line" is supported. Omit to run the whole suite.
timeoutMsNoHard wall-clock limit for the whole run; the process tree is killed past it (default 120000)
backgroundNoReturn a run id at once; poll get-run-status
lastFailedNoOnly re-run tests that failed in the previous run (Playwright --last-failed) — the fast fix → re-run loop
projectRootNoProject directory; defaults to the server working directory
testTimeoutMsNoPer-test timeout passed to Playwright
retryOnFailureNoAuto retry failing tests once before reporting failure (default true; ignored when retries is set)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
runNo
errorNo
runIdNo
statusNo

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and openWorldHint=true, but the description supplies the operative detail: it diagnoses missing installs, dead dev servers, syntax errors, crashes and timeouts, kills the process tree on timeout while keeping partial results, emits progress, and persists runs for later analysis. That is materially more than the annotation flags convey and explains exactly why the tool is flagged destructive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the verb/resource and result format, with no filler. The middle sentence is a dense comma-list ('missing installs, dead dev servers, syntax errors, crashes and timeouts') that is information-rich but slightly run-on compared to the crisp opener.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and annotations cover the safety profile; the description adds failure-mode, background, and persistence behavior. It is essentially complete for invocation, though it never clarifies the fast re-run loop (lastFailed) or the interaction between retries and retryOnFailure, both of which live only in schema text.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 86%, so parameters are already well documented and the baseline is 3. The description's parameter-related content ('background: true returns a run id', process tree killed past the limit) largely restates the schema text for background and timeoutMs rather than adding new semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Run the project's Playwright tests') and immediately defines the output shape: stats plus each failure's file:line, kind and message. It is clearly distinguishable from siblings like list-tests (enumeration only) and get-run-status (polling), the latter of which is named explicitly for the background case.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use cues: 'background: true returns a run id for long suites' and 'Runs are recorded for analyze-history', which routes the agent to the right follow-up tool. It does not state exclusions, e.g. that list-tests should be used to discover tests before running a subset, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save-loginSave a login sessionA
Idempotent

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).

NameRequiredDescriptionDefault
urlYesLogin page URL (http/https)
nameNoSession name, e.g. 'admin' (default 'user'); saved to playwright/.auth/<name>.json
pathNoWhere to save the storageState JSON inside the project (overrides name)
reuseNoKeep a saved session that still passes verify instead of logging in again (default true)
verifyNoHow to tell the session works; also used to decide whether a saved session is still valid
actionsNoLogin steps. In fill values write {{env:E2E_PASSWORD}} for a secret from the environment and {{totp}} for an authenticator code, never the secret itself. End with a 'wait' on something only signed-in users see
headersNoExtra HTTP headers
viewportNo
timeoutMsNoOverall limit in ms (default 60000)
projectRootNoProject directory (default: server root)
totpSecretEnvNoEnvironment variable holding the authenticator secret (base32 or otpauth:// URI), for {{totp}}
actionTimeoutMsNoHow long each step waits for its element (default 10000)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
urlNo
pathNosave-login: the storageState file, relative to the project
errorNo
validNovalidate-selector: the selector parsed and ran
statusNo
expiresAtNosave-login: when the first session cookie expires (ISO)

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotent, non-destructive, open-world) it discloses the file write and its default location, the conditional re-login behavior driven by verify, and how secrets are kept out of chat via {{env:...}} and {{totp}}. What is missing is failure/error behavior (e.g., what happens when verify never passes).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences, front-loaded with the core action and destination path before the reuse and secret-handling details. Nothing is filler, though the second and third sentences pack several distinct ideas that could be split for scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter tool with nested action/verify objects the description covers the concepts an agent most needs: what is produced, where, reuse semantics, and secret templating; an output schema exists so return values need no explanation. Edge cases such as timeout expiry or directory creation are left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 92%, so the baseline is a 3; the description still adds real meaning by explaining the fill-value templating, tying {{totp}} to totpSecretEnv, and prescribing that actions should end with a 'wait' on a signed-in-only element. That is guidance the schema does not encode.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb+resource (log in once and save the session as a storageState file) and states the default destination path, so an agent knows exactly what artifact the tool produces. It also contrasts with the rest of the suite ('for tests and the page tools'), making the tool's role distinct from siblings like inspect-page or run-test.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the reuse policy ('if a saved session still passes verify it is reused; expired ones log in again') and its consumer contexts (tests, page tools), which tells an agent when to reach for it. It stops short of explicit exclusions or naming an alternative tool for one-off interactive browsing, so it isn't a full when/when-not map.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

suggest-fixSuggest (and apply) a fixA
Destructive

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).

NameRequiredDescriptionDefault
urlNoHeal against this live page instead of the trace snapshot
applyNoWrite the fix (default: diff only)
indexNo1-based failure index (default 1)
configNoplaywright.config path or 1-based index
verifyNoRe-run after applying; revert if still failing (default true)
headersNoExtra HTTP headers, e.g. Authorization
candidateNoStrict mode violation: which of the listed matches the test meant (1-based)
timeoutMsNoVerification run limit (default 120000)
projectRootNo
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
allowExpectationUpdateNoAllow applying changed expected text (can hide regressions)

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
fixNo
errorNo
appliedNo
verifiedNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: it matches against the DOM at failure time via trace or live URL, returns a diff and confidence, and apply:true writes, re-runs, and reverts if still red. This aligns with destructiveHint=true and clarifies the safety net (auto-revert) and refusal case. It could still state whether a destructive apply requires confirmation or what confidence values mean, but the core mutation semantics are disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the action and scope, then the fix classes, then the write/verify contract and refusal condition. Dense but no redundant clauses; every sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 11 optional parameters, an output schema, and rich annotations, the description covers the essential decision points: what it patches, what it returns, what apply does, and when it refuses. Minor gaps remain around prerequisites for live-URL healing (auth via storageState/headers) and what the confidence score means for deciding to apply.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 91% schema coverage, the schema already defines url, apply, verify, candidate, and allowExpectationUpdate individually. The description's value is integrative ('apply: true writes it, re-runs the test and reverts if still red'), which connects apply and verify but largely restates what those parameter descriptions say. No additional syntax or conditional-requirement detail (e.g., when storageState/headers are needed) is given.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Patch a failure from the last run') and enumerates the three fix classes it handles: drifted locator, strict-mode multi-match, and changed copy. This clearly separates it from siblings like get-failure (read the failure) or validate-selector (check a selector).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Establishes the precondition (a failure from the last run) and one explicit exclusion ('Refuses when the element is truly missing (app bug)'). It doesn't name sibling alternatives such as get-failure or validate-selector, so routing is implied rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate-selectorValidate selector or locatorA
Read-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.

NameRequiredDescriptionDefault
harNo
urlYesFull URL of the live page to test against (http/https)
deviceNoPlaywright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)
routesNoNetwork mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request
actionsNoSteps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows
browserNoEngine (default chromium)
channelNoBranded Chromium to launch instead of the bundled one (must be installed)
headersNoExtra HTTP headers, e.g. Authorization
waitForNoWait for this selector to be visible first (for elements that render late)
selectorYesSelector or locator, e.g. getByRole('button', { name: 'Save' })
viewportNo
timeoutMsNoOverall limit in ms (default 45000)
projectRootNoProject whose Playwright launches the browser (default: server root)
storageStateNoLogged-in session: storageState JSON inside the project, e.g. playwright/.auth/user.json
actionTimeoutMsNoHow long each action waits for its element (default 10000); keep timeoutMs above the total

Output Schema

NameRequiredDescription
okYesfalse when the call failed (see error) or the tests it ran failed
urlNo
errorNo
validNovalidate-selector: the selector parsed and ran
locatorNoa verified unique locator for the first match
matchesNoelements matched; actions need exactly 1
httpStatusNothe page's HTTP status

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld, and the description adds real behavior beyond them: it runs against a live page, counts once after load, and returns a sturdier verified locator per match. Session and header requirements are hinted via storageState/headers but not explained further.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose, then the key caveat, then a compact list of what is accepted. Every parenthetical example earns its place by defining valid locator forms.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return values, and it still summarizes them usefully. For a 15-parameter live-page tool it covers the essentials, though auth expectations and timeout interplay are only partially touched.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is high (87%), so the baseline is 3, but the description adds meaning by tying waitFor/actions to the late-element case and by spelling out the accepted locator syntax (getByRole, .first(), .filter(), frameLocator()). Other parameters are left entirely to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Check a CSS selector, Playwright selector or locator ... on a live page') and enumerates the outputs (validity, match count, sample matches, verified locator). It is clear what the tool does, but it never explicitly distinguishes itself from neighbors like inspect-page or run-test.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives actionable guidance: 'Counts once after load: use waitFor or actions for late elements,' and notes that actions need exactly 1 match. It stops short of naming an alternative tool or stating when not to use this one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.7.0
    • Changedanalyze-history1 field changed
      • addedInput schema / properties / source
        Added value: +{
        +  "description": "With a Pro key: 'both' (default) merges this machine's runs with CI runs from Pro Cloud; 'cloud' or 'local' for one side",
        +  "enum": [
        +    "local",
        +    "cloud",
        +    "both"
        +  ],
        +  "type": "string"
        +}
    • Addedcheck-test-change
    • Changedget-run-status1 field changed
      • addedOutput schema / properties / run / properties / quarantined
        Added value: +{
        +  "description": "failures covered by an active quarantine entry (they do not fail the run)",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Addedquarantine
    • Changedrun-test1 field changed
      • addedOutput schema / properties / run / properties / quarantined
        Added value: +{
        +  "description": "failures covered by an active quarantine entry (they do not fail the run)",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Addedsave-login
  2. 16 tool updatesv0.6.1
    • Changedanalyze-history3 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedInput schema / properties / view / description
        Previous value: -"Default 'flaky'"New value: +"Default 'flaky'; 'slow' ranks durations, 'trend' is per day, 'commits' names the commit each test went bad"
      • changedInput schema / properties / view / enum
        Previous value: -[
        -  "flaky",
        -  "patterns",
        -  "test"
        -]New value: +[
        +  "flaky",
        +  "patterns",
        +  "test",
        +  "slow",
        +  "trend",
        +  "commits"
        +]
    • Changedaudit-accessibility9 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actionTimeoutMs
        Added value: +{
        +  "description": "How long each action waits for its element (default 10000); keep timeoutMs above the total",
        +  "maximum": 120000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • changedInput schema / properties / actions / description
        Previous value: -"Steps run after load to reach a state (modal, step 3)"New value: +"Steps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows"
      • addedInput schema / properties / browser
        Added value: +{
        +  "description": "Engine (default chromium)",
        +  "enum": [
        +    "chromium",
        +    "firefox",
        +    "webkit"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / channel
        Added value: +{
        +  "description": "Branded Chromium to launch instead of the bundled one (must be installed)",
        +  "enum": [
        +    "chrome",
        +    "chrome-beta",
        +    "msedge",
        +    "msedge-beta"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / device
        Added value: +{
        +  "description": "Playwright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)",
        +  "maxLength": 60,
        +  "minLength": 2,
        +  "type": "string"
        +}
      • addedInput schema / properties / har
        Added value: +{
        +  "properties": {
        +    "mode": {
        +      "description": "'replay' (default) answers requests from the file; 'record' saves the traffic",
        +      "enum": [
        +        "replay",
        +        "record"
        +      ],
        +      "type": "string"
        +    },
        +    "notFound": {
        +      "description": "replay: requests missing from the file abort (default) or go to the network",
        +      "enum": [
        +        "abort",
        +        "fallback"
        +      ],
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": ".har or .zip inside the project",
        +      "maxLength": 500,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "url": {
        +      "description": "Glob limiting the requests, e.g. '**/api/**'",
        +      "maxLength": 500,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "path"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / routes
        Added value: +{
        +  "description": "Network mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request",
        +  "items": {
        +    "properties": {
        +      "abort": {
        +        "type": "boolean"
        +      },
        +      "body": {
        +        "maxLength": 200000,
        +        "type": "string"
        +      },
        +      "contentType": {
        +        "maxLength": 100,
        +        "type": "string"
        +      },
        +      "delayMs": {
        +        "maximum": 10000,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "headers": {
        +        "additionalProperties": {
        +          "type": "string"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "json": {},
        +      "method": {
        +        "maxLength": 10,
        +        "type": "string"
        +      },
        +      "status": {
        +        "maximum": 599,
        +        "minimum": 100,
        +        "type": "integer"
        +      },
        +      "url": {
        +        "description": "Glob, e.g. '**/api/cart'",
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "url": {
        +      "type": "string"
        +    },
        +    "violations": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "help": {
        +            "type": "string"
        +          },
        +          "helpUrl": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "type": "string"
        +          },
        +          "impact": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "impact",
        +          "help",
        +          "helpUrl",
        +          "count"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Addedaudit-performance
    • Addedaudit-tests
    • Addedbisect-failure
    • Changedcompare-visual-state8 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actionTimeoutMs
        Added value: +{
        +  "description": "How long each action waits for its element (default 10000); keep timeoutMs above the total",
        +  "maximum": 120000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • changedInput schema / properties / actions / description
        Previous value: -"Steps run after load to reach a state (modal, step 3)"New value: +"Steps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows"
      • addedInput schema / properties / browser
        Added value: +{
        +  "description": "Engine (default chromium)",
        +  "enum": [
        +    "chromium",
        +    "firefox",
        +    "webkit"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / channel
        Added value: +{
        +  "description": "Branded Chromium to launch instead of the bundled one (must be installed)",
        +  "enum": [
        +    "chrome",
        +    "chrome-beta",
        +    "msedge",
        +    "msedge-beta"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / device
        Added value: +{
        +  "description": "Playwright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)",
        +  "maxLength": 60,
        +  "minLength": 2,
        +  "type": "string"
        +}
      • addedInput schema / properties / har
        Added value: +{
        +  "properties": {
        +    "mode": {
        +      "description": "'replay' (default) answers requests from the file; 'record' saves the traffic",
        +      "enum": [
        +        "replay",
        +        "record"
        +      ],
        +      "type": "string"
        +    },
        +    "notFound": {
        +      "description": "replay: requests missing from the file abort (default) or go to the network",
        +      "enum": [
        +        "abort",
        +        "fallback"
        +      ],
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": ".har or .zip inside the project",
        +      "maxLength": 500,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "url": {
        +      "description": "Glob limiting the requests, e.g. '**/api/**'",
        +      "maxLength": 500,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "path"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / routes
        Added value: +{
        +  "description": "Network mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request",
        +  "items": {
        +    "properties": {
        +      "abort": {
        +        "type": "boolean"
        +      },
        +      "body": {
        +        "maxLength": 200000,
        +        "type": "string"
        +      },
        +      "contentType": {
        +        "maxLength": 100,
        +        "type": "string"
        +      },
        +      "delayMs": {
        +        "maximum": 10000,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "headers": {
        +        "additionalProperties": {
        +          "type": "string"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "json": {},
        +      "method": {
        +        "maxLength": 10,
        +        "type": "string"
        +      },
        +      "status": {
        +        "maximum": 599,
        +        "minimum": 100,
        +        "type": "integer"
        +      },
        +      "url": {
        +        "description": "Glob, e.g. '**/api/cart'",
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
    • Changeddiagnose-flaky2 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "tests": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "failed": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "file": {
        +            "type": "string"
        +          },
        +          "line": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "passed": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "project": {
        +            "type": "string"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "verdict": {
        +            "enum": [
        +              "NOT REPRODUCING",
        +              "FLAKY",
        +              "CONSISTENTLY FAILING",
        +              "NO TESTS RAN"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "file",
        +          "title"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "verdict": {
        +      "enum": [
        +        "NOT REPRODUCING",
        +        "FLAKY",
        +        "CONSISTENTLY FAILING",
        +        "NO TESTS RAN"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Changedgenerate-e2e-test7 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / assertScope
        Added value: +{
        +  "description": "steps: CSS scope of the end-state aria snapshot (default 'body')",
        +  "maxLength": 200,
        +  "type": "string"
        +}
      • addedInput schema / properties / project
        Added value: +{
        +  "description": "steps: Playwright project for the verification run",
        +  "type": "string"
        +}
      • addedInput schema / properties / steps
        Added value: +{
        +  "description": "Walk the flow: run these steps on the live page first, then write a spec that replays them and asserts the end state",
        +  "items": {
        +    "properties": {
        +      "locator": {
        +        "description": "Locator or selector, e.g. getByRole('button', { name: 'Next' })",
        +        "type": "string"
        +      },
        +      "ms": {
        +        "description": "wait without locator",
        +        "maximum": 10000,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "enum": [
        +          "goto",
        +          "click",
        +          "dblclick",
        +          "hover",
        +          "fill",
        +          "press",
        +          "check",
        +          "uncheck",
        +          "select",
        +          "wait"
        +        ],
        +        "type": "string"
        +      },
        +      "url": {
        +        "description": "goto target (may be relative)",
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "fill text, press key, select option",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 30,
        +  "type": "array"
        +}
      • addedInput schema / properties / storageState
        Added value: +{
        +  "description": "steps: signed-in session file, also used by the spec",
        +  "type": "string"
        +}
      • addedInput schema / properties / timeoutMs
        Added value: +{
        +  "maximum": 600000,
        +  "minimum": 5000,
        +  "type": "integer"
        +}
      • addedInput schema / properties / verify
        Added value: +{
        +  "description": "steps: run the written spec once to prove it passes (default true)",
        +  "type": "boolean"
        +}
    • Changedget-failure2 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "failure": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "actual": {
        +          "type": "string"
        +        },
        +        "expected": {
        +          "type": "string"
        +        },
        +        "file": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "line": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "message": {
        +          "type": "string"
        +        },
        +        "project": {
        +          "type": "string"
        +        },
        +        "title": {
        +          "type": "string"
        +        },
        +        "tracePath": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "file",
        +        "title",
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "index": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "total": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Changedget-run-status2 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "run": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "durationMs": {
        +          "type": "number"
        +        },
        +        "exitCode": {
        +          "anyOf": [
        +            {
        +              "maximum": 9007199254740991,
        +              "minimum": -9007199254740991,
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "failed": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "failures": {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "file": {
        +                "type": "string"
        +              },
        +              "kind": {
        +                "type": "string"
        +              },
        +              "line": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "message": {
        +                "type": "string"
        +              },
        +              "project": {
        +                "type": "string"
        +              },
        +              "title": {
        +                "type": "string"
        +              },
        +              "tracePath": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "file",
        +              "title",
        +              "kind",
        +              "message"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "failuresTruncated": {
        +          "type": "boolean"
        +        },
        +        "flaky": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "partial": {
        +          "type": "boolean"
        +        },
        +        "passed": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "skipped": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "passed",
        +        "failed",
        +        "flaky",
        +        "skipped",
        +        "durationMs",
        +        "exitCode",
        +        "partial",
        +        "failures"
        +      ],
        +      "type": "object"
        +    },
        +    "runId": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Changedinspect-page10 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actionTimeoutMs
        Added value: +{
        +  "description": "How long each action waits for its element (default 10000); keep timeoutMs above the total",
        +  "maximum": 120000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • changedInput schema / properties / actions / description
        Previous value: -"Steps run after load to reach a state (modal, step 3)"New value: +"Steps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows"
      • addedInput schema / properties / browser
        Added value: +{
        +  "description": "Engine (default chromium)",
        +  "enum": [
        +    "chromium",
        +    "firefox",
        +    "webkit"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / channel
        Added value: +{
        +  "description": "Branded Chromium to launch instead of the bundled one (must be installed)",
        +  "enum": [
        +    "chrome",
        +    "chrome-beta",
        +    "msedge",
        +    "msedge-beta"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / device
        Added value: +{
        +  "description": "Playwright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)",
        +  "maxLength": 60,
        +  "minLength": 2,
        +  "type": "string"
        +}
      • addedInput schema / properties / har
        Added value: +{
        +  "properties": {
        +    "mode": {
        +      "description": "'replay' (default) answers requests from the file; 'record' saves the traffic",
        +      "enum": [
        +        "replay",
        +        "record"
        +      ],
        +      "type": "string"
        +    },
        +    "notFound": {
        +      "description": "replay: requests missing from the file abort (default) or go to the network",
        +      "enum": [
        +        "abort",
        +        "fallback"
        +      ],
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": ".har or .zip inside the project",
        +      "maxLength": 500,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "url": {
        +      "description": "Glob limiting the requests, e.g. '**/api/**'",
        +      "maxLength": 500,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "path"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / routes
        Added value: +{
        +  "description": "Network mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request",
        +  "items": {
        +    "properties": {
        +      "abort": {
        +        "type": "boolean"
        +      },
        +      "body": {
        +        "maxLength": 200000,
        +        "type": "string"
        +      },
        +      "contentType": {
        +        "maxLength": 100,
        +        "type": "string"
        +      },
        +      "delayMs": {
        +        "maximum": 10000,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "headers": {
        +        "additionalProperties": {
        +          "type": "string"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "json": {},
        +      "method": {
        +        "maxLength": 10,
        +        "type": "string"
        +      },
        +      "status": {
        +        "maximum": 599,
        +        "minimum": 100,
        +        "type": "integer"
        +      },
        +      "url": {
        +        "description": "Glob, e.g. '**/api/cart'",
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
      • changedInput schema / properties / view / description
        Previous value: -"'locators': compact map of interactive elements (cheapest); 'elements' (default): DOM inventory"New value: +"'locators': compact map of interactive elements (cheapest); 'aria': accessibility snapshot + toMatchAriaSnapshot check (scoped by selector); 'elements' (default): DOM inventory"
      • changedInput schema / properties / view / enum
        Previous value: -[
        -  "elements",
        -  "locators"
        -]New value: +[
        +  "elements",
        +  "locators",
        +  "aria"
        +]
    • Changedlist-tests2 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "tests": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "failed": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "file": {
        +            "type": "string"
        +          },
        +          "line": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "passed": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "project": {
        +            "type": "string"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "verdict": {
        +            "enum": [
        +              "NOT REPRODUCING",
        +              "FLAKY",
        +              "CONSISTENTLY FAILING",
        +              "NO TESTS RAN"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "file",
        +          "title"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "total": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "truncated": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Addedload-report
    • Changedrun-test2 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "run": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "durationMs": {
        +          "type": "number"
        +        },
        +        "exitCode": {
        +          "anyOf": [
        +            {
        +              "maximum": 9007199254740991,
        +              "minimum": -9007199254740991,
        +              "type": "integer"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "failed": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "failures": {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "file": {
        +                "type": "string"
        +              },
        +              "kind": {
        +                "type": "string"
        +              },
        +              "line": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "message": {
        +                "type": "string"
        +              },
        +              "project": {
        +                "type": "string"
        +              },
        +              "title": {
        +                "type": "string"
        +              },
        +              "tracePath": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "file",
        +              "title",
        +              "kind",
        +              "message"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "failuresTruncated": {
        +          "type": "boolean"
        +        },
        +        "flaky": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "partial": {
        +          "type": "boolean"
        +        },
        +        "passed": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "skipped": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "passed",
        +        "failed",
        +        "flaky",
        +        "skipped",
        +        "durationMs",
        +        "exitCode",
        +        "partial",
        +        "failures"
        +      ],
        +      "type": "object"
        +    },
        +    "runId": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Changedsuggest-fix3 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / candidate
        Added value: +{
        +  "description": "Strict mode violation: which of the listed matches the test meant (1-based)",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "applied": {
        +      "type": "boolean"
        +    },
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "fix": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "after": {
        +          "type": "string"
        +        },
        +        "alternatives": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "before": {
        +          "type": "string"
        +        },
        +        "confidence": {
        +          "type": "string"
        +        },
        +        "file": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "enum": [
        +            "locator",
        +            "expectation"
        +          ],
        +          "type": "string"
        +        },
        +        "line": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "why": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "file",
        +        "line",
        +        "before",
        +        "after",
        +        "kind",
        +        "confidence",
        +        "why"
        +      ],
        +      "type": "object"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "verified": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
    • Changedvalidate-selector10 fields changed
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actionTimeoutMs
        Added value: +{
        +  "description": "How long each action waits for its element (default 10000); keep timeoutMs above the total",
        +  "maximum": 120000,
        +  "minimum": 1000,
        +  "type": "integer"
        +}
      • changedInput schema / properties / actions / description
        Previous value: -"Steps run after load to reach a state (modal, step 3)"New value: +"Steps run in order after load to reach a state (modal, step 3). One call = one fresh browser, so include the login steps; end with a 'wait' on what the state shows"
      • addedInput schema / properties / browser
        Added value: +{
        +  "description": "Engine (default chromium)",
        +  "enum": [
        +    "chromium",
        +    "firefox",
        +    "webkit"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / channel
        Added value: +{
        +  "description": "Branded Chromium to launch instead of the bundled one (must be installed)",
        +  "enum": [
        +    "chrome",
        +    "chrome-beta",
        +    "msedge",
        +    "msedge-beta"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / device
        Added value: +{
        +  "description": "Playwright device preset, e.g. 'iPhone 15', 'Pixel 7', 'iPad Pro 11' (viewport, user agent, touch)",
        +  "maxLength": 60,
        +  "minLength": 2,
        +  "type": "string"
        +}
      • addedInput schema / properties / har
        Added value: +{
        +  "properties": {
        +    "mode": {
        +      "description": "'replay' (default) answers requests from the file; 'record' saves the traffic",
        +      "enum": [
        +        "replay",
        +        "record"
        +      ],
        +      "type": "string"
        +    },
        +    "notFound": {
        +      "description": "replay: requests missing from the file abort (default) or go to the network",
        +      "enum": [
        +        "abort",
        +        "fallback"
        +      ],
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": ".har or .zip inside the project",
        +      "maxLength": 500,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "url": {
        +      "description": "Glob limiting the requests, e.g. '**/api/**'",
        +      "maxLength": 500,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "path"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / routes
        Added value: +{
        +  "description": "Network mocks, first match wins: json/body/status fulfil, abort fails, delayMs alone slows the real request",
        +  "items": {
        +    "properties": {
        +      "abort": {
        +        "type": "boolean"
        +      },
        +      "body": {
        +        "maxLength": 200000,
        +        "type": "string"
        +      },
        +      "contentType": {
        +        "maxLength": 100,
        +        "type": "string"
        +      },
        +      "delayMs": {
        +        "maximum": 10000,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "headers": {
        +        "additionalProperties": {
        +          "type": "string"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "json": {},
        +      "method": {
        +        "maxLength": 10,
        +        "type": "string"
        +      },
        +      "status": {
        +        "maximum": 599,
        +        "minimum": 100,
        +        "type": "integer"
        +      },
        +      "url": {
        +        "description": "Glob, e.g. '**/api/cart'",
        +        "maxLength": 500,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 20,
        +  "type": "array"
        +}
      • addedInput schema / properties / waitFor
        Added value: +{
        +  "description": "Wait for this selector to be visible first (for elements that render late)",
        +  "type": "string"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "error": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "hint": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "type": "string"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "message"
        +      ],
        +      "type": "object"
        +    },
        +    "httpStatus": {
        +      "description": "the page's HTTP status",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "locator": {
        +      "description": "a verified unique locator for the first match",
        +      "type": "string"
        +    },
        +    "matches": {
        +      "description": "elements matched; actions need exactly 1",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "ok": {
        +      "description": "false when the call failed (see error) or the tests it ran failed",
        +      "type": "boolean"
        +    },
        +    "url": {
        +      "type": "string"
        +    },
        +    "valid": {
        +      "description": "validate-selector: the selector parsed and ran",
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "ok"
        +  ],
        +  "type": "object"
        +}
  3. 2 tool updatesv0.4.2
    • Addedaudit-accessibility
    • Changeddiagnose-flaky1 field changed
      • addedInput schema / properties / order
        Added value: +{
        +  "description": "Also run the target files in `runs` random orders (Playwright 1.64+ --shuffle, one worker) to find tests that depend on what ran before them; returns the seed that reproduces it and the likely culprit test",
        +  "type": "boolean"
        +}
  4. 11 tool updatesv0.3.2
    • First observedanalyze-history
    • First observedcompare-visual-state
    • First observeddiagnose-flaky
    • First observedgenerate-e2e-test
    • First observedget-failure
    • First observedget-run-status
    • First observedinspect-page
    • First observedlist-tests
    • First observedrun-test
    • First observedsuggest-fix
    • First observedvalidate-selector

TDQS

A3.9/5.0

Scored across 19 tools

Disambiguation4/5

Most tools occupy a clearly distinct stage of the E2E lifecycle (run, inspect failure, suggest fix, bisect, quarantine, audit), and many descriptions explicitly state preconditions like 'use run-test first'. A few pairs remain close: inspect-page vs validate-selector (both return verified locators from a live page) and audit-tests vs check-test-change vs diagnose-flaky (all judge flakiness, though static/heuristic/empirical respectively). These overlaps are resolvable from the descriptions but could still cause misselection.

Naming Consistency4/5

Almost every tool follows a kebab-case verb_noun pattern (run-test, get-failure, audit-performance, generate-e2e-test), which is predictable and readable. The main deviation is 'quarantine', a bare verb whose add/list/remove subactions live only in the description, and a couple of tools carry very compound names. Overall consistent with only minor outliers.

Tool Count4/5

At 19 tools the surface is on the heavy side, but each tool maps to a genuinely different concern: execution, run history, failure triage, flake diagnosis, test generation, code hygiene, auth, and three separate page audits. No obvious redundant tool is present, so the count is justified by breadth even if slightly over what a single server usually needs.

Completeness4/5

Coverage is strong end-to-end: list and run tests, load external/CI reports, inspect failures, suggest and verify fixes, diagnose flake, bisect commits, quarantine, plus visual/a11y/perf audits, selector validation, page inspection, login state saving, and test scaffolding. Gaps are minor — no dedicated config/install or environment management tool, no network mocking/route setup for test runs, and no baseline/quarantine cleanup beyond expiry and remove.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers