playwright-e2e-mcp 0.1.1 → 0.1.3

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.
Files changed (43) hide show
  1. package/README.md +123 -45
  2. package/dist/http.d.ts +19 -1
  3. package/dist/http.js +98 -9
  4. package/dist/http.js.map +1 -1
  5. package/dist/index.js +11 -3
  6. package/dist/index.js.map +1 -1
  7. package/dist/server.d.ts +13 -0
  8. package/dist/server.js +25 -12
  9. package/dist/server.js.map +1 -1
  10. package/dist/tools/compare-visual-state.js +11 -8
  11. package/dist/tools/compare-visual-state.js.map +1 -1
  12. package/dist/tools/generate-e2e-test.js +46 -10
  13. package/dist/tools/generate-e2e-test.js.map +1 -1
  14. package/dist/tools/inspect-page.js +2 -0
  15. package/dist/tools/inspect-page.js.map +1 -1
  16. package/dist/tools/list-tests.js +8 -1
  17. package/dist/tools/list-tests.js.map +1 -1
  18. package/dist/tools/run-test.js +1 -1
  19. package/dist/tools/run-test.js.map +1 -1
  20. package/dist/tools/shared.d.ts +9 -2
  21. package/dist/tools/shared.js +135 -10
  22. package/dist/tools/shared.js.map +1 -1
  23. package/dist/tools/validate-selector.js +2 -0
  24. package/dist/tools/validate-selector.js.map +1 -1
  25. package/dist/types/index.d.ts +7 -0
  26. package/dist/utils/change-analyzer.js +31 -26
  27. package/dist/utils/change-analyzer.js.map +1 -1
  28. package/dist/utils/image-diff.js +23 -4
  29. package/dist/utils/image-diff.js.map +1 -1
  30. package/dist/utils/path-utils.d.ts +25 -3
  31. package/dist/utils/path-utils.js +159 -7
  32. package/dist/utils/path-utils.js.map +1 -1
  33. package/dist/utils/playwright-runner.d.ts +14 -10
  34. package/dist/utils/playwright-runner.js +128 -30
  35. package/dist/utils/playwright-runner.js.map +1 -1
  36. package/dist/utils/report-parser.js +7 -6
  37. package/dist/utils/report-parser.js.map +1 -1
  38. package/dist/utils/trace-reader.js +23 -6
  39. package/dist/utils/trace-reader.js.map +1 -1
  40. package/dist/utils/url-policy.d.ts +29 -0
  41. package/dist/utils/url-policy.js +99 -0
  42. package/dist/utils/url-policy.js.map +1 -0
  43. package/package.json +4 -2
package/README.md CHANGED
@@ -19,17 +19,19 @@ with unique CSS selectors, and validate the replacement selector before re-runni
19
19
 
20
20
  ## Demo
21
21
 
22
- **Live endpoint** — a real `initialize` + `tools/list` round-trip against
23
- `https://playwright-e2e-mcp.vercel.app/api/mcp`:
22
+ **Hosted endpoint** — what an `initialize` + `tools/list` round-trip against
23
+ `https://playwright-e2e-mcp.vercel.app/api/mcp` returns for a client that sends the
24
+ bearer token (without one, only `list-tests` and `get-failure` are listed):
24
25
 
