playwright-e2e-mcp 0.1.2 → 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 (2) hide show
  1. package/README.md +57 -31
  2. package/package.json +4 -2
package/README.md CHANGED
@@ -42,7 +42,7 @@ and every other MCP client — pick whichever route fits:
42
42
  | --- | --- |
43
43
  | **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
44
44
  | **MCP Registry** (registry-aware clients discover it automatically) | `io.github.trajectiq-ai/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
45
- | **Any client, no npm account needed** | `npx -y github:trajectiq-ai/E2E#v0.1.2` (pin a release tag) |
45
+ | **Any client, no npm account needed** | `npx -y github:trajectiq-ai/E2E#v0.1.3` (pin a release tag) |
46
46
  | **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/trajectiq-ai/E2E/releases) |
47
47
  | **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
48
48
 
@@ -242,8 +242,8 @@ builds `dist/` automatically on install). Pin a release tag: an unpinned
242
242
  `github:trajectiq-ai/E2E` runs whatever is on the default branch at that moment.
243
243
 
244
244
  ```bash
245
- npx -y github:trajectiq-ai/E2E#v0.1.2
246
- npm install -D github:trajectiq-ai/E2E#v0.1.2 @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
247
247
  npx playwright install chromium
248
248
  ```
249
249
 
@@ -251,7 +251,7 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
251
251
  it locally:
252
252
 
253
253
  ```bash
254
- npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.2/playwright-e2e-mcp-0.1.2.tgz
254
+ npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.3/playwright-e2e-mcp-0.1.3.tgz
255
255
  ```
256
256
 
257
257
  Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
@@ -267,7 +267,7 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
267
267
  "mcpServers": {
268
268
  "playwright-e2e": {
269
269
  "command": "npx",
270
- "args": ["-y", "github:trajectiq-ai/E2E#v0.1.2"],
270
+ "args": ["-y", "github:trajectiq-ai/E2E#v0.1.3"],
271
271
  "env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
272
272
  }
273
273
  }
@@ -281,8 +281,8 @@ when the client launches it somewhere else (e.g. your home directory).
281
281
  **Codex / VS Code / Copilot CLIs:**
282
282
 
283
283
  ```bash
284
- codex mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.2
285
- code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:trajectiq-ai/E2E#v0.1.2"]}'
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"]}'
286
286
  ```
287
287
 
288
288
  Codex's defaults fight this server: the first launch clones the repo and runs
@@ -293,7 +293,7 @@ Codex's defaults fight this server: the first launch clones the repo and runs
293
293
  ```toml
294
294
  [mcp_servers.playwright-e2e]
295
295
  command = "npx"
296
- args = ["-y", "github:trajectiq-ai/E2E#v0.1.2"]
296
+ args = ["-y", "github:trajectiq-ai/E2E#v0.1.3"]
297
297
  startup_timeout_sec = 60
298
298
  tool_timeout_sec = 600
299
299
  ```
@@ -308,7 +308,7 @@ into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first
308
308
  **Claude Code:**
309
309
 
310
310
  ```bash
311
- claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.2
311
+ claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.3
312
312
  ```
313
313
 
314
314
  **Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
@@ -349,7 +349,7 @@ Streamable HTTP bridge for exactly that case:
349
349
  | --- | --- |
350
350
  | **Endpoint** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
351
351
  | **Transport** | MCP Streamable HTTP (`POST` JSON in, JSON or SSE out) |
352
- | **Auth** | optional bearer token (`PW_MCP_HTTP_TOKEN`); without one only read-only tools are served |
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 |
353
353
  | **Source** | [`api/mcp.ts`](api/mcp.ts) → [`src/http.ts`](src/http.ts) |
354
354
 
355
355
  The bridge runs the *same* `createServer()` as the stdio transport; the SDK
@@ -357,28 +357,43 @@ serves every request with a fresh server instance, which is what a serverless
357
357
  function wants. `test/http-bridge.test.mjs` drives the real Node adapter over
358
358
  `node:http` so a broken bridge fails in CI, not in ChatGPT.
359
359
 
