playwright-e2e-mcp 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,6 +3,10 @@
3
3
  [![CI](https://github.com/xsignon-secure/E2E/actions/workflows/ci.yml/badge.svg)](https://github.com/xsignon-secure/E2E/actions/workflows/ci.yml) [![release](https://img.shields.io/github/v/release/xsignon-secure/E2E)](https://github.com/xsignon-secure/E2E/releases) [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-io.github.xsignon--secure%2FE2E-2563eb)](https://registry.modelcontextprotocol.io/)
4
4
  [![M8ven Score](https://m8ven.ai/badge/mcp/trajectiq-ai/e2e)](https://m8ven.ai/mcp/trajectiq-ai/e2e?s=readme)
5
5
 
6
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=playwright-e2e&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBsYXl3cmlnaHQtZTJlLW1jcCJdfQ==)
7
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_server-0098FF?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright-e2e%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522playwright-e2e-mcp%2522%255D%257D)
8
+ [![Add to Claude Desktop](https://img.shields.io/badge/Claude_Desktop-.mcpb_bundle-D97757)](https://github.com/xsignon-secure/E2E/releases/latest)
9
+
6
10
  An [MCP](https://modelcontextprotocol.io) server that **diagnoses and fixes failing Playwright
7
11
  tests**. It is the layer that sits next to a browser-driving MCP: Playwright MCP gives an agent
8
12
  hands in the browser; this server gives it a test runner, a failure analyst and a verified fixer.
@@ -62,16 +66,36 @@ against the bundled `examples/sample-test.spec.ts` (actual output, unedited):
62
66
  Images are rendered with `node scripts/gen-demo-images.mjs`: the run-test card is real
63
67
  captured output; the endpoint card is an illustration of the authenticated listing.
64
68
 
69
+ > If this saves you a debugging session, a ⭐ on the repo helps other Playwright users find it.
70
+
65
71
  ## Install
66
72
 
67
73
  Works with Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Freebuff
68
74
  and every other MCP client — pick whichever route fits:
69
75
 
76
+ **Let your agent do it.** Paste this into Claude Code, Cursor, Codex, Gemini CLI or any
77
+ other coding agent:
78
+
79
+ > Install the playwright-e2e-mcp server and skill by following
80
+ > https://raw.githubusercontent.com/xsignon-secure/E2E/main/llms-install.md
81
+
82
+ or run the installer yourself from the project root. It merges the server into each
83
+ client's project config it finds (Claude Code, Cursor, VS Code, Gemini CLI, Codex) and
84
+ installs the agent skill, leaving your other servers alone:
85
+
86
+ ```bash
87
+ npx -y playwright-e2e-mcp init # --client all | cursor,vscode … · --dry-run
88
+ ```
89
+
70
90
  | Route | How |
71
91
  | --- | --- |
92
+ | **One command, any project** | `npx -y playwright-e2e-mcp init` |
93
+ | **Claude Code plugin (server + skill)** | `/plugin marketplace add xsignon-secure/E2E` then `/plugin install playwright-e2e-mcp@xsignon-secure` |
94
+ | **Gemini CLI extension (server + skill)** | `gemini extensions install https://github.com/xsignon-secure/E2E` |
95
+ | **Skill only, any agent** | `npx skills add xsignon-secure/E2E` |
72
96
  | **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
73
97
  | **MCP Registry** (registry-aware clients discover it automatically) | `io.github.xsignon-secure/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
74
- | **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.3.0` (pin a release tag) |
98
+ | **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.3.2` (pin a release tag) |
75
99
  | **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/xsignon-secure/E2E/releases) |
76
100
  | **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
77
101
 
@@ -394,8 +418,8 @@ builds `dist/` automatically on install). Pin a release tag: an unpinned
394
418
  `github:xsignon-secure/E2E` runs whatever is on the default branch at that moment.
395
419
 
396
420
  ```bash
397
- npx -y github:xsignon-secure/E2E#v0.3.0
398
- npm install -D github:xsignon-secure/E2E#v0.3.0 @playwright/test # or as a project dependency
421
+ npx -y github:xsignon-secure/E2E#v0.3.2
422
+ npm install -D github:xsignon-secure/E2E#v0.3.2 @playwright/test # or as a project dependency
399
423
  npx playwright install chromium
400
424
  ```
401
425
 
@@ -403,7 +427,7 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
403
427
  it locally:
404
428
 
405
429
  ```bash
406
- npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.3.0/playwright-e2e-mcp-0.3.0.tgz
430
+ npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.3.2/playwright-e2e-mcp-0.3.2.tgz
407
431
  ```
408
432
 
409
433
  Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
@@ -419,7 +443,7 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
419
443
  "mcpServers": {
420
444
  "playwright-e2e": {
421
445
  "command": "npx",
422
- "args": ["-y", "github:xsignon-secure/E2E#v0.3.0"],
446
+ "args": ["-y", "github:xsignon-secure/E2E#v0.3.2"],
423
447
  "env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
424
448
  }
425
449
  }
@@ -433,8 +457,8 @@ when the client launches it somewhere else (e.g. your home directory).
433
457
  **Codex / VS Code / Copilot CLIs:**
434
458
 
435
459
  ```bash
436
- codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.0
437
- code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.3.0"]}'
460
+ codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.2
461
+ code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.3.2"]}'
438
462
  ```
439
463
 
440
464
  Codex's defaults fight this server: the first launch clones the repo and runs
@@ -445,7 +469,7 @@ Codex's defaults fight this server: the first launch clones the repo and runs
445
469
  ```toml
446
470
  [mcp_servers.playwright-e2e]
447
471
  command = "npx"
448
- args = ["-y", "github:xsignon-secure/E2E#v0.3.0"]
472
+ args = ["-y", "github:xsignon-secure/E2E#v0.3.2"]
449
473
  startup_timeout_sec = 60
450
474
  tool_timeout_sec = 600
451
475
  ```
@@ -460,7 +484,7 @@ into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first
460
484
  **Claude Code:**
461
485
 
462
486
  ```bash
463
- claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.0
487
+ claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.2
464
488
  ```
465
489
 
466
490
  **Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
@@ -595,7 +619,7 @@ steps:
595
619
  - uses: actions/setup-node@v6
596
620
  with: { node-version: 24 }
597
621
  - run: npm ci && npx playwright install --with-deps chromium
598
- - uses: xsignon-secure/E2E@v0.3.0
622
+ - uses: xsignon-secure/E2E@v0.3.2
599
623
  with:
600
624
  flaky-runs: 3 # 0 skips the flaky verdict
601
625
  suggest: 2 # suggest-fix diffs for the first 2 failures
@@ -892,8 +916,8 @@ job requests for itself; if it is refused, the run names the setting to change.
892
916
  ### Verifying a published release
893
917
 
894
918
  ```bash
895
- git checkout v0.3.0 && npm ci && npm run mcpb
896
- npm run release:verify -- v0.3.0
919
+ git checkout v0.3.2 && npm ci && npm run mcpb
920
+ npm run release:verify -- v0.3.2
897
921
  ```
898
922
 
899
923
  The release notes promise that the tag rebuilds the published bundle byte for
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `playwright-e2e-mcp init`: one command an agent (or a person) runs to wire
3
+ * the server and the agent skill into a project, for whichever clients the
4
+ * project uses. Config files are merged, never replaced: other servers and
5
+ * settings stay as they are, an existing playwright-e2e entry is updated in
6
+ * place, and a file that is not valid JSON is left untouched and reported.
7
+ *
8
+ * Exit codes: 0 done (or nothing to do), 1 a file could not be updated,
9
+ * 2 bad arguments.
10
+ */
11
+ export declare const SERVER_NAME = "playwright-e2e";
12
+ export declare const SKILL_NAME = "playwright-e2e-mcp";
13
+ export declare const CLIENTS: readonly ["claude", "cursor", "vscode", "gemini", "codex", "windsurf"];
14
+ export type Client = (typeof CLIENTS)[number];
15
+ export declare const INIT_USAGE: string;
16
+ export interface InitOptions {
17
+ projectRoot: string;
18
+ clients?: Client[];
19
+ tools?: string;
20
+ skill: boolean;
21
+ dryRun: boolean;
22
+ }
23
+ export declare function parseInitArgs(argv: string[], cwd?: string): InitOptions;
24
+ /** Clients whose project folder or config file already exists. */
25
+ export declare function detectClients(root: string): Client[];
26
+ export interface PlannedChange {
27
+ client: Client | 'skill';
28
+ file: string;
29
+ action: 'create' | 'update' | 'unchanged' | 'error';
30
+ content?: string;
31
+ error?: string;
32
+ }
33
+ export declare function planInit(options: InitOptions, home?: string): {
34
+ clients: Client[];
35
+ changes: PlannedChange[];
36
+ };
37
+ /** The skill folder shipped in the npm package (dist/cli → ../../skill). */
38
+ export declare function bundledSkillDir(): string;
39
+ export declare function applyInit(changes: PlannedChange[], skillSource?: string): void;
40
+ export declare function runInit(argv: string[], out?: (line: string) => void): number;
@@ -0,0 +1,218 @@
1
+ /**
2
+ * `playwright-e2e-mcp init`: one command an agent (or a person) runs to wire
3
+ * the server and the agent skill into a project, for whichever clients the
4
+ * project uses. Config files are merged, never replaced: other servers and
5
+ * settings stay as they are, an existing playwright-e2e entry is updated in
6
+ * place, and a file that is not valid JSON is left untouched and reported.
7
+ *
8
+ * Exit codes: 0 done (or nothing to do), 1 a file could not be updated,
9
+ * 2 bad arguments.
10
+ */
11
+ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
+ import os from 'node:os';
13
+ import path from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { parseArgs } from 'node:util';
16
+ export const SERVER_NAME = 'playwright-e2e';
17
+ export const SKILL_NAME = 'playwright-e2e-mcp';
18
+ export const CLIENTS = ['claude', 'cursor', 'vscode', 'gemini', 'codex', 'windsurf'];
19
+ export const INIT_USAGE = [
20
+ 'Usage: playwright-e2e-mcp init [options]',
21
+ '',
22
+ 'Adds the playwright-e2e MCP server and the playwright-e2e-mcp agent skill to a',
23
+ 'project. Existing config files are merged, never overwritten.',
24
+ '',
25
+ ' --client <list> comma separated: claude, cursor, vscode, gemini, codex,',
26
+ ' windsurf, or all (default: the clients the project already',
27
+ ' uses, or claude,cursor,vscode when none is found)',
28
+ ' --project-root <dir> project directory (default: cwd)',
29
+ ' --tools <list> expose only these tools/profiles (e.g. core), see --help',
30
+ ' --no-skill do not install the agent skill',
31
+ ' --dry-run print what would change without writing',
32
+ '',
33
+ 'Files (project scope): claude .mcp.json · cursor .cursor/mcp.json ·',
34
+ 'vscode .vscode/mcp.json · gemini .gemini/settings.json · codex .codex/config.toml.',
35
+ 'windsurf has no project file; it writes ~/.codeium/windsurf/mcp_config.json.',
36
+ 'Skill: .agents/skills/ (read by Codex, Gemini, Cursor and others) and',
37
+ '.claude/skills/ when claude is selected.',
38
+ '',
39
+ ].join('\n');
40
+ export function parseInitArgs(argv, cwd = process.cwd()) {
41
+ const { values } = parseArgs({
42
+ args: argv,
43
+ strict: true,
44
+ options: {
45
+ client: { type: 'string' },
46
+ 'project-root': { type: 'string' },
47
+ tools: { type: 'string' },
48
+ 'no-skill': { type: 'boolean' },
49
+ 'dry-run': { type: 'boolean' },
50
+ },
51
+ });
52
+ let clients;
53
+ if (values.client !== undefined) {
54
+ const names = values.client.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
55
+ if (names.includes('all'))
56
+ clients = [...CLIENTS];
57
+ else {
58
+ const unknown = names.filter((n) => !CLIENTS.includes(n));
59
+ if (unknown.length || !names.length) {
60
+ throw new Error(`--client must list ${CLIENTS.join(', ')} or all (got: ${unknown.join(', ') || 'nothing'})`);
61
+ }
62
+ clients = [...new Set(names)];
63
+ }
64
+ }
65
+ return {
66
+ projectRoot: path.resolve(cwd, values['project-root'] ?? '.'),
67
+ clients,
68
+ tools: values.tools,
69
+ skill: !values['no-skill'],
70
+ dryRun: Boolean(values['dry-run']),
71
+ };
72
+ }
73
+ /** Clients whose project folder or config file already exists. */
74
+ export function detectClients(root) {
75
+ const has = (p) => existsSync(path.join(root, p));
76
+ const found = [];
77
+ if (has('.mcp.json') || has('.claude') || has('CLAUDE.md'))
78
+ found.push('claude');
79
+ if (has('.cursor'))
80
+ found.push('cursor');
81
+ if (has('.vscode'))
82
+ found.push('vscode');
83
+ if (has('.gemini') || has('GEMINI.md'))
84
+ found.push('gemini');
85
+ if (has('.codex'))
86
+ found.push('codex');
87
+ return found;
88
+ }
89
+ function serverArgs(tools) {
90
+ return tools ? ['-y', 'playwright-e2e-mcp', `--tools=${tools}`] : ['-y', 'playwright-e2e-mcp'];
91
+ }
92
+ /** Merges our entry into a JSON config under `key`, keeping everything else. */
93
+ function planJson(file, key, entry, client) {
94
+ let data = {};
95
+ let existed = false;
96
+ if (existsSync(file)) {
97
+ existed = true;
98
+ const raw = readFileSync(file, 'utf8');
99
+ if (raw.trim()) {
100
+ try {
101
+ const parsed = JSON.parse(raw);
102
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
103
+ throw new Error('not a JSON object');
104
+ data = parsed;
105
+ }
106
+ catch (err) {
107
+ return { client, file, action: 'error', error: `not valid JSON (${err.message}); left unchanged` };
108
+ }
109
+ }
110
+ }
111
+ const current = data[key];
112
+ const servers = current && typeof current === 'object' && !Array.isArray(current) ? { ...current } : {};
113
+ const before = JSON.stringify(servers[SERVER_NAME]);
114
+ servers[SERVER_NAME] = entry;
115
+ if (existed && before === JSON.stringify(entry))
116
+ return { client, file, action: 'unchanged' };
117
+ return { client, file, action: existed ? 'update' : 'create', content: `${JSON.stringify({ ...data, [key]: servers }, null, 2)}\n` };
118
+ }
119
+ /** Codex reads TOML; append our table unless one is already there. */
120
+ function planCodex(file, args) {
121
+ const table = `[mcp_servers.${SERVER_NAME}]`;
122
+ const block = `${table}\ncommand = "npx"\nargs = [${args.map((a) => JSON.stringify(a)).join(', ')}]\n`;
123
+ if (!existsSync(file))
124
+ return { client: 'codex', file, action: 'create', content: block };
125
+ const raw = readFileSync(file, 'utf8');
126
+ if (raw.includes(table))
127
+ return { client: 'codex', file, action: 'unchanged' };
128
+ const sep = raw.length === 0 || raw.endsWith('\n\n') ? '' : raw.endsWith('\n') ? '\n' : '\n\n';
129
+ return { client: 'codex', file, action: 'update', content: `${raw}${sep}${block}` };
130
+ }
131
+ export function planInit(options, home = os.homedir()) {
132
+ const root = options.projectRoot;
133
+ let clients = options.clients ?? detectClients(root);
134
+ if (!clients.length)
135
+ clients = ['claude', 'cursor', 'vscode'];
136
+ const args = serverArgs(options.tools);
137
+ const stdio = { command: 'npx', args };
138
+ const changes = [];
139
+ for (const client of clients) {
140
+ switch (client) {
141
+ case 'claude':
142
+ changes.push(planJson(path.join(root, '.mcp.json'), 'mcpServers', { type: 'stdio', ...stdio }, client));
143
+ break;
144
+ case 'cursor':
145
+ changes.push(planJson(path.join(root, '.cursor', 'mcp.json'), 'mcpServers', stdio, client));
146
+ break;
147
+ case 'vscode':
148
+ changes.push(planJson(path.join(root, '.vscode', 'mcp.json'), 'servers', { type: 'stdio', ...stdio }, client));
149
+ break;
150
+ case 'gemini':
151
+ changes.push(planJson(path.join(root, '.gemini', 'settings.json'), 'mcpServers', stdio, client));
152
+ break;
153
+ case 'codex':
154
+ changes.push(planCodex(path.join(root, '.codex', 'config.toml'), args));
155
+ break;
156
+ case 'windsurf':
157
+ changes.push(planJson(path.join(home, '.codeium', 'windsurf', 'mcp_config.json'), 'mcpServers', stdio, client));
158
+ break;
159
+ }
160
+ }
161
+ if (options.skill) {
162
+ const targets = [path.join(root, '.agents', 'skills', SKILL_NAME)];
163
+ if (clients.includes('claude'))
164
+ targets.push(path.join(root, '.claude', 'skills', SKILL_NAME));
165
+ for (const dir of targets) {
166
+ changes.push({ client: 'skill', file: dir, action: existsSync(path.join(dir, 'SKILL.md')) ? 'update' : 'create' });
167
+ }
168
+ }
169
+ return { clients, changes };
170
+ }
171
+ /** The skill folder shipped in the npm package (dist/cli → ../../skill). */
172
+ export function bundledSkillDir() {
173
+ return fileURLToPath(new URL(`../../skill/${SKILL_NAME}/`, import.meta.url));
174
+ }
175
+ export function applyInit(changes, skillSource = bundledSkillDir()) {
176
+ for (const change of changes) {
177
+ if (change.action === 'error' || change.action === 'unchanged')
178
+ continue;
179
+ if (change.client === 'skill') {
180
+ mkdirSync(change.file, { recursive: true });
181
+ cpSync(skillSource, change.file, { recursive: true, force: true });
182
+ continue;
183
+ }
184
+ mkdirSync(path.dirname(change.file), { recursive: true });
185
+ writeFileSync(change.file, change.content ?? '');
186
+ }
187
+ }
188
+ export function runInit(argv, out = (l) => process.stdout.write(`${l}\n`)) {
189
+ let options;
190
+ try {
191
+ options = parseInitArgs(argv);
192
+ }
193
+ catch (err) {
194
+ out(`init: ${err.message}\n`);
195
+ out(INIT_USAGE);
196
+ return 2;
197
+ }
198
+ const { clients, changes } = planInit(options);
199
+ if (options.skill && !existsSync(path.join(bundledSkillDir(), 'SKILL.md'))) {
200
+ out('init: the skill files are missing from this install; skipping the skill.');
201
+ for (const c of changes)
202
+ if (c.client === 'skill')
203
+ c.action = 'unchanged';
204
+ }
205
+ if (!options.dryRun)
206
+ applyInit(changes);
207
+ const rel = (p) => (p.startsWith(options.projectRoot) ? path.relative(options.projectRoot, p) || '.' : p);
208
+ out(`${options.dryRun ? 'Would set up' : 'Set up'} playwright-e2e for: ${clients.join(', ')}`);
209
+ for (const c of changes) {
210
+ const what = c.client === 'skill' ? 'skill' : c.client;
211
+ out(` ${c.action.padEnd(9)} ${rel(c.file)} (${what})${c.error ? `: ${c.error}` : ''}`);
212
+ }
213
+ out('');
214
+ out('Next: make sure browsers are installed (npx playwright install chromium), then');
215
+ out('restart or reload the agent so it picks up the new server.');
216
+ return changes.some((c) => c.action === 'error') ? 1 : 0;
217
+ }
218
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -31,6 +31,15 @@ async function main() {
31
31
  process.exitCode = await runCi(process.argv.slice(3));
32
32
  return;
33
33
  }
34
+ if (process.argv[2] === 'init') {
35
+ const { runInit, INIT_USAGE } = await import('./cli/init.js');
36
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
37
+ process.stdout.write(INIT_USAGE);
38
+ return;
39
+ }
40
+ process.exitCode = runInit(process.argv.slice(3));
41
+ return;
42
+ }
34
43
  if (process.argv.includes('--version') || process.argv.includes('-v')) {
35
44
  process.stdout.write(`${SERVER_VERSION}\n`);
36
45
  return;
@@ -41,6 +50,7 @@ async function main() {
41
50
  '',
42
51
  'Usage: playwright-e2e-mcp [--tools=<list>] [--version] [--help]',
43
52
  ' playwright-e2e-mcp ci [options] run the suite and print a Markdown diagnosis (ci --help)',
53
+ ' playwright-e2e-mcp init [options] add the server + agent skill to a project (init --help)',
44
54
  '',
45
55
  'Connects over stdio (MCP). Configuration via environment:',
46
56
  ' PW_MCP_PROJECT_ROOT default project root (default: cwd)',
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,SAAS,YAAY;IACnB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACxD,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC9D,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,cAAc,IAAI,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;YACE,4EAA4E;YAC5E,EAAE;YACF,iEAAiE;YACjE,mGAAmG;YACnG,kGAAkG;YAClG,EAAE;YACF,2DAA2D;YAC3D,kEAAkE;YAClE,sFAAsF;YACtF,wFAAwF;YACxF,0EAA0E;YAC1E,uFAAuF;YACvF,mFAAmF;YACnF,4DAA4D;YAC5D,EAAE;YACF,6CAA6C;YAC7C,8EAA8E;YAC9E,wEAAwE;YACxE,kEAAkE;YAClE,2DAA2D;YAC3D,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACzE,IAAI,SAAS;QAAE,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAE7E,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACnB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1H,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright-e2e-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "MCP server that runs, diagnoses and fixes failing Playwright end-to-end tests: trace analysis, verified locator fixes, flaky ranking",
5
5
  "author": "xsignon-secure (https://github.com/xsignon-secure)",
6
6
  "mcpName": "io.github.xsignon-secure/E2E",
@@ -26,7 +26,10 @@
26
26
  "selectors",
27
27
  "flaky-tests",
28
28
  "github-action",
29
- "ci"
29
+ "ci",
30
+ "agent-skills",
31
+ "claude-code-plugin",
32
+ "gemini-cli-extension"
30
33
  ],
31
34
  "main": "./dist/index.js",
32
35
  "types": "./dist/index.d.ts",
@@ -42,6 +45,7 @@
42
45
  "files": [
43
46
  "dist",
44
47
  "examples",
48
+ "skill/playwright-e2e-mcp",
45
49
  "README.md",
46
50
  "LICENSE"
47
51
  ],
@@ -0,0 +1,34 @@
1
+ # Agent skill: playwright-e2e-mcp
2
+
3
+ `playwright-e2e-mcp/` is an [Agent Skill](https://agentskills.io/specification)
4
+ that teaches an agent when and how to use this repo's MCP server: the run, read
5
+ the failure, inspect, validate, fix and re-run loop, self-healing fixes with
6
+ `suggest-fix`, signed-in page inspection, background runs, run-history triage,
7
+ flaky-test diagnosis, test generation and visual comparison. It targets
8
+ playwright-e2e-mcp 0.3.0 (and works with 0.2.0 or newer). It works with any agent that reads
9
+ `SKILL.md` skills (Claude Code, Codex CLI, OpenClaw and others) once the MCP
10
+ server is connected.
11
+
12
+ ```
13
+ playwright-e2e-mcp/
14
+ ├── SKILL.md # when to use the skill and the step-by-step workflow
15
+ └── references/
16
+ ├── setup.md # server install per client, env vars, skill install
17
+ ├── tools.md # every tool's arguments
18
+ ├── failure-kinds.md # failure kinds, error codes and what to do
19
+ └── example-session.md # a worked fix-a-failing-test session
20
+ ```
21
+
22
+ The skill contains only Markdown: no scripts, binaries or symlinks, and no
23
+ credentials.
24
+
25
+ ## Packaging for a marketplace (Agensi)
26
+
27
+ Agensi expects one top-level folder named after the skill, with `SKILL.md` at
28
+ its root, text files only and no OS junk files. From this `skill/` directory:
29
+
30
+ ```bash
31
+ zip -r playwright-e2e-mcp.zip playwright-e2e-mcp -x "*.DS_Store" "*Thumbs.db"
32
+ ```
33
+
34
+ Keep the skill's `name` in `SKILL.md` equal to the folder name.
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: playwright-e2e-mcp
3
+ description: Runs, debugs and fixes Playwright end-to-end tests through the playwright-e2e-mcp server, using structured run results, trace-based failure diagnostics, verified locators, self-healing fixes that re-run and revert if still red, per-test flaky verdicts that separate parallelism bugs from races, signed-in page inspection and local run history. Use when the user asks to run Playwright tests, fix a failing or broken e2e test, find out why a test is flaky or which tests are unstable, repair a selector that no longer matches, write a new Playwright test, or check a page for visual regressions.
4
+ ---
5
+
6
+ # Playwright E2E with playwright-e2e-mcp
7
+
8
+ This skill drives the `playwright-e2e-mcp` MCP server. The server runs Playwright
9
+ for you and returns structured results instead of raw terminal output: pass/fail
10
+ stats, each failure with `file:line`, a failure kind, the DOM at the moment of
11
+ failure (read from the Playwright trace), failed network requests, console errors
12
+ and concrete next steps. It can also propose and apply a verified fix for a broken
13
+ locator, inspect pages behind a login, run long suites in the background and keep
14
+ a local history of every run.
15
+
16
+ This skill is written for playwright-e2e-mcp 0.3.0 and works with 0.2.0 or
17
+ newer. If `suggest-fix`, `get-run-status` or `analyze-history` is missing, the
18
+ server is older than 0.2.0: use the steps that do not need those tools and tell
19
+ the user to update it. `diagnose-flaky`'s per-test table and `isolate` option
20
+ arrived in 0.3.0.
21
+
22
+ ## Before you start
23
+
24
+ 1. Check that the server's tools are available. They are named `run-test`,
25
+ `get-run-status`, `get-failure`, `suggest-fix`, `inspect-page`,
26
+ `validate-selector`, `list-tests`, `generate-e2e-test`,
27
+ `compare-visual-state`, `diagnose-flaky` and `analyze-history` (your client
28
+ may prefix them, e.g. `mcp__playwright-e2e__run-test`).
29
+ 2. If they are all missing, stop and tell the user the MCP server is not
30
+ connected. Point them to `references/setup.md` for the one-line install for
31
+ their client. Do not fall back to shelling out to `npx playwright test` unless
32
+ the user asks. If only some are missing, the server may run a smaller tool
33
+ profile (`--tools=core` exposes `run-test`, `get-run-status`, `get-failure`,
34
+ `suggest-fix`, `diagnose-flaky` and `list-tests`); work with what is there and
35
+ mention the profile when a task needs a page tool.
36
+ 3. Every tool except `get-run-status` takes an optional `projectRoot`. Leave it
37
+ out unless the user works in a sub-project; the server defaults to `PW_MCP_PROJECT_ROOT` or its working
38
+ directory, and rejects any root outside its allowed roots.
39
+ 4. If the client offers the server's prompts as slash commands,
40
+ `/fix-failing-test` and `/triage-flaky-tests` start the two main workflows
41
+ below.
42
+
43
+ ## The core loop: fix a failing test
44
+
45
+ Follow these steps in order. Do not edit code before step 3.
46
+
47
+ 1. **Run.** Call `run-test` with the narrowest scope you know:
48
+ `{ "testFiles": ["tests/checkout.spec.ts"] }`, or `file:line`, or `grep`.
49
+ Omit `testFiles` only when the user asks for the whole suite. Failing tests are
50
+ retried once by default, so a test that passes on retry is reported as
51
+ **flaky**, not failed. For a long suite pass `background: true` and poll
52
+ `get-run-status` with `waitSeconds: 30`.
53
+ 2. **Read the failure.** For each failure, call `get-failure` with its 1-based
54
+ `index`. Read the message and code frame, expected vs actual, the failure kind,
55
+ the DOM snapshot at failure, the failed action and its selector, failed network
56
+ requests and console errors.
57
+ 3. **Decide what is wrong** using the failure kind (see
58
+ `references/failure-kinds.md`):
59
+ - `server-unreachable` / `SERVER_NOT_RUNNING`: the app is not running. Tell the
60
+ user to start the dev server, or suggest `webServer` in the Playwright config.
61
+ Do not edit tests.
62
+ - A locator or selector in the message, or "0 elements": call `suggest-fix`
63
+ with the same `index`. If it returns a diff with `high` confidence, call it
64
+ again with `apply: true`; it re-runs the test and reverts if still red. If it
65
+ says the element is missing, treat it as an app bug and report the evidence.
66
+ Otherwise go to the selector loop below.
67
+ - `assertion` with a sensible selector: compare expected vs actual and the DOM
68
+ snapshot. Decide whether the app regressed or the test expectation is stale,
69
+ and say which before changing anything.
70
+ - `timeout`: check the DOM snapshot and failed requests for a slow or failed
71
+ API call before raising any timeout.
72
+ - Failed network request (4xx/5xx/no response) right before the failure: the
73
+ backend is the likely cause; report it.
74
+ 4. **Fix** the spec or the app code, the smallest change that addresses the cause.
75
+ 5. **Re-run only what failed:** `run-test` with `{ "lastFailed": true }`. Repeat
76
+ from step 2 until green.
77
+
78
+ ## Selector loop: a locator no longer matches
79
+
80
+ 1. `inspect-page` with the page URL and `view: "locators"`
81
+ (e.g. `{ "url": "http://localhost:3000/checkout", "view": "locators" }`).
82
+ Behind a login, pass `storageState` (the project's saved auth file); to reach a
83
+ modal or later step, pass `actions`. Every locator listed was checked to match
84
+ exactly one element.
85
+ 2. Pick a replacement. Prefer, in order: role + accessible name (`getByRole`),
86
+ `getByTestId`, label/placeholder, then a short stable CSS selector. Avoid
87
+ positional selectors such as `:nth-child` and generated class names.
88
+ 3. `validate-selector` with `{ "url": ..., "selector": ... }` before editing the
89
+ spec. It accepts locator expressions as written in the spec. Only use one that
90
+ comes back `✅ VALID` with exactly 1 match.
91
+ 4. Update the spec and re-run with `lastFailed: true`.
92
+
93
+ ## Pages behind a login
94
+
95
+ `inspect-page`, `validate-selector` and `compare-visual-state` open the page in a
96
+ fresh browser, so a signed-in page shows the login screen unless you pass state:
97
+
98
+ - `storageState`: path inside the project to a Playwright storageState JSON, such
99
+ as `playwright/.auth/user.json` written by the project's setup project. Look for
100
+ it in `playwright.config.*` before asking the user. The server can default to
101
+ `PW_MCP_STORAGE_STATE`.
102
+ - `headers`: extra HTTP headers, e.g. an API token the user gave you. Never invent
103
+ or log credentials.
104
+ - `actions`: up to 20 steps after load (`click`, `fill`, `press`, `check`,
105
+ `select`, `hover`, `wait`, `goto`, ...) to open a modal or reach a later step.
106
+ - `viewport`: `{ "width": 390, "height": 844 }` for mobile layouts.
107
+
108
+ When a response says the page landed on a login screen, retry with
109
+ `storageState`. `suggest-fix` takes `storageState` and `headers` too when you heal
110
+ against a live `url`.
111
+
112
+ ## Flaky or intermittent failures
113
+
114
+ Start with `analyze-history` (default view `flaky`) to see which tests flip
115
+ between pass and fail across recorded runs, which regressed, and which are simply
116
+ broken; `view: "patterns"` groups failures that share a cause. Then call
117
+ `diagnose-flaky` on the worst ones (optionally `{ "testFiles": [...], "runs": 5 }`;
118
+ with no `testFiles` it takes the tests that failed in the last run). It repeats
119
+ them with retries disabled, in one Playwright process, and returns a table with
120
+ one verdict **per test** (passes, failures, duration spread, first error):
121
+
122
+ - **CONSISTENTLY FAILING**: not flaky; treat it as a real failure (core loop).
123
+ - **FLAKY**: some runs passed. Same error signature each time points to a real
124
+ race in the app or test; varying errors point to timing or environment. Look for
125
+ missing awaits, assertions without auto-waiting, shared state between tests and
126
+ fixed `waitForTimeout` sleeps. Never "fix" flakiness by only adding retries or
127
+ sleeps.
128
+ - **NOT REPRODUCING**: passed every run. Report that the failure was one-off.
129
+
130
+ When a test is FLAKY and the suite runs in parallel, call `diagnose-flaky` again
131
+ with `isolate: true`. It repeats the tests fully parallel, then repeats the
132
+ failing ones with one worker, and reads each one:
133
+
134
+ - **fails only in parallel**: the test shares state with others (same user or
135
+ account, DB rows, files, ports, a global fixture). Fix the data isolation, for
136
+ example per-worker data from `testInfo.workerIndex`; do not just serialize the
137
+ whole suite.
138
+ - **flaky even alone**: the race is inside the test or the app.
139
+ - **fails alone too**: a real bug, not parallelism.
140
+
141
+ Pass `separateProcesses: true` only when the flake seems tied to global setup or
142
+ a cold start, since one process per run is slower. `get-failure` works on the
143
+ last failing diagnose run straight after, and each repetition is recorded in the
144
+ history, so `diagnose-flaky` with `runs: 5` is also the quickest way to seed
145
+ history for `analyze-history`.
146
+
147
+ Every `run-test`, `diagnose-flaky` and `suggest-fix` run is recorded in
148
+ `<project>/.playwright-e2e-mcp/history.jsonl` on the user's machine;
149
+ `analyze-history` with `view: "test"` and a `test` filter shows one test's
150
+ pass/fail timeline.
151
+
152
+ ## Other tasks
153
+
154
+ - **List tests:** `list-tests`, with `filter` for a substring of `file › title`.
155
+ - **Write a new test:** `generate-e2e-test` with a `description` (and `pageUrl` if
156
+ there is no `baseURL`). It scaffolds a spec from selectors the project actually
157
+ declares, from recent git changes, and reports each selector's source. Review the
158
+ file it writes, then `run-test` it. Pass `write: false` to preview without
159
+ writing.
160
+ - **Set up CI:** when the user wants the same diagnosis on every pull request,
161
+ point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.3.0`) or the
162
+ `npx -y playwright-e2e-mcp ci` command in `references/setup.md`. It writes the
163
+ run, flaky verdicts and fix diffs to the job summary and one PR comment.
164
+ - **Visual regression:** `compare-visual-state` with `url` and a `name`. The first
165
+ call saves a baseline under `.pw-mcp/visual/`; later calls report changed
166
+ regions and color shifts and write a diff image. Use `action: "baseline"` only
167
+ when the user confirms the new look is intended.
168
+
169
+ ## Reporting back
170
+
171
+ When you finish, tell the user, in this order:
172
+
173
+ 1. The result: which tests now pass, fail or are flaky (counts from the last
174
+ `run-test`).
175
+ 2. The cause of each failure you fixed, with the `file:line` you changed.
176
+ 3. Anything you did not fix and why (app bug, server down, needs a decision).
177
+
178
+ ## Things to avoid
179
+
180
+ - Do not raise timeouts, add retries, add `waitForTimeout`, or delete or
181
+ `test.skip` a test to make a run green, unless the user explicitly asks.
182
+ - Do not accept a new visual baseline without the user's confirmation.
183
+ - Do not pass `allowExpectationUpdate: true` to `suggest-fix` unless the user
184
+ confirms the new text is intended; a changed expected value can be a real bug.
185
+ - Do not point `inspect-page` or `validate-selector` at sites the user did not
186
+ name; they open real pages in a headless browser.
187
+ - `run-test` executes the project's own test code. Run it only in projects the
188
+ user has asked you to work on.
189
+
190
+ ## References
191
+
192
+ - `references/setup.md`: install and client configuration, environment variables.
193
+ - `references/tools.md`: every tool's arguments.
194
+ - `references/failure-kinds.md`: failure kinds and error codes, and what to do.
195
+ - `references/example-session.md`: a worked fix-a-failing-test session with
196
+ `suggest-fix`.
@@ -0,0 +1,53 @@
1
+ # Example session: fixing a failing checkout test
2
+
3
+ **User:** The checkout test started failing after the redesign. Can you fix it?
4
+
5
+ 1. Agent calls `run-test` with `{ "testFiles": ["tests/checkout.spec.ts"] }`.
6
+
7
+ ```
8
+ ## Playwright run — ❌ FAILED
9
+ | passed | failed | flaky | skipped |
10
+ | 2 | 1 | 0 | 0 |
11
+ ### 1 of 1. checkout.spec.ts › pays with card
12
+ File: checkout.spec.ts:18 | failed · timeout
13
+ ```
14
+
15
+ 2. Agent calls `get-failure` with `{ "index": 1 }`. The failed action is
16
+ `locator('#pay-now').click()`. The DOM snapshot at failure has no `#pay-now`,
17
+ but it does have a `Pay now` button. No network requests failed and the console
18
+ is clean, so the app itself looks healthy.
19
+
20
+ 3. The failure kind is `timeout`, but the cause is a locator that no longer
21
+ matches, so the agent calls `suggest-fix` with `{ "index": 1 }`:
22
+
23
+ ```
24
+ ### Proposed locator fix — confidence **high**
25
+ The button's accessible name matches "pay", and
26
+ `getByRole('button', { name: 'Pay now' })` is proven to resolve to exactly
27
+ that element.
28
+ - await page.locator('#pay-now').click();
29
+ + await page.getByRole('button', { name: 'Pay now' }).click();
30
+ ```
31
+
32
+ 4. Confidence is high, so the agent calls `suggest-fix` with
33
+ `{ "index": 1, "apply": true }`. The server writes the change, re-runs the test
34
+ with retries off, and reports `✅ Verified — the test passes with the fix`.
35
+ Had the test still failed, the server would have restored the original file.
36
+
37
+ 5. Agent calls `run-test` with `{ "lastFailed": true }` to confirm, then
38
+ `{ "testFiles": ["tests/checkout.spec.ts"] }` for the whole file: 3 passed.
39
+
40
+ **Agent's reply:**
41
+
42
+ > All 3 checkout tests pass now. "pays with card" failed because the redesign
43
+ > removed the `#pay-now` id from the pay button. I changed the locator at
44
+ > `tests/checkout.spec.ts:18` to `getByRole('button', { name: 'Pay now' })`,
45
+ > which matches exactly one element, and the server re-ran the test to confirm
46
+ > the fix.
47
+
48
+ ## When suggest-fix refuses
49
+
50
+ If `suggest-fix` says the element is most likely missing, do not weaken the test.
51
+ Read `get-failure` again for failed network requests and console errors, check the
52
+ page with `inspect-page` (with `storageState` if it needs a login), and report it
53
+ to the user as a probable app bug with that evidence.
@@ -0,0 +1,32 @@
1
+ # Failure kinds and error codes
2
+
3
+ ## Per-test failure kinds (from `run-test` and `get-failure`)
4
+
5
+ | Kind | Meaning | What to do |
6
+ | --- | --- | --- |
7
+ | `assertion` | An `expect` did not hold | Compare expected vs actual and the DOM snapshot; decide whether the app regressed or the expectation is stale, and say which before editing |
8
+ | `timeout` | An action or the test ran out of time | Check the DOM snapshot and failed network requests for the real cause (element never appeared, API failed) before touching timeouts |
9
+ | `server-unreachable` | The app under test did not respond | Ask the user to start the dev server, or configure `webServer` in the Playwright config; do not edit tests |
10
+ | `browser-crash` | The browser or page closed unexpectedly | Re-run once; if it repeats, suggest `npx playwright install` to repair browsers |
11
+ | `syntax` | The spec or config does not compile | Fix the reported `file:line` first; nothing else will run until it does |
12
+ | `config` | The Playwright config is invalid | Read the message and fix the config |
13
+ | `unknown` | Not classified | Read the message, stack and DOM snapshot directly |
14
+
15
+ A test reported as **flaky** passed on the automatic retry. Run
16
+ `diagnose-flaky` before deciding how to treat it.
17
+
18
+ ## Tool error codes
19
+
20
+ | Code | Meaning | What to do |
21
+ | --- | --- | --- |
22
+ | `NO_PLAYWRIGHT` | `@playwright/test` is not installed in the project | Show the user the install command the error includes |
23
+ | `NO_CONFIG` | No `playwright.config.*` found | Ask where the config is, or pass `projectRoot` / `config` |
24
+ | `MULTIPLE_CONFIGS` | Several configs found; the error lists them numbered | Ask the user which one, or pick the obvious one, and pass `config: "2"` or its path |
25
+ | `INVALID_PATH` | A path or `projectRoot` leaves the allowed roots | Use a path inside the project; to allow another root the user must set `PW_MCP_ALLOWED_ROOTS` |
26
+ | `SERVER_NOT_RUNNING` | The app is not reachable | As `server-unreachable` above |
27
+ | `TIMEOUT` | The whole run hit `timeoutMs`; results are partial | Narrow the run (`testFiles`, `grep`) or raise `timeoutMs` for this call |
28
+ | `BROWSER_CRASH` | Browser failed | As `browser-crash` above |
29
+ | `SYNTAX_ERROR` | A spec has a syntax error | Fix the reported file; `list-tests` still works via a source scan |
30
+ | `DISK_FULL` | No space left on device | Ask the user to free disk space |
31
+ | `SPAWN_FAILED` / `REPORT_MISSING` | Playwright could not start or wrote no report | Check Node and Playwright are installed; re-run with `LOG_LEVEL=debug` |
32
+ | `CLIENT_DISCONNECT` | The run was cancelled | Re-run if still needed |
@@ -0,0 +1,120 @@
1
+ # Setup: connecting the playwright-e2e-mcp server
2
+
3
+ This skill only gives the agent instructions. The tools come from the
4
+ `playwright-e2e-mcp` MCP server, which must be connected to the agent.
5
+
6
+ ## Requirements
7
+
8
+ - playwright-e2e-mcp **0.2.0 or newer**, 0.3.0 recommended. `suggest-fix`,
9
+ `get-run-status`, `analyze-history`, verified locators and signed-in page
10
+ inspection arrived in 0.2.0; per-test flaky verdicts, `isolate`, tool profiles
11
+ and the `ci` command in 0.3.0. Check with
12
+ `npx -y playwright-e2e-mcp --version`.
13
+
14
+ - Node.js 20 or newer.
15
+ - A project with `@playwright/test` installed and a browser available:
16
+ `npx playwright install chromium`.
17
+
18
+ ## Install the server
19
+
20
+ The server is published on npm as `playwright-e2e-mcp` and in the official MCP
21
+ Registry as `io.github.xsignon-secure/E2E`. Pin a version in shared configs
22
+ (`playwright-e2e-mcp@<version>`) so every machine runs the same build.
23
+
24
+ **Claude Code**
25
+
26
+ ```bash
27
+ claude mcp add playwright-e2e -- npx -y playwright-e2e-mcp
28
+ ```
29
+
30
+ **Claude Desktop, Cursor, Windsurf, Gemini CLI, Qwen Code and other JSON-config clients**
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "playwright-e2e": {
36
+ "command": "npx",
37
+ "args": ["-y", "playwright-e2e-mcp"],
38
+ "env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ Claude Desktop also has a one-click `.mcpb` extension on the project's
45
+ [GitHub releases](https://github.com/xsignon-secure/E2E/releases); it asks for the
46
+ project root on install.
47
+
48
+ **Codex CLI**
49
+
50
+ ```toml
51
+ # ~/.codex/config.toml
52
+ [mcp_servers.playwright-e2e]
53
+ command = "npx"
54
+ args = ["-y", "playwright-e2e-mcp"]
55
+ startup_timeout_sec = 60
56
+ tool_timeout_sec = 600
57
+ ```
58
+
59
+ Raise the timeouts as shown: a Playwright run with retries takes longer than
60
+ Codex's 60-second default tool timeout.
61
+
62
+ ## Install the skill
63
+
64
+ Copy the `playwright-e2e-mcp/` folder (the one holding `SKILL.md`) into your
65
+ agent's skills directory, for example:
66
+
67
+ - Claude Code: `~/.claude/skills/` (personal) or `.claude/skills/` (project)
68
+ - Codex CLI: `~/.codex/skills/`
69
+ - Other agents: their documented skills folder
70
+
71
+ ## Environment variables
72
+
73
+ Set these in the server's `env` block. None of them are secrets except
74
+ `PW_MCP_HTTP_TOKEN`; never put a token in a committed config file.
75
+
76
+ | Variable | Default | Purpose |
77
+ | --- | --- | --- |
78
+ | `PW_MCP_PROJECT_ROOT` | server working directory | Default project root for every tool |
79
+ | `PW_MCP_TOOLS` | all | Tools to expose: names and/or profiles `core`, `triage`, `inspect`, `author` (same as the `--tools=` flag). `core` halves the tool-definition context |
80
+ | `PW_MCP_ALLOWED_ROOTS` | none | Extra directories allowed as `projectRoot` (`:`-separated, `;` on Windows) |
81
+ | `PW_MCP_BLOCK_PRIVATE_URLS` | off for stdio | `1` makes the URL tools refuse loopback, private-network and cloud-metadata addresses |
82
+ | `PW_MCP_STORAGE_STATE` | none | Default Playwright storageState JSON (inside the project) for the page tools, so signed-in pages open logged in |
83
+ | `PW_MCP_HISTORY` | on | `0` stops recording runs to `<project>/.playwright-e2e-mcp/history.jsonl` (this turns off `analyze-history`) |
84
+ | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, `error` or `silent` |
85
+ | `PW_MCP_HTTP_TOKEN` | none | HTTP bridge only: bearer token that unlocks all tools |
86
+
87
+ ## Hosted endpoint
88
+
89
+ Clients that only accept remote MCP servers can use the Streamable HTTP bridge
90
+ (`https://playwright-e2e-mcp.vercel.app/api/mcp`, or your own deployment of the
91
+ repo). Without a bearer token the bridge serves only `list-tests`,
92
+ `get-failure` and `analyze-history`, so the core loop in `SKILL.md` needs a local install or a token.
93
+
94
+ ## Check it works
95
+
96
+ Ask the agent to "list my Playwright tests". It should call `list-tests` and
97
+ return files and titles. Clients that show MCP prompts also list
98
+ `/fix-failing-test` and `/triage-flaky-tests`. If it says the tools are missing, the server is not
99
+ connected: restart the client after editing its config.
100
+
101
+ ## CI (0.3.0+)
102
+
103
+ The same diagnosis runs without an agent:
104
+
105
+ ```bash
106
+ npx -y playwright-e2e-mcp ci --flaky-runs 3 --suggest 2 --output report.md
107
+ ```
108
+
109
+ Exit code 0 means passed, 1 tests failed, 2 the run itself failed. On GitHub
110
+ Actions it also writes to the job summary. As an Action:
111
+
112
+ ```yaml
113
+ - uses: xsignon-secure/E2E@v0.3.0
114
+ with:
115
+ flaky-runs: 3
116
+ suggest: 2
117
+ ```
118
+
119
+ It keeps one PR comment up to date when the run fails (needs
120
+ `pull-requests: write`).
@@ -0,0 +1,161 @@
1
+ # Tool reference
2
+
3
+ All paths are relative to the project root. Every tool except `get-run-status`
4
+ accepts an optional `projectRoot`, which must sit inside the server's allowed roots.
5
+
6
+ ## run-test
7
+
8
+ Runs Playwright and returns stats, failures, failure kinds and fix hints.
9
+
10
+ | Argument | Type | Notes |
11
+ | --- | --- | --- |
12
+ | `testFiles` | string[] | Files or directories; `file:line` supported. Omit to run everything |
13
+ | `grep` | string | Only tests whose title matches this regex |
14
+ | `browser` | `chromium` \| `firefox` \| `webkit` | Matched against config project names |
15
+ | `background` | boolean | Return a run id at once and keep running; follow it with `get-run-status` |
16
+ | `headed` | boolean | Visible browser window |
17
+ | `timeoutMs` | number | Wall-clock limit for the run (default 120000); partial results are returned past it |
18
+ | `testTimeoutMs` | number | Per-test timeout |
19
+ | `workers`, `retries` | number | Passed to Playwright |
20
+ | `config` | string | Config path, or 1-based index when there are several |
21
+ | `retryOnFailure` | boolean | Retry failures once before reporting (default true; ignored when `retries` is set) |
22
+ | `lastFailed` | boolean | Re-run only the tests that failed last time |
23
+ | `args` | string[] | Allowlisted Playwright flags such as `--repeat-each=N`, `--max-failures=N`, `--update-snapshots`, `--shard=1/3`, `--trace=on`; path-taking flags are rejected |
24
+
25
+ Traces are captured on failure automatically so `get-failure` can show the DOM.
26
+ Clients that send a progress token get live progress while the run goes.
27
+
28
+ ## get-failure
29
+
30
+ | Argument | Type | Notes |
31
+ | --- | --- | --- |
32
+ | `index` | number | 1-based failure index from the last run (default 1) |
33
+
34
+ Returns the message and code frame, expected vs actual, stack, failure kind and
35
+ diagnosis, console output, the DOM snapshot at failure with the failed action and
36
+ its selector, failed network requests, console errors and warnings, and next steps.
37
+
38
+ ## inspect-page
39
+
40
+ | Argument | Type | Notes |
41
+ | --- | --- | --- |
42
+ | `url` | string | Required, full http(s) URL |
43
+ | `selector` | string | Inspect only matches of this CSS selector |
44
+ | `waitFor` | string | Wait for a selector (CSS or `text=...`) first |
45
+ | `waitUntil` | `load` \| `domcontentloaded` \| `networkidle` | Navigation wait |
46
+ | `includeHtml` | boolean | Include rendered HTML (capped by `maxHtmlChars`, default 20000) |
47
+ | `timeoutMs` | number | Default 45000 |
48
+ | `view` | `elements` \| `locators` | `locators`: compact map of interactive elements with verified locators |
49
+ | `storageState` | string | Playwright storageState JSON inside the project (signed-in session); defaults to `PW_MCP_STORAGE_STATE` |
50
+ | `headers` | object | Extra HTTP headers |
51
+ | `actions` | array | Up to 20 steps after load: `{ type: click\|dblclick\|fill\|press\|check\|uncheck\|select\|hover\|wait\|goto, locator?, value?, url?, ms? }` |
52
+ | `viewport` | object | `{ width, height }` |
53
+
54
+ Returns each element's Playwright locators proven unique on the page (role +
55
+ name first), unique CSS selector, tag, visibility, box, text and attributes,
56
+ plus console messages. `validate-selector` and `compare-visual-state` take the
57
+ same `storageState`, `headers`, `actions` and `viewport`.
58
+
59
+ ## validate-selector
60
+
61
+ | Argument | Type | Notes |
62
+ | --- | --- | --- |
63
+ | `url` | string | Required |
64
+ | `selector` | string | Required: CSS, a Playwright selector, or a locator such as `getByRole('button', { name: 'Save' })` |
65
+ | `timeoutMs` | number | Default 45000 |
66
+
67
+ Verdicts: `✅ VALID — N matches` with samples and a unique locator for each,
68
+ a strict-mode warning when more than one matches, `✅ VALID — 0 matches` with
69
+ advice, or `❌ INVALID` with the parse error.
70
+
71
+ ## list-tests
72
+
73
+ | Argument | Type | Notes |
74
+ | --- | --- | --- |
75
+ | `config` | string | Config path or index |
76
+ | `testDir` | string | Restrict to a directory |
77
+ | `filter` | string | Case-insensitive substring of `file › title` |
78
+ | `limit` | number | Default 500 |
79
+
80
+ Falls back to a source scan when Playwright cannot list (broken install or spec).
81
+
82
+ ## generate-e2e-test
83
+
84
+ | Argument | Type | Notes |
85
+ | --- | --- | --- |
86
+ | `description` | string | Required: what the test should cover |
87
+ | `pageUrl` | string | Start page (default: `baseURL` / `webServer.url`) |
88
+ | `testDir`, `file` | string | Where to write; `file` must end in `.spec.*` or `.test.*` |
89
+ | `write` | boolean | Write to disk (default true) |
90
+ | `overwrite` | boolean | Replace a spec this tool generated earlier |
91
+ | `liveInspect` | boolean | Cross-check selectors on the live page |
92
+ | `config` | string | As above |
93
+
94
+ ## compare-visual-state
95
+
96
+ | Argument | Type | Notes |
97
+ | --- | --- | --- |
98
+ | `url` | string | Required |
99
+ | `name` | string | Baseline id, e.g. `checkout-page` |
100
+ | `action` | `compare` \| `baseline` | Default `compare`; `baseline` re-captures the reference |
101
+ | `selector` | string | Capture one element |
102
+ | `fullPage` | boolean | Full scrollable page |
103
+ | `tolerance` | number | Percent of pixels allowed to differ (default 0.1) |
104
+ | `pixelThreshold` | number | Per-pixel channel delta (default 60) |
105
+ | `waitUntil`, `waitFor`, `timeoutMs` | | As `inspect-page` |
106
+
107
+ Baselines live in `.pw-mcp/visual/`.
108
+
109
+ ## diagnose-flaky
110
+
111
+ | Argument | Type | Notes |
112
+ | --- | --- | --- |
113
+ | `testFiles` | string[] | Default: tests that failed in the last run |
114
+ | `runs` | number | 2 to 10 (default 3) |
115
+ | `isolate` | boolean | Repeat fully parallel (`workers` default 4), then repeat the failing tests with one worker (0.3.0+) |
116
+ | `separateProcesses` | boolean | One Playwright process per run instead of one `--repeat-each` process; slower (0.3.0+) |
117
+ | `browser`, `headed`, `workers`, `config` | | As `run-test` |
118
+ | `timeoutMs` | number | Per run (default 120000); the single `--repeat-each` process gets this × `runs` |
119
+
120
+ Runs with retries disabled and returns, per test, passes, failures, duration
121
+ spread, first error and `CONSISTENTLY FAILING`, `FLAKY` or `NOT REPRODUCING`,
122
+ plus the verdict block for the worst test. With `isolate`, a second table reads
123
+ each failing test as "fails only in parallel", "flaky even alone" or "fails
124
+ alone too". Versions before 0.3.0 return one run-level verdict and a per-run
125
+ table instead.
126
+
127
+ ## suggest-fix
128
+
129
+ | Argument | Type | Notes |
130
+ | --- | --- | --- |
131
+ | `index` | number | 1-based failure index from the last run (default 1) |
132
+ | `apply` | boolean | Write the fix (default false: diff only) |
133
+ | `verify` | boolean | After applying, re-run and revert if still failing (default true) |
134
+ | `allowExpectationUpdate` | boolean | Allow applying a changed expected text (default false) |
135
+ | `url`, `storageState`, `headers` | | Heal against a live page instead of the trace snapshot |
136
+ | `config`, `timeoutMs` | | As `run-test` |
137
+
138
+ Returns a unified diff: a locator fix rated `high` or `medium` confidence, or an
139
+ expectation update rated `low` that is applied only with
140
+ `allowExpectationUpdate: true`. Otherwise it refuses and says the element is most
141
+ likely missing.
142
+
143
+ ## get-run-status
144
+
145
+ | Argument | Type | Notes |
146
+ | --- | --- | --- |
147
+ | `runId` | string | From `run-test` with `background: true` (default: latest) |
148
+ | `waitSeconds` | number | Wait up to this long (max 55) |
149
+ | `cancel` | boolean | Stop the run |
150
+
151
+ ## analyze-history
152
+
153
+ | Argument | Type | Notes |
154
+ | --- | --- | --- |
155
+ | `view` | `flaky` \| `patterns` \| `test` | Default `flaky` |
156
+ | `test` | string | Substring of a test's file or title |
157
+ | `lastRuns` | number | Default 30 |
158
+ | `limit` | number | Default 15 |
159
+
160
+ Reads `.playwright-e2e-mcp/history.jsonl`, written by every run
161
+ (`PW_MCP_HISTORY=0` disables it).