playwright-e2e-mcp 0.4.1 → 0.5.0
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 +215 -43
- package/dist/cli/init.js +3 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/http.d.ts +6 -1
- package/dist/http.js +13 -3
- package/dist/http.js.map +1 -1
- package/dist/oauth.d.ts +34 -0
- package/dist/oauth.js +346 -0
- package/dist/oauth.js.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +31 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze-history.d.ts +12 -1
- package/dist/tools/analyze-history.js +89 -5
- package/dist/tools/analyze-history.js.map +1 -1
- package/dist/tools/audit-accessibility.d.ts +85 -0
- package/dist/tools/audit-accessibility.js +4 -1
- package/dist/tools/audit-accessibility.js.map +1 -1
- package/dist/tools/audit-performance.d.ts +333 -0
- package/dist/tools/audit-performance.js +377 -0
- package/dist/tools/audit-performance.js.map +1 -0
- package/dist/tools/compare-visual-state.d.ts +84 -0
- package/dist/tools/generate-e2e-test.d.ts +90 -0
- package/dist/tools/generate-e2e-test.js +223 -34
- package/dist/tools/generate-e2e-test.js.map +1 -1
- package/dist/tools/get-failure.js +2 -1
- package/dist/tools/get-failure.js.map +1 -1
- package/dist/tools/inspect-page.d.ts +94 -0
- package/dist/tools/inspect-page.js +42 -5
- package/dist/tools/inspect-page.js.map +1 -1
- package/dist/tools/load-report.d.ts +48 -0
- package/dist/tools/load-report.js +167 -0
- package/dist/tools/load-report.js.map +1 -0
- package/dist/tools/probe-script.d.ts +7 -0
- package/dist/tools/probe-script.js +256 -7
- package/dist/tools/probe-script.js.map +1 -1
- package/dist/tools/shared.d.ts +137 -2
- package/dist/tools/shared.js +155 -8
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/suggest-fix.d.ts +35 -1
- package/dist/tools/suggest-fix.js +197 -17
- package/dist/tools/suggest-fix.js.map +1 -1
- package/dist/tools/validate-selector.d.ts +84 -0
- package/dist/tools/validate-selector.js +7 -1
- package/dist/tools/validate-selector.js.map +1 -1
- package/dist/types/index.d.ts +28 -0
- package/dist/utils/project-detector.d.ts +7 -0
- package/dist/utils/project-detector.js +11 -0
- package/dist/utils/project-detector.js.map +1 -1
- package/dist/utils/report-parser.d.ts +28 -3
- package/dist/utils/report-parser.js +77 -11
- package/dist/utils/report-parser.js.map +1 -1
- package/dist/utils/run-history.d.ts +66 -3
- package/dist/utils/run-history.js +149 -3
- package/dist/utils/run-history.js.map +1 -1
- package/package.json +5 -3
- package/skill/playwright-e2e-mcp/SKILL.md +71 -15
- package/skill/playwright-e2e-mcp/references/setup.md +1 -1
- package/skill/playwright-e2e-mcp/references/tools.md +67 -6
package/README.md
CHANGED
|
@@ -40,9 +40,13 @@ run-test ──▶ get-failure ──▶ suggest-fix (apply + re-run) ──▶
|
|
|
40
40
|
| 🔍 | "Why did this fail?" | Reads Playwright's trace: the page at the moment of failure, the broken request, the console error. No guessing. |
|
|
41
41
|
| 🛠️ | "Fix it" | Swaps in a locator proven unique on the page, **re-runs the test**, and undoes the edit if it's still red. If the button is really gone, it tells you it's an app bug instead of hiding it. |
|
|
42
42
|
| 🎲 | "Is this test flaky?" | Re-runs it many ways (repeated, alone, in random order) and names the exact test and seed that cause the flake. |
|
|
43
|
-
| 📈 | "What's been breaking lately?" | Keeps a local run history and separates flaky, newly broken and always-broken tests
|
|
43
|
+
| 📈 | "What's been breaking lately?" | Keeps a local run history and separates flaky, newly broken and always-broken tests; shows the slowest tests, stability by day and **the commit where each test went bad**. |
|
|
44
|
+
| ☁️ | "Why did CI fail?" | Loads the CI job's report (or merges sharded blob reports), maps its paths onto your checkout and finds the traces in the downloaded artifact, so the same diagnosis and fixes work on CI failures. |
|
|
45
|
+
| ✍️ | "Write a test for this flow" | Walks the steps on the live page first, writes a spec that replays them with assertions on where the flow landed (URL and accessibility snapshot), and runs it once to prove it passes. |
|
|
44
46
|
| ♿ | "Check this page for accessibility" | Runs axe-core (WCAG 2.2 AA) and returns each problem with a ready-to-paste locator and regression test. |
|
|
45
|
-
|
|
|
47
|
+
| ⚡ | "Why is this page slow?" | Measures Web Vitals (LCP, CLS, INP, TBT) on desktop or a throttled phone, names the slow element and the elements that jump, and hands back a budget test. |
|
|
48
|
+
| 🧪 | "Show me the error state" | Mocks API responses (500s, empty lists, slow calls) so the AI can inspect, audit or measure states that are hard to reach. |
|
|
49
|
+
| 🔐 | "Test the page after login" | Works behind sign-in with saved sessions, headers and click/fill steps, in Chromium, Firefox or WebKit, and can record or replay network traffic from a HAR file. |
|
|
46
50
|
| 🤖 | "Do it in CI" | A [GitHub Action and `ci` command](#ci-github-action-and-ci-command) post the diagnosis, flaky verdict and fix diffs on your PR. |
|
|
47
51
|
|
|
48
52
|
**Why it stands out**
|
|
@@ -55,6 +59,14 @@ run-test ──▶ get-failure ──▶ suggest-fix (apply + re-run) ──▶
|
|
|
55
59
|
(locators, waiting, auth, test data, mocking, flake patterns, review checklist).
|
|
56
60
|
- **Ready in one line.** `npx -y playwright-e2e-mcp init` sets up Claude Code, Cursor and VS Code.
|
|
57
61
|
|
|
62
|
+
### Free and open source, for good
|
|
63
|
+
|
|
64
|
+
- **MIT licensed.** Use it, change it, ship it in commercial work; no fees, no paid tier, no feature held back.
|
|
65
|
+
- **No account, no API key, no sign-up.** `npx -y playwright-e2e-mcp init` is the whole setup.
|
|
66
|
+
- **No telemetry.** It never phones home; your tests, traces and run history stay on your machine.
|
|
67
|
+
- **Free dependencies only:** the MCP SDK (Apache-2.0), zod (MIT), axe-core (MPL-2.0) and the Playwright your project already has (Apache-2.0).
|
|
68
|
+
- **Free to host yourself**, too: the HTTP bridge deploys to a free Vercel account (see [Hosted endpoint](#hosted-endpoint-chatgpt--remote-clients)).
|
|
69
|
+
|
|
58
70
|
<details>
|
|
59
71
|
<summary><b>The technical details</b></summary>
|
|
60
72
|
|
|
@@ -75,8 +87,16 @@ run-test ──▶ get-failure ──▶ suggest-fix (apply + re-run) ──▶
|
|
|
75
87
|
flaky, regressed and broken tests from the local run record.
|
|
76
88
|
- **Accessibility.** `audit-accessibility` runs axe-core against WCAG 2.2 AA on any page,
|
|
77
89
|
signed in or after steps, with offending elements as verified locators.
|
|
78
|
-
- **
|
|
79
|
-
|
|
90
|
+
- **Performance.** `audit-performance` measures lab Web Vitals (LCP, CLS, TBT, FCP, TTFB, and
|
|
91
|
+
INP for the interactions in `actions`), optionally as a throttled phone and as the median of
|
|
92
|
+
several runs, rates them against Google's thresholds or your budgets, and names the LCP
|
|
93
|
+
element and the elements that shifted as verified locators.
|
|
94
|
+
- **Ambiguous locators.** When a locator suddenly matches two elements (strict mode
|
|
95
|
+
violation), `suggest-fix` takes the unique locator Playwright reports for the intended
|
|
96
|
+
match: the exact-name one, or the one you pick.
|
|
97
|
+
- **Pages behind a login, in any state.** Every page tool accepts a Playwright
|
|
98
|
+
`storageState`, extra headers, click/fill steps to reach a modal or a later step, and
|
|
99
|
+
network mocks to force error, empty and slow states.
|
|
80
100
|
|
|
81
101
|
</details>
|
|
82
102
|
|
|
@@ -131,7 +151,7 @@ npx -y playwright-e2e-mcp init # --client all | cursor,vscode … ·
|
|
|
131
151
|
| **Skill only, any agent** | `npx skills add xsignon-secure/E2E` |
|
|
132
152
|
| **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
|
|
133
153
|
| **MCP Registry** (registry-aware clients discover it automatically) | `io.github.xsignon-secure/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
|
|
134
|
-
| **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.
|
|
154
|
+
| **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.5.0` (pin a release tag) |
|
|
135
155
|
| **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/xsignon-secure/E2E/releases) |
|
|
136
156
|
| **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
|
|
137
157
|
|
|
@@ -143,7 +163,7 @@ code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","playwrigh
|
|
|
143
163
|
```
|
|
144
164
|
|
|
145
165
|
Only need the fix loop? `--tools=core` (or `PW_MCP_TOOLS=core`) exposes six tools and
|
|
146
|
-
|
|
166
|
+
cuts the tool-definition context by about three quarters; see [Configuration](#configuration).
|
|
147
167
|
|
|
148
168
|
Details and per-client config: [Installation](#installation) ·
|
|
149
169
|
[MCP client configuration](#mcp-client-configuration).
|
|
@@ -157,30 +177,53 @@ Details and per-client config: [Installation](#installation) ·
|
|
|
157
177
|
| `run-test` | Run Playwright tests and return stats, failures, diagnostics and hints; reports progress, and `background: true` returns a run id for long suites |
|
|
158
178
|
| `get-run-status` | Progress or final result of a background run; can wait for it or cancel it |
|
|
159
179
|
| `get-failure` | Deep analysis of one failure: stack, expected/actual, **DOM snapshot at failure (from the Playwright trace)**, failed requests, console errors, next steps |
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
180
|
+
| `load-report` | Load a run from CI: a JSON report or a folder of sharded blob reports; CI paths are mapped onto the checkout and traces found in the unpacked artifact, so `get-failure`, `suggest-fix` and `diagnose-flaky` work on it, and the run joins the history with its commit |
|
|
181
|
+
| `suggest-fix` | Patch a failure: a drifted locator is replaced with one **proven unique** on the DOM at failure, an ambiguous one (strict mode violation) gets the unique locator of the intended match, changed copy gets the new expected text; `apply: true` writes it, re-runs the test and reverts if still red |
|
|
182
|
+
| `inspect-page` | Open a URL headlessly (optionally signed in, after steps) and return elements with **verified Playwright locators**, CSS selectors, visibility, text and console output, or the **accessibility snapshot with a ready `toMatchAriaSnapshot` assertion** |
|
|
162
183
|
| `list-tests` | List available tests (`file`, `line`, full title, projects) with filtering |
|
|
163
184
|
| `validate-selector` | Check a CSS selector, Playwright selector or **locator expression** against a live page: validity, match count, and a sturdier verified locator for each match |
|
|
164
|
-
| `generate-e2e-test` | Scaffold a Playwright test from a description using the project's **real** selectors and verified locators from the live page |
|
|
185
|
+
| `generate-e2e-test` | Scaffold a Playwright test from a description using the project's **real** selectors and verified locators from the live page, or **walk a flow** step by step on the live page and write a spec that is run once to prove it passes |
|
|
165
186
|
| `compare-visual-state` | Visual regression: screenshot before/after a change and report *what* moved and how colors shifted |
|
|
166
187
|
| `audit-accessibility` | Run axe-core (WCAG 2.2 AA by default) on a page, signed in or after steps, and return violations worst first with **verified locators** for the offending elements and a regression check |
|
|
188
|
+
| `audit-performance` | Measure lab **Web Vitals** (LCP, CLS, TBT, FCP, TTFB, INP during steps), optionally as a throttled phone and the median of several runs; rate them or check budgets, name the LCP and shifting elements as verified locators, list heavy and render-blocking requests, and return a budget test |
|
|
167
189
|
| `diagnose-flaky` | Run a failing test 2–10 times **with retries disabled** and return an evidence verdict: `CONSISTENTLY FAILING`, `FLAKY` or `NOT REPRODUCING`; tells parallelism and **test-order** bugs from races |
|
|
168
|
-
| `analyze-history` | Rank flaky, regressed and broken tests from the local run history, group failures by cause, or show one test's timeline |
|
|
190
|
+
| `analyze-history` | Rank flaky, regressed and broken tests from the local run history, group failures by cause, list the slowest tests, show stability by day, name **the commit where each test went bad**, or show one test's timeline |
|
|
169
191
|
|
|
170
192
|
Two **prompts** package the main workflows for clients that show them as slash commands:
|
|
171
193
|
`fix-failing-test` (optional `test`) and `triage-flaky-tests`.
|
|
172
194
|
|
|
173
195
|
### Page state: signed-in pages, headers and steps
|
|
174
196
|
|
|
175
|
-
`inspect-page`, `validate-selector
|
|
176
|
-
|
|
197
|
+
`inspect-page`, `validate-selector`, `compare-visual-state`, `audit-accessibility` and
|
|
198
|
+
`audit-performance` accept the same page-state arguments (`suggest-fix` accepts
|
|
199
|
+
`storageState` and `headers` for a live `url`):
|
|
177
200
|
|
|
178
201
|
| Argument | Type | Description |
|
|
179
202
|
| --- | --- | --- |
|
|
180
203
|
| `storageState` | string | Path inside the project to a Playwright storageState JSON (cookies + localStorage), e.g. `playwright/.auth/user.json` from your setup project. Defaults to `PW_MCP_STORAGE_STATE` |
|
|
181
204
|
| `headers` | object | Extra HTTP headers for every request, e.g. `{ "Authorization": "Bearer …" }` |
|
|
182
205
|
| `actions` | array | Up to 20 steps run after load: `{ "type": "click" \| "dblclick" \| "hover" \| "fill" \| "press" \| "check" \| "uncheck" \| "select" \| "wait" \| "goto", "locator"?, "value"?, "url"?, "ms"? }`. Locators use Playwright syntax, e.g. `getByRole('button', { name: 'Open settings' })` |
|
|
206
|
+
| `routes` | array | Up to 20 network mocks applied before the page loads, first match wins: `{ "url": "**/api/cart", "method"?, "status"?, "json"? \| "body"?, "contentType"?, "headers"?, "abort"?, "delayMs"? }`. `json`, `body` or `status` fulfils the request, `abort: true` fails it, and `delayMs` alone slows the real request |
|
|
183
207
|
| `viewport` | object | `{ "width": 390, "height": 844 }` (default 1280×720) |
|
|
208
|
+
| `har` | object | `{ "path": "tests/fixtures/cart.har", "mode"?: "replay" \| "record", "url"?: "**/api/**", "notFound"?: "abort" \| "fallback" }`. `replay` (default) answers matching requests from the file, `record` saves the page's traffic to it. The file and its folder must be inside the project. `routes` mocks still win over the HAR |
|
|
209
|
+
| `browser` | `chromium` \| `firefox` \| `webkit` | Browser engine (default `chromium`; the engine must be installed with `npx playwright install`). `audit-performance` is Chromium-only, and WebKit is refused while private addresses are blocked |
|
|
210
|
+
|
|
211
|
+
Mocks make states that are hard to reach easy to inspect, audit or measure: the error
|
|
212
|
+
banner after a 500, the empty list, the spinner of a slow API, the page without a
|
|
213
|
+
third-party script. The response says how many requests each mock handled and flags a mock
|
|
214
|
+
that matched nothing, which usually means a wrong glob:
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
"routes": [
|
|
218
|
+
{ "url": "**/api/cart", "json": { "items": [] } },
|
|
219
|
+
{ "url": "**/api/checkout", "method": "POST", "status": 500, "body": "boom" },
|
|
220
|
+
{ "url": "**/googletagmanager.com/**", "abort": true }
|
|
221
|
+
]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
A HAR makes a page repeatable: record it once against a working backend
|
|
225
|
+
(`"mode": "record"`), then replay it so the page renders the same data offline or in CI.
|
|
226
|
+
The same file works in a spec with `page.routeFromHAR()`.
|
|
184
227
|
|
|
185
228
|
A failing step reports which one failed and how many ran. When the page lands on a login
|
|
186
229
|
screen, the response says so and suggests `storageState`.
|
|
@@ -256,7 +299,7 @@ numbered next steps (re-run this single test by `file:line`, headed/debug mode,
|
|
|
256
299
|
| Argument | Type | Description |
|
|
257
300
|
| --- | --- | --- |
|
|
258
301
|
| `url` | string | Full http(s) URL to open (required) |
|
|
259
|
-
| `view` | `elements` \| `locators` | `locators` returns a compact map of interactive elements with verified locators (cheapest); `elements` (default) the DOM inventory |
|
|
302
|
+
| `view` | `elements` \| `locators` \| `aria` | `locators` returns a compact map of interactive elements with verified locators (cheapest); `aria` the accessibility snapshot of the page (or of `selector`) with a ready `toMatchAriaSnapshot` assertion; `elements` (default) the DOM inventory |
|
|
260
303
|
| `projectRoot` | string | Project whose Playwright launches the browser |
|
|
261
304
|
| `selector` | string | Inspect matches of this selector instead of the whole DOM |
|
|
262
305
|
| `waitFor` | string | Wait for a selector (CSS or `text=…`) before inspecting |
|
|
@@ -264,7 +307,7 @@ numbered next steps (re-run this single test by `file:line`, headed/debug mode,
|
|
|
264
307
|
| `includeHtml` | boolean | Include the rendered HTML (capped) |
|
|
265
308
|
| `maxHtmlChars` | number | HTML cap, default `20000` |
|
|
266
309
|
| `timeoutMs` | number | Overall limit, default `45000` |
|
|
267
|
-
| `storageState` / `headers` / `actions` / `viewport` | — | [Page state](#page-state-signed-in-pages-headers-and-steps) |
|
|
310
|
+
| `storageState` / `headers` / `actions` / `routes` / `har` / `browser` / `viewport` | — | [Page state](#page-state-signed-in-pages-headers-and-steps) |
|
|
268
311
|
|
|
269
312
|
Each element comes with Playwright locators that were **checked on the page** to resolve to
|
|
270
313
|
exactly that element, best first (role + accessible name, test id, label, placeholder, text,
|
|
@@ -276,6 +319,16 @@ captured, errors first. A locator map looks like:
|
|
|
276
319
|
2. `getByLabel('Search')` — searchbox "Search"
|
|
277
320
|
```
|
|
278
321
|
|
|
322
|
+
`view: "aria"` returns the page's structure as Playwright sees it, and the assertion that
|
|
323
|
+
locks it in a test:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
await expect(page.locator("#cart")).toMatchAriaSnapshot(`
|
|
327
|
+
- list:
|
|
328
|
+
- listitem: Real item
|
|
329
|
+
`);
|
|
330
|
+
```
|
|
331
|
+
|
|
279
332
|
### `list-tests`
|
|
280
333
|
|
|
281
334
|
| Argument | Type | Description |
|
|
@@ -318,9 +371,35 @@ advice, or `❌ INVALID` with the parse error.
|
|
|
318
371
|
| `write` | boolean | Write the file to disk (default `true`) |
|
|
319
372
|
| `overwrite` | boolean | Replace an existing spec at the target path; only specs this tool generated can be replaced |
|
|
320
373
|
| `liveInspect` | boolean | Cross-check selectors against the live page (default on when a URL is known) |
|
|
374
|
+
| `steps` | array | **Walk the flow**: up to 30 steps in the [`actions`](#page-state-signed-in-pages-headers-and-steps) format, run on the live page before anything is written |
|
|
375
|
+
| `assertScope` | string | With `steps`: CSS scope of the end-state accessibility snapshot (default `body`) |
|
|
376
|
+
| `storageState` | string | With `steps`: signed-in session for the walk; the spec uses it too (`test.use`) |
|
|
377
|
+
| `verify` / `project` / `timeoutMs` | — | With `steps`: run the written spec once (default `true`), in this Playwright project |
|
|
321
378
|
| `projectRoot` / `config` | string | As with the other tools |
|
|
322
379
|
|
|
323
|
-
|
|
380
|
+
**With `steps`**, the tool walks the flow on the live page first. If a step's locator does
|
|
381
|
+
not work, it stops there, writes nothing and says which step failed. Otherwise it writes a
|
|
382
|
+
spec that replays the steps, asserts the URL path and the accessibility snapshot where the
|
|
383
|
+
flow landed (headings only when the snapshot is long), and runs it once:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
test('rename in settings', async ({ page }) => {
|
|
387
|
+
await page.goto('http://localhost:3000/account');
|
|
388
|
+
await page.getByRole('button', { name: 'Open settings' }).click();
|
|
389
|
+
await page.getByLabel('Nickname').fill('Ada');
|
|
390
|
+
|
|
391
|
+
// End state
|
|
392
|
+
await expect(page.locator("dialog")).toMatchAriaSnapshot(`
|
|
393
|
+
- dialog:
|
|
394
|
+
- heading "Settings" [level=2]
|
|
395
|
+
- text: Nickname
|
|
396
|
+
- textbox "Nickname": Ada
|
|
397
|
+
- button "Save settings"
|
|
398
|
+
`);
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Without `steps`**, it reads the agent's recent changes (`git status`, falling back to `git diff HEAD~1`,
|
|
324
403
|
then recent mtimes), extracts the locators those files actually declare
|
|
325
404
|
(`data-testid`, `getByRole`, `aria-label`, `placeholder`, `id`, `name`, element text),
|
|
326
405
|
ranks verified-live selectors first, writes a spec built from them, and reports each
|
|
@@ -433,6 +512,47 @@ Example output:
|
|
|
433
512
|
|
|
434
513
|
It ends with an `@axe-core/playwright` check for the spec, so the page stays fixed.
|
|
435
514
|
|
|
515
|
+
### `audit-performance`
|
|
516
|
+
|
|
517
|
+
| Argument | Type | Description |
|
|
518
|
+
| --- | --- | --- |
|
|
519
|
+
| `url` | string | Page to measure (required) |
|
|
520
|
+
| `throttle` | `none` \| `mobile` | `mobile` is Lighthouse's phone preset: 412×823 touch viewport, 4x CPU slowdown, slow 4G. Default `none` (desktop, unthrottled) |
|
|
521
|
+
| `cpuSlowdown` | number | Override the CPU slowdown factor (1–20) |
|
|
522
|
+
| `runs` | number | Load the page 1–5 times and report the median (default `1`); the LCP range is shown |
|
|
523
|
+
| `budgets` | object | `{ lcpMs, cls, inpMs, tbtMs, fcpMs, ttfbMs, transferKb, requests }`, any subset. With budgets the verdict is pass/fail; without, metrics are rated against Google's thresholds |
|
|
524
|
+
| `settleMs` | number | Keep observing after load for late images and shifts (default `1500`) |
|
|
525
|
+
| `waitFor` / `waitUntil` / `timeoutMs` | — | As with `inspect-page` (`waitUntil` default `load`, `timeoutMs` per run, default `60000`) |
|
|
526
|
+
| `storageState` / `headers` / `actions` / `routes` / `viewport` | — | [Page state](#page-state-signed-in-pages-headers-and-steps). Clicks and key presses in `actions` are measured as interactions (INP) |
|
|
527
|
+
|
|
528
|
+
The metrics come from the browser's own performance entries (the same ones Lighthouse and
|
|
529
|
+
the `web-vitals` library read) and the bytes from the DevTools protocol, so cross-origin
|
|
530
|
+
sizes count too. Example output:
|
|
531
|
+
|
|
532
|
+
```
|
|
533
|
+
## ⚡ 3 of 6 metrics need work (CLS, INP, TBT)
|
|
534
|
+
|
|
535
|
+
| Metric | Value | Rating |
|
|
536
|
+
| --- | --- | --- |
|
|
537
|
+
| LCP · largest contentful paint | 412 ms | 🟢 good |
|
|
538
|
+
| CLS · cumulative layout shift | 0.109 | 🟠 needs improvement |
|
|
539
|
+
| INP · slowest interaction (lab) | 360 ms | 🟠 needs improvement |
|
|
540
|
+
| TBT · total blocking time | 306 ms | 🟠 needs improvement |
|
|
541
|
+
|
|
542
|
+
### What to fix
|
|
543
|
+
- **CLS 0.109**: these moved: `getByRole('img', { name: 'Summer sale' })`, `getByRole('button', { name: 'Add to cart' })`. Reserve their space (…)
|
|
544
|
+
- **TBT 306 ms** from 2 long task(s), the longest 404 ms: split or defer JavaScript.
|
|
545
|
+
- **INP 360 ms** on pointerdown on button: the handler blocks the next paint; yield (…)
|
|
546
|
+
|
|
547
|
+
### Network
|
|
548
|
+
**Transfer:** 302 kB in 4 requests · DOM: 13 nodes · JS heap: 10.0 MB
|
|
549
|
+
**Render-blocking:**
|
|
550
|
+
- stylesheet `http://localhost:4173/style.css` · 324 ms
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
It ends with a Playwright test that asserts LCP and CLS stay within budget. These are lab
|
|
554
|
+
numbers from one headless Chromium; field data (CrUX, RUM) can differ.
|
|
555
|
+
|
|
436
556
|
### `suggest-fix`
|
|
437
557
|
|
|
438
558
|
| Argument | Type | Description |
|
|
@@ -441,12 +561,18 @@ It ends with an `@axe-core/playwright` check for the spec, so the page stays fix
|
|
|
441
561
|
| `apply` | boolean | Write the fix into the spec (default `false`: return the diff only) |
|
|
442
562
|
| `verify` | boolean | After applying, re-run the test and revert the file if it still fails (default `true`) |
|
|
443
563
|
| `allowExpectationUpdate` | boolean | Allow applying a changed expected text/value (default `false`, since it can hide a real regression) |
|
|
564
|
+
| `candidate` | number | For a strict mode violation, which of the listed matches the test meant (1-based) |
|
|
444
565
|
| `url` | string | Heal against this live page instead of the DOM snapshot in the failure trace |
|
|
445
566
|
| `storageState` / `headers` | — | For `url`, as in [Page state](#page-state-signed-in-pages-headers-and-steps) |
|
|
446
567
|
| `config` / `timeoutMs` / `projectRoot` | — | As with `run-test` |
|
|
447
568
|
|
|
448
|
-
|
|
569
|
+
Three kinds of fix:
|
|
449
570
|
|
|
571
|
+
- **Ambiguous locator.** A strict mode violation ("resolved to 2 elements") lists each match
|
|
572
|
+
with the unique locator Playwright computed for it. When the broken locator matched by
|
|
573
|
+
substring (`name: 'Save'` hitting *Save* and *Save draft*), the exact-name match is picked
|
|
574
|
+
with `high` confidence. When the matches are equal (the same *Home* link in the header and
|
|
575
|
+
the footer), they are listed and you choose with `candidate`.
|
|
450
576
|
- **Locator drift.** The broken locator is read from the error, its words are matched
|
|
451
577
|
(with synonyms such as *btn → button*, *checkout → proceed to checkout*) against every
|
|
452
578
|
element in the DOM at failure, and the best match's verified-unique locator replaces it.
|
|
@@ -476,17 +602,38 @@ the full `run-test` result, which also becomes the last run for `get-failure` an
|
|
|
476
602
|
|
|
477
603
|
| Argument | Type | Description |
|
|
478
604
|
| --- | --- | --- |
|
|
479
|
-
| `view` | `flaky` \| `patterns` \| `test` | `flaky` (default) ranks unstable tests; `patterns` groups failures by kind and normalized error; `test` shows one test's timeline |
|
|
605
|
+
| `view` | `flaky` \| `patterns` \| `slow` \| `trend` \| `commits` \| `test` | `flaky` (default) ranks unstable tests; `patterns` groups failures by kind and normalized error; `slow` lists tests by median duration and flags ones that got slower; `trend` shows failed and flaky executions per day; `commits` names the first bad commit of each failing or flaky test; `test` shows one test's timeline |
|
|
480
606
|
| `test` | string | Substring of a test's file or title (filters every view) |
|
|
481
607
|
| `lastRuns` | number | How many recent runs to analyze (default `30`) |
|
|
482
608
|
| `limit` | number | Max rows (default `15`) |
|
|
483
609
|
|
|
484
|
-
Every `run-test`, `diagnose-flaky` and `
|
|
610
|
+
Every `run-test`, `diagnose-flaky`, `suggest-fix` and `load-report` run appends a line to
|
|
485
611
|
`<project>/.playwright-e2e-mcp/history.jsonl` (the folder carries its own `.gitignore`;
|
|
486
612
|
nothing leaves the machine; `PW_MCP_HISTORY=0` turns it off). The flaky view separates
|
|
487
613
|
tests that flip between pass and fail, tests that started failing and stayed red
|
|
488
614
|
(regressed), and tests that failed every run (broken), each with a `PFFP~` timeline.
|
|
489
615
|
|
|
616
|
+
Each run records the commit it tested (from git locally, from the report's metadata for CI
|
|
617
|
+
runs). The `commits` view uses that to say where a test went bad: the first failing or flaky
|
|
618
|
+
run after its last streak of passes, with the last good commit and a `git diff` to compare
|
|
619
|
+
them.
|
|
620
|
+
|
|
621
|
+
### `load-report`
|
|
622
|
+
|
|
623
|
+
| Argument | Type | Description |
|
|
624
|
+
| --- | --- | --- |
|
|
625
|
+
| `report` | string | A Playwright JSON report inside the project (e.g. `ci-artifacts/results.json`), or a folder of blob-report zips from sharded jobs (merged with the project's `playwright merge-reports`) (required) |
|
|
626
|
+
| `traceDirs` | string[] | Folders inside the project where the job's `test-results` artifact was unpacked (default: the report's folder and its parent) |
|
|
627
|
+
| `commit` / `branch` | string | Override what the report's metadata says (Playwright records it with `captureGitInfo` or on CI) |
|
|
628
|
+
| `record` | boolean | Add the run to the history (default `true`) |
|
|
629
|
+
| `timeoutMs` | number | Limit for merging blob reports (default `120000`) |
|
|
630
|
+
|
|
631
|
+
Download the artifacts first, for example with
|
|
632
|
+
`gh run download <run-id> -n playwright-report -D ci-artifacts`. The CI machine's absolute
|
|
633
|
+
paths are mapped onto your checkout, so failures point at local files and get-failure can
|
|
634
|
+
open each trace. The run becomes the last run, so the usual loop works on it: `get-failure`,
|
|
635
|
+
then `suggest-fix` (which re-runs the fix locally), or `diagnose-flaky`.
|
|
636
|
+
|
|
490
637
|
---
|
|
491
638
|
|
|
492
639
|
## Installation
|
|
@@ -502,8 +649,8 @@ builds `dist/` automatically on install). Pin a release tag: an unpinned
|
|
|
502
649
|
`github:xsignon-secure/E2E` runs whatever is on the default branch at that moment.
|
|
503
650
|
|
|
504
651
|
```bash
|
|
505
|
-
npx -y github:xsignon-secure/E2E#v0.
|
|
506
|
-
npm install -D github:xsignon-secure/E2E#v0.
|
|
652
|
+
npx -y github:xsignon-secure/E2E#v0.5.0
|
|
653
|
+
npm install -D github:xsignon-secure/E2E#v0.5.0 @playwright/test # or as a project dependency
|
|
507
654
|
npx playwright install chromium
|
|
508
655
|
```
|
|
509
656
|
|
|
@@ -511,7 +658,7 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
|
|
|
511
658
|
it locally:
|
|
512
659
|
|
|
513
660
|
```bash
|
|
514
|
-
npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.
|
|
661
|
+
npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.5.0/playwright-e2e-mcp-0.5.0.tgz
|
|
515
662
|
```
|
|
516
663
|
|
|
517
664
|
Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
|
|
@@ -527,22 +674,24 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
|
|
|
527
674
|
"mcpServers": {
|
|
528
675
|
"playwright-e2e": {
|
|
529
676
|
"command": "npx",
|
|
530
|
-
"args": ["-y", "github:xsignon-secure/E2E#v0.
|
|
677
|
+
"args": ["-y", "github:xsignon-secure/E2E#v0.5.0"],
|
|
531
678
|
"env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
|
|
532
679
|
}
|
|
533
680
|
}
|
|
534
681
|
}
|
|
535
682
|
```
|
|
536
683
|
|
|
537
|
-
**Claude Desktop / Cursor / Windsurf:** add the same block to their MCP config file
|
|
684
|
+
**Claude Desktop / Cursor / Windsurf / Cline:** add the same block to their MCP config file
|
|
685
|
+
(Cline: *MCP Servers → Configure*). **Zed** and other clients that take a command: run `npx`
|
|
686
|
+
with the arguments `-y playwright-e2e-mcp`.
|
|
538
687
|
The server uses its working directory as the project root; set `PW_MCP_PROJECT_ROOT`
|
|
539
688
|
when the client launches it somewhere else (e.g. your home directory).
|
|
540
689
|
|
|
541
690
|
**Codex / VS Code / Copilot CLIs:**
|
|
542
691
|
|
|
543
692
|
```bash
|
|
544
|
-
codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.
|
|
545
|
-
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.
|
|
693
|
+
codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.5.0
|
|
694
|
+
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.5.0"]}'
|
|
546
695
|
```
|
|
547
696
|
|
|
548
697
|
Codex's defaults fight this server: the first launch clones the repo and runs
|
|
@@ -553,7 +702,7 @@ Codex's defaults fight this server: the first launch clones the repo and runs
|
|
|
553
702
|
```toml
|
|
554
703
|
[mcp_servers.playwright-e2e]
|
|
555
704
|
command = "npx"
|
|
556
|
-
args = ["-y", "github:xsignon-secure/E2E#v0.
|
|
705
|
+
args = ["-y", "github:xsignon-secure/E2E#v0.5.0"]
|
|
557
706
|
startup_timeout_sec = 60
|
|
558
707
|
tool_timeout_sec = 600
|
|
559
708
|
```
|
|
@@ -568,7 +717,7 @@ into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first
|
|
|
568
717
|
**Claude Code:**
|
|
569
718
|
|
|
570
719
|
```bash
|
|
571
|
-
claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.
|
|
720
|
+
claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.5.0
|
|
572
721
|
```
|
|
573
722
|
|
|
574
723
|
**Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
|
|
@@ -609,7 +758,7 @@ Streamable HTTP bridge for exactly that case:
|
|
|
609
758
|
| --- | --- |
|
|
610
759
|
| **Endpoint** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
|
|
611
760
|
| **Transport** | MCP Streamable HTTP (`POST` JSON in, JSON or SSE out) |
|
|
612
|
-
| **Auth** | bearer token (`PW_MCP_HTTP_TOKEN`). The deployment at this URL requires
|
|
761
|
+
| **Auth** | bearer token (`PW_MCP_HTTP_TOKEN`), or OAuth sign-in with that token as the access key (for claude.ai connectors). The deployment at this URL requires one of them; a bridge started without the variable serves only the read-only tools |
|
|
613
762
|
| **Source** | [`api/mcp.ts`](api/mcp.ts) → [`src/http.ts`](src/http.ts) |
|
|
614
763
|
|
|
615
764
|
The bridge runs the *same* `createServer()` as the stdio transport; the SDK
|
|
@@ -617,11 +766,16 @@ serves every request with a fresh server instance, which is what a serverless
|
|
|
617
766
|
function wants. `test/http-bridge.test.mjs` drives the real Node adapter over
|
|
618
767
|
`node:http` so a broken bridge fails in CI, not in ChatGPT.
|
|
619
768
|
|
|
620
|
-
**This deployment is token-protected.** `https://playwright-e2e-mcp.vercel.app`
|
|
621
|
-
has `PW_MCP_HTTP_TOKEN` set, so a request
|
|
622
|
-
|
|
623
|
-
`401 {"error":"unauthorized"}`.
|
|
624
|
-
|
|
769
|
+
**This demo deployment is token-protected.** `https://playwright-e2e-mcp.vercel.app`
|
|
770
|
+
runs on the maintainer's account and has `PW_MCP_HTTP_TOKEN` set, so a request
|
|
771
|
+
without `Authorization: Bearer <token>` (or an OAuth sign-in with it) gets
|
|
772
|
+
`401 {"error":"unauthorized"}`. Nothing is held back: the same bridge is free to
|
|
773
|
+
host yourself on a free Vercel account, with your own token:
|
|
774
|
+
|
|
775
|
+
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fxsignon-secure%2FE2E&env=PW_MCP_HTTP_TOKEN&envDescription=A%20random%20secret%20of%2016%2B%20characters%3B%20clients%20send%20it%20as%20a%20bearer%20token%20or%20type%20it%20to%20sign%20in&project-name=playwright-e2e-mcp)
|
|
776
|
+
|
|
777
|
+
A serverless function has no browser, so for running and fixing your own tests
|
|
778
|
+
the free local install (`npx -y playwright-e2e-mcp init`) is the better route.
|
|
625
779
|
|
|
626
780
|
**Open vs. token-protected.** With `PW_MCP_HTTP_TOKEN` set (at least 16
|
|
627
781
|
characters; use a random value) every tool is served to clients that send
|
|
@@ -643,6 +797,20 @@ deployment choose the connector's **API key** authentication and send
|
|
|
643
797
|
`Authorization: Bearer <token>` — or point the connector at your own deployment
|
|
644
798
|
with `PW_MCP_HTTP_TOKEN` unset.
|
|
645
799
|
|
|
800
|
+
**Add it to claude.ai (or Claude Desktop's connectors):** Settings → Connectors →
|
|
801
|
+
*Add custom connector* → paste the endpoint above and leave the OAuth fields
|
|
802
|
+
empty. Claude registers itself and opens a sign-in page; type the deployment's
|
|
803
|
+
access key (the value of `PW_MCP_HTTP_TOKEN`) and press **Allow access**. The
|
|
804
|
+
bridge is its own small OAuth 2.1 server (discovery, dynamic client
|
|
805
|
+
registration, authorization code with PKCE S256, refresh tokens) and keeps no
|
|
806
|
+
state: client ids, codes and tokens are signed with a key derived from
|
|
807
|
+
`PW_MCP_HTTP_TOKEN`, access tokens last an hour and refresh tokens 30 days, and
|
|
808
|
+
changing `PW_MCP_HTTP_TOKEN` signs every connected client out. The sign-in page
|
|
809
|
+
shows which site will receive access, so only type the key when that is the
|
|
810
|
+
app you are connecting. Source: [`src/oauth.ts`](src/oauth.ts); the
|
|
811
|
+
`/.well-known/oauth-*` and `/oauth/*` paths reach the function through the
|
|
812
|
+
rewrites in [`vercel.json`](vercel.json).
|
|
813
|
+
|
|
646
814
|
To self-host the open, read-only variant, deploy this repo with
|
|
647
815
|
`PW_MCP_HTTP_TOKEN` unset; nothing else changes.
|
|
648
816
|
|
|
@@ -659,9 +827,10 @@ codex mcp add playwright-e2e-remote --url https://playwright-e2e-mcp.vercel.app/
|
|
|
659
827
|
**What to expect:** `list-tests` works and reports the specs bundled with the
|
|
660
828
|
deployment. Even with a token, tools that spawn a browser (`run-test`,
|
|
661
829
|
`inspect-page`, `validate-selector`, `diagnose-flaky`, …) cannot download
|
|
662
|
-
Chromium in a serverless function, so they return
|
|
663
|
-
|
|
664
|
-
and for clients that cannot run local
|
|
830
|
+
Chromium in a serverless function, so they return `NO_PLAYWRIGHT` with a note
|
|
831
|
+
that points to the local install. Use the stdio install for real runs; the
|
|
832
|
+
hosted endpoint is for discovery and for clients that cannot run local
|
|
833
|
+
processes.
|
|
665
834
|
|
|
666
835
|
```bash
|
|
667
836
|
# verify the handshake without any client (the live deployment needs the token;
|
|
@@ -703,7 +872,7 @@ steps:
|
|
|
703
872
|
- uses: actions/setup-node@v6
|
|
704
873
|
with: { node-version: 24 }
|
|
705
874
|
- run: npm ci && npx playwright install --with-deps chromium
|
|
706
|
-
- uses: xsignon-secure/E2E@v0.
|
|
875
|
+
- uses: xsignon-secure/E2E@v0.5.0
|
|
707
876
|
with:
|
|
708
877
|
flaky-runs: 3 # 0 skips the flaky verdict
|
|
709
878
|
suggest: 2 # suggest-fix diffs for the first 2 failures
|
|
@@ -730,7 +899,7 @@ browsers match Playwright 1.63. Mount your project at `/work`; its own
|
|
|
730
899
|
| Environment variable | Default | Purpose |
|
|
731
900
|
| --- | --- | --- |
|
|
732
901
|
| `PW_MCP_PROJECT_ROOT` | server cwd | Default project root for every tool |
|
|
733
|
-
| `PW_MCP_TOOLS` | all | Which tools to expose, as tool names and/or profiles, comma separated (same as the `--tools=` flag). Profiles: `core` (run, status, failure, fix, flaky, list), `triage` (run, status, failure, flaky, history, list), `inspect` (page, selector, accessibility, visual), `author` (list, page, selector, generate, run). All
|
|
902
|
+
| `PW_MCP_TOOLS` | all | Which tools to expose, as tool names and/or profiles, comma separated (same as the `--tools=` flag). Profiles: `core` (run, status, failure, fix, flaky, list), `triage` (run, status, failure, CI report, flaky, history, list), `inspect` (page, selector, accessibility, performance, visual), `author` (list, page, selector, generate, run). All fourteen tool definitions cost about 9k tokens of context per request; `core` costs about 2.3k |
|
|
734
903
|
| `PW_MCP_STORAGE_STATE` | — | Default `storageState` file (inside the project) for the page tools |
|
|
735
904
|
| `PW_MCP_SHUFFLE_SEEDS` | random | Comma-separated seeds for `diagnose-flaky`'s `order` pass, to replay the orders a diagnosis reported |
|
|
736
905
|
| `PW_MCP_HISTORY` | on | `0` stops recording runs to `.playwright-e2e-mcp/history.jsonl` |
|
|
@@ -848,7 +1017,7 @@ picks the right locator from the snapshot on the first try, which the server doe
|
|
|
848
1017
|
src/
|
|
849
1018
|
├── index.ts # bin entry point (--version/--help, main-module guard)
|
|
850
1019
|
├── server.ts # McpServer setup, tool registration, shutdown handling
|
|
851
|
-
├── tools/ # the
|
|
1020
|
+
├── tools/ # the fourteen tools, the probe script + shared plumbing
|
|
852
1021
|
├── prompts.ts # fix-failing-test, triage-flaky-tests
|
|
853
1022
|
├── utils/ # playwright-runner, report-parser, project-detector, path-utils,
|
|
854
1023
|
│ # logger, trace-reader (trace.zip → DOM/network/console),
|
|
@@ -897,10 +1066,13 @@ server over stdio against a live fixture app and a Playwright project under
|
|
|
897
1066
|
`e2e/fixture/`, then drives it exactly like an MCP client and asserts ~40 behaviours
|
|
898
1067
|
that only appear end-to-end:
|
|
899
1068
|
|
|
900
|
-
- initialize handshake,
|
|
1069
|
+
- initialize handshake, 14 tools, 2 prompts, spec tool annotations and object input schemas,
|
|
901
1070
|
- verified locators, locator validation, signed-in pages (`storageState`) and page steps,
|
|
902
1071
|
- background runs with progress, run history views, and `suggest-fix` healing a drifted
|
|
903
|
-
locator and verifying
|
|
1072
|
+
locator and an ambiguous one, verifying each with a re-run (and refusing when the
|
|
1073
|
+
element is missing),
|
|
1074
|
+
- Web Vitals with budgets and phone throttling, and network mocks that force error and
|
|
1075
|
+
empty states,
|
|
904
1076
|
- live DOM inspection, CSS selector validation (matches, zero matches, engine
|
|
905
1077
|
syntax, parse errors), dead-server detection,
|
|
906
1078
|
- visual regression: baseline → unchanged compare → `blue → red` diff detection,
|
|
@@ -1001,8 +1173,8 @@ job requests for itself; if it is refused, the run names the setting to change.
|
|
|
1001
1173
|
### Verifying a published release
|
|
1002
1174
|
|
|
1003
1175
|
```bash
|
|
1004
|
-
git checkout v0.
|
|
1005
|
-
npm run release:verify -- v0.
|
|
1176
|
+
git checkout v0.5.0 && npm ci && npm run mcpb
|
|
1177
|
+
npm run release:verify -- v0.5.0
|
|
1006
1178
|
```
|
|
1007
1179
|
|
|
1008
1180
|
The release notes promise that the tag rebuilds the published bundle byte for
|
package/dist/cli/init.js
CHANGED
|
@@ -42,7 +42,7 @@ export function parseInitArgs(argv, cwd = process.cwd()) {
|
|
|
42
42
|
args: argv,
|
|
43
43
|
strict: true,
|
|
44
44
|
options: {
|
|
45
|
-
client: { type: 'string' },
|
|
45
|
+
client: { type: 'string', multiple: true },
|
|
46
46
|
'project-root': { type: 'string' },
|
|
47
47
|
tools: { type: 'string' },
|
|
48
48
|
'no-skill': { type: 'boolean' },
|
|
@@ -51,7 +51,8 @@ export function parseInitArgs(argv, cwd = process.cwd()) {
|
|
|
51
51
|
});
|
|
52
52
|
let clients;
|
|
53
53
|
if (values.client !== undefined) {
|
|
54
|
-
|
|
54
|
+
// `--client gemini --client codex` and `--client gemini,codex` mean the same.
|
|
55
|
+
const names = values.client.join(',').split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
55
56
|
if (names.includes('all'))
|
|
56
57
|
clients = [...CLIENTS];
|
|
57
58
|
else {
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrF,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAC5C,MAAM,CAAC,MAAM,UAAU,GAAG,oBAAoB,CAAC;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC;AAG9F,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,0CAA0C;IAC1C,EAAE;IACF,gFAAgF;IAChF,+DAA+D;IAC/D,EAAE;IACF,kFAAkF;IAClF,qFAAqF;IACrF,4EAA4E;IAC5E,2DAA2D;IAC3D,mFAAmF;IACnF,yDAAyD;IACzD,kEAAkE;IAClE,EAAE;IACF,qEAAqE;IACrE,oFAAoF;IACpF,8EAA8E;IAC9E,uEAAuE;IACvE,0CAA0C;IAC1C,EAAE;CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAUb,MAAM,UAAU,aAAa,CAAC,IAAc,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE;YACP,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* verified locally before it is deployed.
|
|
11
11
|
*
|
|
12
12
|
* The stdio transport in server.ts is untouched; this is an additional way to
|
|
13
|
-
* reach the same
|
|
13
|
+
* reach the same fourteen tools.
|
|
14
14
|
*/
|
|
15
15
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
16
16
|
import type { McpHttpHandler } from '@modelcontextprotocol/server';
|
|
@@ -31,6 +31,11 @@ export interface McpHttpHandlerOptions {
|
|
|
31
31
|
* deployment's own Vercel hostnames are accepted.
|
|
32
32
|
*/
|
|
33
33
|
allowedHosts?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* Path the MCP endpoint is served on, advertised as the OAuth protected
|
|
36
|
+
* resource. Defaults to `/api/mcp`, where the Vercel function lives.
|
|
37
|
+
*/
|
|
38
|
+
mcpPath?: string;
|
|
34
39
|
}
|
|
35
40
|
/** Tokens shorter than this are refused: they can be guessed. */
|
|
36
41
|
export declare const MIN_TOKEN_LENGTH = 16;
|
package/dist/http.js
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* verified locally before it is deployed.
|
|
11
11
|
*
|
|
12
12
|
* The stdio transport in server.ts is untouched; this is an additional way to
|
|
13
|
-
* reach the same
|
|
13
|
+
* reach the same fourteen tools.
|
|
14
14
|
*/
|
|
15
15
|
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
16
16
|
import { createMcpHandler, hostHeaderValidationResponse } from '@modelcontextprotocol/server';
|
|
17
|
+
import { createOAuthServer } from './oauth.js';
|
|
17
18
|
import { createServer, READ_ONLY_TOOLS } from './server.js';
|
|
18
19
|
import { setMaxChildren, setScrubChildEnv } from './utils/playwright-runner.js';
|
|
19
20
|
import { setBlockPrivateUrls } from './utils/url-policy.js';
|
|
@@ -74,6 +75,9 @@ export function createMcpHttpHandler(options = {}) {
|
|
|
74
75
|
if (!token) {
|
|
75
76
|
logger.warn('PW_MCP_HTTP_TOKEN is not set; serving read-only tools only', { tools: READ_ONLY_TOOLS });
|
|
76
77
|
}
|
|
78
|
+
// With a token, OAuth clients (claude.ai connectors) sign in by typing it
|
|
79
|
+
// on the authorize page; without one the endpoint is open and needs none.
|
|
80
|
+
const oauth = token ? createOAuthServer({ token, mcpPath: options.mcpPath ?? '/api/mcp' }) : undefined;
|
|
77
81
|
const inner = createMcpHandler((context) => createServer({
|
|
78
82
|
...(token ? {} : { tools: READ_ONLY_TOOLS, restricted: true }),
|
|
79
83
|
// Lets tools stop their children when the HTTP client disconnects.
|
|
@@ -90,8 +94,14 @@ export function createMcpHttpHandler(options = {}) {
|
|
|
90
94
|
if (rejected)
|
|
91
95
|
return rejected;
|
|
92
96
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
97
|
+
if (oauth) {
|
|
98
|
+
const oauthResponse = await oauth.handle(request);
|
|
99
|
+
if (oauthResponse)
|
|
100
|
+
return oauthResponse;
|
|
101
|
+
const authorization = request.headers.get('authorization');
|
|
102
|
+
if (!tokenMatches(authorization, token) && !oauth.verifyAccessToken(authorization)) {
|
|
103
|
+
return jsonResponse(401, { error: 'unauthorized' }, { 'www-authenticate': oauth.challenge(request) });
|
|
104
|
+
}
|
|
95
105
|
}
|
|
96
106
|
return inner.fetch(request, requestOptions);
|
|
97
107
|
},
|