360
- **Open vs. token-protected.** When the deployment has no `PW_MCP_HTTP_TOKEN`,
361
- anyone can reach the URL, so the bridge serves only `list-tests` and
362
- `get-failure`, in restricted mode: `list-tests` scans sources instead of running
363
- `playwright test --list` (which would execute the project's config), callers
364
- cannot pick another `projectRoot`, and nothing spawns a process, drives a browser
365
- or writes a file. Set `PW_MCP_HTTP_TOKEN` (at least 16 characters; use a random
366
- value) to serve all eight tools to clients that send `Authorization: Bearer <token>`;
367
- other requests get `401`. Child processes started over HTTP get only an allowlisted
368
- environment. `PW_MCP_ALLOWED_HOSTS` (comma separated, `*` for any) limits the
369
- accepted `Host` header; without a token and without that variable, only
370
- `localhost` names and the deployment's own Vercel hostnames are accepted
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
371
377
  (DNS-rebinding protection).
372
378
 
373
379
  **Add it to ChatGPT:** Settings → Connectors → turn on **Advanced → Developer
374
- mode** → *Create custom connector* → paste the endpoint above → authentication
375
- **None** (read-only tools).
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.
376
388
 
377
389
  Codex can also take the remote transport instead of spawning `npx`, if you'd
378
- 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:
379
392
 
380
393
  ```bash
381
- 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
382
397
  ```
383
398
 
384
399
  **What to expect:** `list-tests` works and reports the specs bundled with the
@@ -389,10 +404,12 @@ hint. Use the stdio install for real runs; the hosted endpoint is for discovery
389
404
  and for clients that cannot run local processes.
390
405
 
391
406
  ```bash
392
- # 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)
393
409
  curl -X POST https://playwright-e2e-mcp.vercel.app/api/mcp \
394
410
  -H 'content-type: application/json' \
395
411
  -H 'accept: application/json, text/event-stream' \
412
+ -H "authorization: Bearer $PW_MCP_HTTP_TOKEN" \
396
413
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
397
414
  ```
398
415
 
@@ -411,10 +428,17 @@ every push, so there is no token to manage and no CLI step — watch the
411
428
  | `PW_MCP_PASSTHROUGH_ENV` | — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. `BASE_URL`) |
412
429
  | `PW_MCP_MAX_CHILDREN` | `4` | HTTP bridge only: how many test runs and browser probes may run at once |
413
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 |
414
- | `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error` \| `silent` |
415
- | `LOG_FORMAT` | `text` | `text` or `json` (structured) |
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):
416
438
 
417
- 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
+ ```
418
442
 
419
443
  ## Typical workflow
420
444
 
@@ -509,6 +533,8 @@ npm install
509
533
  npm run build # tsc → dist/ (zero errors)
510
534
  npm test # build + test/run-tests.mjs (unit tests, any Node ≥20)
511
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
512
538
  ```
513
539
 
514
540
  Tests cover the report parser (sample Playwright JSON, trace attachments), path utils
@@ -521,8 +547,8 @@ helpers, the **trace reader** (synthetic trace.zip: error, failed action, DOM sn
521
547
  (failure signatures, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN),
522
548
  the **HTTP bridge** (token, restricted mode, Host allowlist), the **security
523
549
  regressions** (sandbox escapes, argument smuggling, symlink writes, code injection,
524
- SSRF ranges, env scrubbing, decode limits), the `.mcpb` manifest and the MCP config
525
- files.
550
+ SSRF ranges, env scrubbing, decode limits), the `.mcpb` manifest, the `.mcpb` zip
551
+ extractor, and the MCP config files.
526
552
 
527
553
  ### Integration suite (`npm run e2e`)
528
554
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "playwright-e2e-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "MCP server that runs, debugs, and inspects Playwright end-to-end tests from any MCP client",
5
+ "author": "trajectiq-ai <trajectiq@gmail.com>",
5
6
  "mcpName": "io.github.trajectiq-ai/E2E",
6
7
  "type": "module",
7
8
  "license": "MIT",
@@ -49,6 +50,7 @@
49
50
  "test": "npm run build && node test/run-tests.mjs",
50
51
  "e2e": "npm run build && node e2e/run.mjs",
51
52
  "mcpb": "npm run build && node scripts/build-mcpb.mjs",
53
+ "mcpb:smoke": "npm run mcpb && node scripts/mcpb-launch-sim.mjs",
52
54
  "prepublishOnly": "npm test"
53
55
  },
54
56
  "engines": {
@@ -56,7 +58,7 @@
56
58
  },
57
59
  "dependencies": {
58
60
  "zod": "^4.2.0",
59
- "@modelcontextprotocol/server": "^2.3.0"
61
+ "@modelcontextprotocol/server": "^2.3.1"
60
62
  },
61
63
  "devDependencies": {
62
64
  "@playwright/test": "1.63.0",