25
- ![Live endpoint: initialize handshake and all 8 tools](https://raw.githubusercontent.com/trajectiq-ai/E2E/main/docs/demo-endpoint.png)
26
+ ![Token-protected endpoint: initialize handshake and all 8 tools](https://raw.githubusercontent.com/trajectiq-ai/E2E/main/docs/demo-endpoint.png)
26
27
 
27
28
  **A real test run** — `run-test` served over stdio by `npx -y playwright-e2e-mcp`
28
29
  against the bundled `examples/sample-test.spec.ts` (actual output, unedited):
29
30
 
30
31
  ![run-test result: 4 passed, 0 failed, 5.1s](https://raw.githubusercontent.com/trajectiq-ai/E2E/main/docs/demo-run-test.png)
31
32
 
32
- Images are generated from real captured output with `node scripts/gen-demo-images.mjs`.
33
+ Images are rendered with `node scripts/gen-demo-images.mjs`: the run-test card is real
34
+ captured output; the endpoint card is an illustration of the authenticated listing.
33
35
 
34
36
  ## Install
35
37
 
@@ -40,7 +42,7 @@ and every other MCP client — pick whichever route fits:
40
42
  | --- | --- |
41
43
  | **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
42
44
  | **MCP Registry** (registry-aware clients discover it automatically) | `io.github.trajectiq-ai/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
43
- | **Any client, no npm account needed** | `npx -y github:trajectiq-ai/E2E` |
45
+ | **Any client, no npm account needed** | `npx -y github:trajectiq-ai/E2E#v0.1.3` (pin a release tag) |
44
46
  | **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/trajectiq-ai/E2E/releases) |
45
47
  | **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
46
48
 
@@ -66,7 +68,7 @@ Details and per-client config: [Installation](#installation) ·
66
68
 
67
69
  | Argument | Type | Description |
68
70
  | --- | --- | --- |
69
- | `projectRoot` | string | Project directory (default: server working directory) |
71
+ | `projectRoot` | string | Project directory inside the configured root (default: server working directory) |
70
72
  | `testFiles` | string[] | Files/directories relative to the root; `file:line` supported. Omit to run everything |
71
73
  | `grep` | string | Only run tests whose title matches this regex |
72
74
  | `browser` | `chromium` \| `firefox` \| `webkit` | Playwright project to run (matched against config project names) |
@@ -77,7 +79,7 @@ Details and per-client config: [Installation](#installation) ·
77
79
  | `config` | string | `playwright.config` path **or 1-based index** when the project has several |
78
80
  | `retryOnFailure` | boolean | Auto-retry failures **once** before reporting them (default `true`; ignored when `retries` is set) |
79
81
  | `lastFailed` | boolean | Only re-run tests that failed in the previous run (Playwright `--last-failed`) — the fast fix → re-run loop |
80
- | `args` | string[] | Extra CLI flags (shell metacharacters are rejected) |
82
+ | `args` | string[] | Extra Playwright flags from an allowlist (`--repeat-each=N`, `--max-failures=N`, `--update-snapshots`, `--shard=1/3`, `--trace=on`, …); values go after `=` and are checked, and flags that take a path, such as `--config` or `--output`, are rejected |
81
83
 
82
84
  Flakiness handling: by default the server injects `--retries=1` (unless the config
83
85
  already sets `retries`), so a test that passes on the retry is reported as **flaky**,
@@ -172,9 +174,9 @@ plain CSS.
172
174
  | --- | --- | --- |
173
175
  | `description` | string | What the test should cover (required) |
174
176
  | `pageUrl` | string | Page the test starts on (default: `baseURL` / `webServer.url` from config) |
175
- | `testDir` / `file` | string | Where to write the spec (default: detected `testDir` + `generated/<slug>.spec.ts`) |
177
+ | `testDir` / `file` | string | Where to write the spec (default: detected `testDir` + `generated/<slug>.spec.ts`); `file` must end in `.spec.*` or `.test.*` |
176
178
  | `write` | boolean | Write the file to disk (default `true`) |
177
- | `overwrite` | boolean | Replace an existing file at the target path |
179
+ | `overwrite` | boolean | Replace an existing spec at the target path; only specs this tool generated can be replaced |
178
180
  | `liveInspect` | boolean | Cross-check selectors against the live page (default on when a URL is known) |
179
181
  | `projectRoot` / `config` | string | As with the other tools |
180
182
 
@@ -236,11 +238,12 @@ Requirements:
236
238
  (`npx playwright install chromium`)
237
239
 
238
240
  **No npm account needed** — install straight from GitHub (the `prepare` script
239
- builds `dist/` automatically on install):
241
+ builds `dist/` automatically on install). Pin a release tag: an unpinned
242
+ `github:trajectiq-ai/E2E` runs whatever is on the default branch at that moment.
240
243
 
241
244
  ```bash
242
- npx -y github:trajectiq-ai/E2E
243
- npm install -D github:trajectiq-ai/E2E @playwright/test # or as a project dependency
245
+ npx -y github:trajectiq-ai/E2E#v0.1.3
246
+ npm install -D github:trajectiq-ai/E2E#v0.1.3 @playwright/test # or as a project dependency
244
247
  npx playwright install chromium
245
248
  ```
246
249
 
@@ -248,7 +251,7 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
248
251
  it locally:
249
252
 
250
253
  ```bash
251
- npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.0/playwright-e2e-mcp-0.1.0.tgz
254
+ npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.3/playwright-e2e-mcp-0.1.3.tgz
252
255
  ```
253
256
 
254
257
  Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
@@ -264,7 +267,7 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
264
267
  "mcpServers": {
265
268
  "playwright-e2e": {
266
269
  "command": "npx",
267
- "args": ["-y", "github:trajectiq-ai/E2E"],
270
+ "args": ["-y", "github:trajectiq-ai/E2E#v0.1.3"],
268
271
  "env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
269
272
  }
270
273
  }
@@ -278,8 +281,8 @@ when the client launches it somewhere else (e.g. your home directory).
278
281
  **Codex / VS Code / Copilot CLIs:**
279
282
 
280
283
  ```bash
281
- codex mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E
282
- code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:trajectiq-ai/E2E"]}'
284
+ codex mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.3
285
+ code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:trajectiq-ai/E2E#v0.1.3"]}'
283
286
  ```
284
287
 
285
288
  Codex's defaults fight this server: the first launch clones the repo and runs
@@ -290,7 +293,7 @@ Codex's defaults fight this server: the first launch clones the repo and runs
290
293
  ```toml
291
294
  [mcp_servers.playwright-e2e]
292
295
  command = "npx"
293
- args = ["-y", "github:trajectiq-ai/E2E"]
296
+ args = ["-y", "github:trajectiq-ai/E2E#v0.1.3"]
294
297
  startup_timeout_sec = 60
295
298
  tool_timeout_sec = 600
296
299
  ```
@@ -298,13 +301,14 @@ tool_timeout_sec = 600
298
301
  **Claude Desktop (one-click):** download and double-click the `.mcpb` Desktop
299
302
  Extension attached to the [latest release](https://github.com/trajectiq-ai/E2E/releases) —
300
303
  the bundle ships its own dependencies, so no Node setup is required. On install it
301
- prompts once for your **project root** (defaults to your home folder) and wires it
304
+ asks you to pick your **project root** (required, no default: choose the project
305
+ folder, not your home directory) and wires it
302
306
  into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first call.
303
307
 
304
308
  **Claude Code:**
305
309
 
306
310
  ```bash
307
- claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E
311
+ claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.3
308
312
  ```
309
313
 
310
314
  **Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
@@ -345,7 +349,7 @@ Streamable HTTP bridge for exactly that case:
345
349
  | --- | --- |
346
350
  | **Endpoint** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
347
351
  | **Transport** | MCP Streamable HTTP (`POST` JSON in, JSON or SSE out) |
348
- | **Auth** | none — the URL is public |
352
+ | **Auth** | bearer token (`PW_MCP_HTTP_TOKEN`). The deployment at this URL requires it; a bridge started without the variable serves only the read-only tools |
349
353
  | **Source** | [`api/mcp.ts`](api/mcp.ts) → [`src/http.ts`](src/http.ts) |
350
354
 
351
355
  The bridge runs the *same* `createServer()` as the stdio transport; the SDK
@@ -353,47 +357,88 @@ serves every request with a fresh server instance, which is what a serverless
353
357
  function wants. `test/http-bridge.test.mjs` drives the real Node adapter over
354
358
  `node:http` so a broken bridge fails in CI, not in ChatGPT.
355
359
 
360
+ **This deployment is token-protected.** `https://playwright-e2e-mcp.vercel.app`
361
+ has `PW_MCP_HTTP_TOKEN` set, so a request without `Authorization: Bearer <token>`
362
+ — including a ChatGPT connector created with authentication *None* — gets
363
+ `401 {"error":"unauthorized"}`. Ask the operator for the token, or run your own
364
+ bridge (below).
365
+
366
+ **Open vs. token-protected.** With `PW_MCP_HTTP_TOKEN` set (at least 16
367
+ characters; use a random value) all eight tools are served to clients that send
368
+ `Authorization: Bearer <token>`, and every other request gets `401`. Without that
369
+ variable anyone who reaches the URL can call the bridge, so it degrades to
370
+ `list-tests` and `get-failure` in restricted mode: `list-tests` scans sources
371
+ instead of running `playwright test --list` (which would execute the project's
372
+ config), callers cannot pick another `projectRoot`, and nothing spawns a process,
373
+ drives a browser or writes a file. Child processes started over HTTP get only an
374
+ allowlisted environment. `PW_MCP_ALLOWED_HOSTS` (comma separated, `*` for any)
375
+ limits the accepted `Host` header; without a token and without that variable,
376
+ only `localhost` names and the deployment's own Vercel hostnames are accepted
377
+ (DNS-rebinding protection).
378
+
356
379
  **Add it to ChatGPT:** Settings → Connectors → turn on **Advanced → Developer
357
- mode** → *Create custom connector* → paste the endpoint above → authentication
358
- **None**.
380
+ mode** → *Create custom connector* → paste the endpoint above. Authentication
381
+ **None** only works against a bridge with no token (read-only tools), so for this
382
+ deployment choose the connector's **API key** authentication and send
383
+ `Authorization: Bearer <token>` — or point the connector at your own deployment
384
+ with `PW_MCP_HTTP_TOKEN` unset.
385
+
386
+ To self-host the open, read-only variant, deploy this repo with
387
+ `PW_MCP_HTTP_TOKEN` unset; nothing else changes.
359
388
 
360
389
  Codex can also take the remote transport instead of spawning `npx`, if you'd
361
- rather not ship Playwright to every machine:
390
+ rather not ship Playwright to every machine. Point it at the token through an
391
+ environment variable so the secret stays out of the config file:
362
392
 
363
393
  ```bash
364
- codex mcp add playwright-e2e-remote --url https://playwright-e2e-mcp.vercel.app/api/mcp
394
+ export PW_MCP_HTTP_TOKEN=… # ask the operator for the value
395
+ codex mcp add playwright-e2e-remote --url https://playwright-e2e-mcp.vercel.app/api/mcp \
396
+ --bearer-token-env-var PW_MCP_HTTP_TOKEN
365
397
  ```
366
398
 
367
399
  **What to expect:** `list-tests` works and reports the specs bundled with the
368
- deployment. Tools that spawn a browser (`run-test`, `inspect-page`,
369
- `validate-selector`, `diagnose-flaky`, …) cannot download Chromium in a
370
- serverless function, so they return their normal `NO_PLAYWRIGHT` hint. Use the
371
- stdio install for real runs; the hosted endpoint is for discovery and for
372
- clients that cannot run local processes.
400
+ deployment. Even with a token, tools that spawn a browser (`run-test`,
401
+ `inspect-page`, `validate-selector`, `diagnose-flaky`, …) cannot download
402
+ Chromium in a serverless function, so they return their normal `NO_PLAYWRIGHT`
403
+ hint. Use the stdio install for real runs; the hosted endpoint is for discovery
404
+ and for clients that cannot run local processes.
373
405
 
374
406
  ```bash
375
- # verify the handshake without any client
407
+ # verify the handshake without any client (the live deployment needs the token;
408
+ # drop the authorization header and it answers 401 instead)
376
409
  curl -X POST https://playwright-e2e-mcp.vercel.app/api/mcp \
377
410
  -H 'content-type: application/json' \
378
411
  -H 'accept: application/json, text/event-stream' \
412
+ -H "authorization: Bearer $PW_MCP_HTTP_TOKEN" \
379
413
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
380
414
  ```
381
415
 
382
- Redeploy after a change:
383
-
384
- ```bash
385
- npx vercel deploy --yes --prod --token="$VERCEL_TOKEN"
386
- ```
416
+ Redeploy after a change: merge to `main`. Vercel's Git integration deploys
417
+ every push, so there is no token to manage and no CLI step — watch the
418
+ `Vercel` commit status for the deployment result.
387
419
 
388
420
  ## Configuration
389
421
 
390
422
  | Environment variable | Default | Purpose |
391
423
  | --- | --- | --- |
392
424
  | `PW_MCP_PROJECT_ROOT` | server cwd | Default project root for every tool |
393
- | `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error` \| `silent` |
394
- | `LOG_FORMAT` | `text` | `text` or `json` (structured) |
425
+ | `PW_MCP_ALLOWED_ROOTS` | — | Extra directories a caller may pass as `projectRoot` (`:`-separated, `;` on Windows). Anything outside these and the default root is rejected |
426
+ | `PW_MCP_HTTP_TOKEN` | — | HTTP bridge only: bearer token (16+ characters) that unlocks all tools (see above) |
427
+ | `PW_MCP_ALLOWED_HOSTS` | localhost + Vercel hostnames when there is no token | HTTP bridge only: comma-separated `Host` allowlist; `*` accepts any |
428
+ | `PW_MCP_PASSTHROUGH_ENV` | — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. `BASE_URL`) |
429
+ | `PW_MCP_MAX_CHILDREN` | `4` | HTTP bridge only: how many test runs and browser probes may run at once |
430
+ | `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 |
431
+ | `LOG_LEVEL` / `MCP_LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error` \| `silent`; `LOG_LEVEL` wins when both are set |
432
+ | `LOG_FORMAT` / `MCP_LOG_FORMAT` | `text` | `text`, or `json` (also `ndjson`) for one structured JSON object per line — ready for a log ingester |
433
+
434
+ Logs always go to **stderr** — stdout is reserved for the MCP protocol. Unrecognized values
435
+ fall back to the default, so a typo in `LOG_LEVEL` logs at `info` and one in `LOG_FORMAT`
436
+ logs as text rather than silencing the server. With `LOG_FORMAT=json` each line is a single
437
+ object (`time`, `level`, `message` plus context):
395
438
 
396
- Logs always go to **stderr** — stdout is reserved for the MCP protocol.
439
+ ```json
440
+ {"time":"2026-10-07T08:00:00.000Z","level":"info","message":"server ready","name":"playwright-e2e-mcp"}
441
+ ```
397
442
 
398
443
  ## Typical workflow
399
444
 
@@ -430,15 +475,42 @@ Logs always go to **stderr** — stdout is reserved for the MCP protocol.
430
475
  | Syntax error in a spec | `SYNTAX_ERROR` with file:line; nothing crashes; `list-tests` falls back to a source scan |
431
476
  | MCP client disconnects | Per-request `AbortSignal` kills the run; stdin end triggers shutdown, and every tracked child tree is force-killed (`killActiveChildren`) |
432
477
  | Disk full | `ENOSPC` detected → `DISK_FULL` with a "free space" hint; logging never throws |
433
- | Malicious paths | `../../etc/passwd`, absolute paths outside the root, URLs and null bytes are rejected with `INVALID_PATH`; CLI args are shell-metacharacter-checked |
478
+ | Malicious paths | `../../etc/passwd`, absolute paths outside the root, a `projectRoot` outside the allowed roots, symlinks that leave the root, URLs and null bytes are rejected with `INVALID_PATH`; extra CLI args must be allowlisted Playwright flags |
434
479
 
435
480
  ## Security notes
436
481
 
437
482
  - **No shell**: Playwright is spawned as `node <playwright/cli.js> …` with an argument
438
- array — no command interpolation.
439
- - **Path sandbox**: user paths are resolved lexically and must stay inside the project root.
483
+ array — no command interpolation. Extra `args` are limited to an allowlist of
484
+ Playwright flags, each with a checked value (`--flag=value`), so a caller cannot
485
+ swap in another `--config` or `--output` or hand git an option through
486
+ `--only-changed`. Paths with a segment starting with `-` are rejected, so a test
487
+ file name cannot be read as a flag.
488
+ - **Path sandbox**: user paths must stay inside the project root, checked lexically
489
+ and again with symlinks resolved. A caller-supplied `projectRoot` must sit inside
490
+ `PW_MCP_PROJECT_ROOT` (or a `PW_MCP_ALLOWED_ROOTS` entry).
491
+ - **Generated code**: `generate-e2e-test` only writes `*.spec.*` / `*.test.*` files,
492
+ only overwrites specs whose header it wrote itself, never writes through a symlink,
493
+ and escapes every value it puts into strings or comments.
494
+ - **HTTP bridge**: read-only tools unless `PW_MCP_HTTP_TOKEN` is set; child processes
495
+ started over HTTP get only an allowlisted environment (`PATH`, `HOME`, temp dirs,
496
+ locale, `CI`, `PLAYWRIGHT_*`, `npm_config_*` without embedded credentials, plus
497
+ anything in `PW_MCP_PASSTHROUGH_ENV`), at most `PW_MCP_MAX_CHILDREN` run at once
498
+ (a disconnected client frees its slot immediately), and internal error messages
499
+ are not returned to clients. The allowlist only covers the child's own
500
+ environment: test code runs as the same OS user, so on Linux it could still read
501
+ the server's startup environment from `/proc`. That is why only token holders
502
+ can run project code; keep other secrets out of the bridge's environment, or run
503
+ it under a separate user.
504
+ - **SSRF guard**: on the HTTP bridge (or with `PW_MCP_BLOCK_PRIVATE_URLS=1`) the URL tools
505
+ refuse hosts that resolve to loopback, private, link-local/metadata or reserved
506
+ addresses, and route the browser through a local proxy that applies the same check
507
+ to every redirect hop and subresource; IPv6 forms that embed an IPv4 address
508
+ (mapped, NAT64, 6to4, Teredo) are blocked too, and WebRTC UDP is disabled so a
509
+ page cannot reach the network around the proxy. It is off for stdio by default because
510
+ opening `http://localhost` dev servers is what these tools are for.
440
511
  - **Cleanup**: temp report/script files are written to the OS temp dir and removed;
441
- child processes are tracked and killed on shutdown.
512
+ child processes are tracked and killed on shutdown. Trace decompression has one
513
+ size budget per archive, and PNGs are capped at 16,384 px per side and 50 M pixels.
442
514
 
443
515
  ## Development
444
516
 
@@ -459,8 +531,10 @@ Zod v4 standard schemas; every tool declares spec tool annotations.
459
531
  ```bash
460
532
  npm install
461
533
  npm run build # tsc → dist/ (zero errors)
462
- npm test # build + test/run-tests.mjs (70 unit tests, any Node ≥20)
534
+ npm test # build + test/run-tests.mjs (unit tests, any Node ≥20)
463
535
  npm run e2e # build + e2e/run.mjs: live MCP ↔ Playwright integration suite
536
+ npm run mcpb # build + bundle dist/ into playwright-e2e-mcp-<version>.mcpb (+ .sha256)
537
+ npm run mcpb:smoke # ...then install that bundle in a temp dir, launch it and assert the handshake
464
538
  ```
465
539
 
466
540
  Tests cover the report parser (sample Playwright JSON, trace attachments), path utils
@@ -469,8 +543,12 @@ discovery, multiple configs, missing install, test-file scanning), the shared to
469
543
  helpers, the **trace reader** (synthetic trace.zip: error, failed action, DOM snapshot,
470
544
  `*.network` failed-request parsing, console error/warning events), the **image diff**
471
545
  (PNG round-trip, regions, color shift, dimension changes), the **change analyzer**
472
- (selector extraction, git + mtime paths) and the **flaky verdict logic**
473
- (failure signatures, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN).
546
+ (selector extraction, git + mtime paths), the **flaky verdict logic**
547
+ (failure signatures, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN),
548
+ the **HTTP bridge** (token, restricted mode, Host allowlist), the **security
549
+ regressions** (sandbox escapes, argument smuggling, symlink writes, code injection,
550
+ SSRF ranges, env scrubbing, decode limits), the `.mcpb` manifest, the `.mcpb` zip
551
+ extractor, and the MCP config files.
474
552
 
475
553
  ### Integration suite (`npm run e2e`)
476
554
 
package/dist/http.d.ts CHANGED
@@ -16,8 +16,26 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
16
16
  import type { McpHttpHandler } from '@modelcontextprotocol/server';
17
17
  /** Mirrors the SDK's default POST body bound, so oversized bodies die early. */
18
18
  export declare const MAX_BODY_BYTES: number;
19
+ export interface McpHttpHandlerOptions {
20
+ /**
21
+ * Bearer token clients must send (`Authorization: Bearer <token>`).
22
+ * Defaults to PW_MCP_HTTP_TOKEN. With a token every tool is served;
23
+ * without one only READ_ONLY_TOOLS are, in restricted mode, so an open
24
+ * endpoint can never spawn processes, drive a browser or write files.
25
+ */
26
+ token?: string;
27
+ /**
28
+ * Hostnames accepted in the Host header (DNS-rebinding protection).
29
+ * Defaults to PW_MCP_ALLOWED_HOSTS (comma separated; `*` allows any).
30
+ * When unset and there is no token, only localhost names and the
31
+ * deployment's own Vercel hostnames are accepted.
32
+ */
33
+ allowedHosts?: string[];
34
+ }
35
+ /** Tokens shorter than this are refused: they can be guessed. */
36
+ export declare const MIN_TOKEN_LENGTH = 16;
19
37
  /** Build the fetch-shaped MCP handler backed by a fresh server per request. */
20
- export declare function createMcpHttpHandler(): McpHttpHandler;
38
+ export declare function createMcpHttpHandler(options?: McpHttpHandlerOptions): McpHttpHandler;
21
39
  /**
22
40
  * Serve one Node request through the MCP handler.
23
41
  *
package/dist/http.js CHANGED
@@ -12,17 +12,90 @@
12
12
  * The stdio transport in server.ts is untouched; this is an additional way to
13
13
  * reach the same eight tools.
14
14
  */
15
- import { createMcpHandler } from '@modelcontextprotocol/server';
16
- import { createServer } from './server.js';
15
+ import { createHash, timingSafeEqual } from 'node:crypto';
16
+ import { createMcpHandler, hostHeaderValidationResponse } from '@modelcontextprotocol/server';
17
+ import { createServer, READ_ONLY_TOOLS } from './server.js';
18
+ import { setMaxChildren, setScrubChildEnv } from './utils/playwright-runner.js';
19
+ import { setBlockPrivateUrls } from './utils/url-policy.js';
17
20
  import { logger } from './utils/logger.js';
18
21
  /** Mirrors the SDK's default POST body bound, so oversized bodies die early. */
19
22
  export const MAX_BODY_BYTES = 4 * 1024 * 1024;
23
+ /** Tokens shorter than this are refused: they can be guessed. */
24
+ export const MIN_TOKEN_LENGTH = 16;
25
+ /** Default Host allowlist for an open (token-less) bridge. */
26
+ function defaultAllowedHosts() {
27
+ const vercel = [process.env.VERCEL_URL, process.env.VERCEL_BRANCH_URL, process.env.VERCEL_PROJECT_PRODUCTION_URL]
28
+ .map((host) => host?.trim().toLowerCase())
29
+ .filter((host) => Boolean(host));
30
+ return ['localhost', '127.0.0.1', '[::1]', ...vercel];
31
+ }
32
+ function envList(value) {
33
+ return (value ?? '')
34
+ .split(',')
35
+ .map((item) => item.trim())
36
+ .filter((item) => item !== '');
37
+ }
38
+ /** Constant-time comparison of the presented bearer token (hashed, so length does not leak). */
39
+ function tokenMatches(header, token) {
40
+ const match = /^Bearer\s+(.+)$/i.exec(header?.trim() ?? '');
41
+ if (!match)
42
+ return false;
43
+ const digest = (value) => createHash('sha256').update(value).digest();
44
+ return timingSafeEqual(digest(match[1].trim()), digest(token));
45
+ }
46
+ /** PW_MCP_MAX_CHILDREN as a positive integer; anything else means the default of 4. */
47
+ function maxChildrenFromEnv() {
48
+ const value = Number(process.env.PW_MCP_MAX_CHILDREN ?? '');
49
+ return Number.isInteger(value) && value > 0 ? value : 4;
50
+ }
51
+ function jsonResponse(status, body, headers = {}) {
52
+ return new Response(JSON.stringify(body), {
53
+ status,
54
+ headers: { 'content-type': 'application/json', ...headers },
55
+ });
56
+ }
20
57
  /** Build the fetch-shaped MCP handler backed by a fresh server per request. */
21
- export function createMcpHttpHandler() {
22
- return createMcpHandler(() => createServer(), {
58
+ export function createMcpHttpHandler(options = {}) {
59
+ const token = (options.token ?? process.env.PW_MCP_HTTP_TOKEN ?? '').trim();
60
+ if (token && token.length < MIN_TOKEN_LENGTH) {
61
+ throw new Error(`PW_MCP_HTTP_TOKEN must be at least ${MIN_TOKEN_LENGTH} characters (use a random value).`);
62
+ }
63
+ const configuredHosts = options.allowedHosts ?? envList(process.env.PW_MCP_ALLOWED_HOSTS);
64
+ const allowedHosts = configuredHosts.includes('*')
65
+ ? []
66
+ : configuredHosts.length > 0 || token
67
+ ? configuredHosts
68
+ : defaultAllowedHosts();
69
+ // Children spawned on behalf of HTTP callers must not see deployment
70
+ // secrets, and URL tools must not reach the deployment's private network.
71
+ setScrubChildEnv(true);
72
+ setMaxChildren(maxChildrenFromEnv());
73
+ setBlockPrivateUrls(true);
74
+ if (!token) {
75
+ logger.warn('PW_MCP_HTTP_TOKEN is not set; serving read-only tools only', { tools: READ_ONLY_TOOLS });
76
+ }
77
+ const inner = createMcpHandler((context) => createServer({
78
+ ...(token ? {} : { tools: READ_ONLY_TOOLS, restricted: true }),
79
+ // Lets tools stop their children when the HTTP client disconnects.
80
+ requestSignal: context?.requestInfo?.signal,
81
+ }), {
23
82
  legacy: 'stateless',
24
83
  onerror: (error) => logger.error('mcp http handler error', { error }),
25
84
  });
85
+ return {
86
+ ...inner,
87
+ fetch: async (request, requestOptions) => {
88
+ if (allowedHosts.length > 0) {
89
+ const rejected = hostHeaderValidationResponse(request, allowedHosts);
90
+ if (rejected)
91
+ return rejected;
92
+ }
93
+ if (token && !tokenMatches(request.headers.get('authorization'), token)) {
94
+ return jsonResponse(401, { error: 'unauthorized' }, { 'www-authenticate': 'Bearer' });
95
+ }
96
+ return inner.fetch(request, requestOptions);
97
+ },
98
+ };
26
99
  }
27
100
  /** A failure that maps onto an HTTP status before any response is written. */
28
101
  class RequestError extends Error {
@@ -59,17 +132,18 @@ async function readBody(req) {
59
132
  const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
60
133
  size += buf.byteLength;
61
134
  if (size > MAX_BODY_BYTES) {
62
- req.destroy();
135
+ // Stop reading; the caller answers 413 and then closes the connection.
136
+ req.pause();
63
137
  throw new RequestError(413, 'request body too large');
64
138
  }
65
139
  chunks.push(buf);
66
140
  }
67
141
  return Buffer.concat(chunks, size);
68
142
  }
69
- function buildRequest(req, method, body) {
143
+ function buildRequest(req, method, body, signal) {
70
144
  const protocol = (firstHeader(req.headers['x-forwarded-proto']) ?? 'http').split(',')[0].trim();
71
145
  const host = firstHeader(req.headers.host) ?? 'localhost';
72
- const init = { method, headers: toHeaders(req.headers) };
146
+ const init = { method, headers: toHeaders(req.headers), signal };
73
147
  if (body && body.byteLength > 0)
74
148
  init.body = body;
75
149
  return new Request(`${protocol}://${host}${req.url ?? '/'}`, init);
@@ -93,11 +167,18 @@ function waitDrain(res) {
93
167
  * mid-stream failure closes the socket so the client stops waiting.
94
168
  */
95
169
  export async function handleNodeRequest(handler, req, res) {
170
+ // Abort the request (and the tool's children) when the client goes away
171
+ // before the response is complete, so its child slot is freed at once.
172
+ const disconnect = new AbortController();
173
+ res.once('close', () => {
174
+ if (!res.writableFinished)
175
+ disconnect.abort();
176
+ });
96
177
  let response;
97
178
  try {
98
179
  const method = (req.method ?? 'GET').toUpperCase();
99
180
  const body = method === 'GET' || method === 'HEAD' ? undefined : await readBody(req);
100
- response = await handler.fetch(buildRequest(req, method, body));
181
+ response = await handler.fetch(buildRequest(req, method, body, disconnect.signal));
101
182
  }
102
183
  catch (err) {
103
184
  const status = err instanceof RequestError ? err.status : 500;
@@ -107,7 +188,15 @@ export async function handleNodeRequest(handler, req, res) {
107
188
  if (!res.headersSent && !res.writableEnded) {
108
189
  res.statusCode = status;
109
190
  res.setHeader('content-type', 'application/json');
110
- res.end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
191
+ // Only our own RequestError messages are meant for clients; anything
192
+ // else may carry paths or internals, so it stays in the server log.
193
+ const message = err instanceof RequestError ? err.message : 'internal server error';
194
+ if (status === 413)
195
+ res.setHeader('connection', 'close');
196
+ res.end(JSON.stringify({ error: message }), () => {
197
+ if (status === 413)
198
+ req.destroy();
199
+ });
111
200
  }
112
201
  else if (!res.writableEnded) {
113
202
  res.destroy();
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -33,9 +33,17 @@ async function main() {
33
33
  'Usage: playwright-e2e-mcp [--version] [--help]',
34
34
  '',
35
35
  'Connects over stdio (MCP). Configuration via environment:',
36
- ' PW_MCP_PROJECT_ROOT default project root (default: cwd)',
37
- ' LOG_LEVEL debug | info | warn | error | silent (default: info)',
38
- ' LOG_FORMAT text | json (default: text)',
36
+ ' PW_MCP_PROJECT_ROOT default project root (default: cwd)',
37
+ ' PW_MCP_ALLOWED_ROOTS extra roots callers may pass as projectRoot',
38
+ ' PW_MCP_BLOCK_PRIVATE_URLS 1 = URL tools refuse private/loopback/metadata addresses',
39
+ ' LOG_LEVEL / MCP_LOG_LEVEL debug | info | warn | error | silent (default: info)',
40
+ ' LOG_FORMAT / MCP_LOG_FORMAT text | json (default: text)',
41
+ '',
42
+ 'HTTP bridge only (api/mcp.ts, src/http.ts):',
43
+ ' PW_MCP_HTTP_TOKEN bearer token (16+ chars) that unlocks all tools',
44
+ ' PW_MCP_ALLOWED_HOSTS Host allowlist, comma separated (* = any)',
45
+ ' PW_MCP_PASSTHROUGH_ENV extra variables passed to test runs',
46
+ ' PW_MCP_MAX_CHILDREN concurrent runs (default: 4)',
39
47
  '',
40
48
  ].join('\n'));
41
49
  return;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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,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,gDAAgD;YAChD,EAAE;YACF,2DAA2D;YAC3D,6DAA6D;YAC7D,8EAA8E;YAC9E,qDAAqD;YACrD,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,OAAO;IACT,CAAC;IAED,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,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,CAAC"}
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,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,gDAAgD;YAChD,EAAE;YACF,2DAA2D;YAC3D,kEAAkE;YAClE,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,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,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,CAAC"}
package/dist/server.d.ts CHANGED
@@ -14,7 +14,20 @@ export interface CreateServerOptions {
14
14
  projectRoot?: string;
15
15
  /** Share a store across servers (tests). */
16
16
  store?: ToolStore;
17
+ /** Register only these tools (default: all). Used by the hosted HTTP bridge. */
18
+ tools?: readonly string[];
19
+ /** Unauthenticated HTTP mode: see ToolContext.restricted. */
20
+ restricted?: boolean;
21
+ /** Aborted when the HTTP client goes away; combined with the MCP request signal. */
22
+ requestSignal?: AbortSignal;
17
23
  }
24
+ /**
25
+ * Tools that neither drive a browser nor write files. The HTTP bridge
26
+ * serves only these unless it is protected by a token, and runs them in
27
+ * restricted mode, where list-tests scans sources instead of spawning
28
+ * Playwright (which would execute the project's config and spec files).
29
+ */
30
+ export declare const READ_ONLY_TOOLS: readonly string[];
18
31
  export declare function resolveDefaultProjectRoot(): string;
19
32
  export declare function createServer(options?: CreateServerOptions): McpServer;
20
33
  /** Close the server, kill orphaned children, and exit. */