mcp-accessibility-scanner 3.3.2 → 3.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 +146 -11
- package/config.d.ts +48 -3
- package/lib/browserContextFactory.js +15 -313
- package/lib/browserContextFactory.js.map +1 -1
- package/lib/browserServerBackend.js +11 -0
- package/lib/browserServerBackend.js.map +1 -1
- package/lib/browserSessions.js +3 -0
- package/lib/browserSessions.js.map +1 -1
- package/lib/config.js +70 -12
- package/lib/config.js.map +1 -1
- package/lib/context.js +463 -57
- package/lib/context.js.map +1 -1
- package/lib/extension/cdpRelay.js +82 -14
- package/lib/extension/cdpRelay.js.map +1 -1
- package/lib/extension/extensionContextFactory.js +15 -8
- package/lib/extension/extensionContextFactory.js.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/mcp/http.js +115 -41
- package/lib/mcp/http.js.map +1 -1
- package/lib/mcp/server.js +16 -8
- package/lib/mcp/server.js.map +1 -1
- package/lib/mcp/tool.js +11 -9
- package/lib/mcp/tool.js.map +1 -1
- package/lib/program.js +28 -8
- package/lib/program.js.map +1 -1
- package/lib/response.js +22 -5
- package/lib/response.js.map +1 -1
- package/lib/sessionLog.js +66 -20
- package/lib/sessionLog.js.map +1 -1
- package/lib/tab.js +13 -7
- package/lib/tab.js.map +1 -1
- package/lib/tools/auditKeyboard.js +27 -25
- package/lib/tools/auditKeyboard.js.map +1 -1
- package/lib/tools/auditScreenReader.js +27 -18
- package/lib/tools/auditScreenReader.js.map +1 -1
- package/lib/tools/auditSite.js +88 -56
- package/lib/tools/auditSite.js.map +1 -1
- package/lib/tools/axe.js +32 -7
- package/lib/tools/axe.js.map +1 -1
- package/lib/tools/common.js +39 -1
- package/lib/tools/common.js.map +1 -1
- package/lib/tools/files.js +60 -3
- package/lib/tools/files.js.map +1 -1
- package/lib/tools/install.js +1 -1
- package/lib/tools/install.js.map +1 -1
- package/lib/tools/pdf.js +4 -2
- package/lib/tools/pdf.js.map +1 -1
- package/lib/tools/recorder.js +52 -0
- package/lib/tools/recorder.js.map +1 -0
- package/lib/tools/report.js +13 -0
- package/lib/tools/report.js.map +1 -0
- package/lib/tools/scanPageMatrix.js +20 -33
- package/lib/tools/scanPageMatrix.js.map +1 -1
- package/lib/tools/screenshot.js +7 -3
- package/lib/tools/screenshot.js.map +1 -1
- package/lib/tools/snapshot.js +10 -3
- package/lib/tools/snapshot.js.map +1 -1
- package/lib/tools.js +5 -1
- package/lib/tools.js.map +1 -1
- package/lib/vscode/browserContextFactory.js +16 -12
- package/lib/vscode/browserContextFactory.js.map +1 -1
- package/lib/vscode/host.js +25 -2
- package/lib/vscode/host.js.map +1 -1
- package/lib/vscode/main.js +15 -0
- package/lib/vscode/main.js.map +1 -1
- package/lib/vscode/validation.js +78 -0
- package/lib/vscode/validation.js.map +1 -0
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -137,8 +137,12 @@ Use `--extension` to connect through the current [Playwright Extension](https://
|
|
|
137
137
|
npx mcp-accessibility-scanner --extension
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
Set `PLAYWRIGHT_MCP_EXTENSION_TOKEN` to the token shown by the extension to bypass the connection approval dialog.
|
|
141
|
-
|
|
140
|
+
Set `PLAYWRIGHT_MCP_EXTENSION_TOKEN` to the token shown by the extension to bypass the connection approval dialog. The relay's CDP WebSocket endpoint always requires a separate random token, generated per relay and appended automatically for the server's own connection. This CDP token is never passed in Chrome's launch arguments or extension URL; the extension approval token cannot authenticate a CDP client.
|
|
141
|
+
Token-bypass connections are not background-safe: Chrome focuses the connection tab and window, and client-created tabs remain open after disconnect ([upstream limitation](https://github.com/microsoft/playwright/issues/42343)).
|
|
142
|
+
With a token, the extension must connect and finish setup within 30 seconds after the connection page opens. Failed attempts release the relay so the next tool call can retry. Without a token, manual approval waits until you approve or cancel the call.
|
|
143
|
+
When `--user-data-dir` contains multiple Chrome profiles, the profile with the extension installed is selected automatically, preferring Chrome's last-used profile. Pass `--profile-dir-name` (or set `PLAYWRIGHT_MCP_PROFILE_DIR_NAME`) to select a profile explicitly; it requires `--user-data-dir` and accepts a Chrome profile directory name such as `Default` or `Profile 1` (see "Profile Path" at `chrome://version`). The `PLAYWRIGHT_MCP_EXTENSION_TOKEN` approval token is specific to the profile, so when selecting a profile explicitly, use the token shown in that profile.
|
|
144
|
+
|
|
145
|
+
Packed extensions require an enabled record in the profile's preferences; a leftover extension directory alone does not count as installed. Profiles whose preferences mark the extension disabled or uninstalled are excluded from automatic selection and rejected for explicit selection. Explicit selection with a custom executable skips local installation checks. A whitespace-only `PLAYWRIGHT_MCP_PROFILE_DIR_NAME` is treated as unset; other string environment variables retain their existing blank-value handling.
|
|
142
146
|
|
|
143
147
|
### Discovering available tools (`list-tools` subcommand)
|
|
144
148
|
|
|
@@ -201,11 +205,15 @@ Create a `config.json` file with the following options:
|
|
|
201
205
|
"timeouts": {
|
|
202
206
|
"navigationTimeout": 60000,
|
|
203
207
|
"defaultTimeout": 5000,
|
|
204
|
-
"settle": 500
|
|
208
|
+
"settle": 500,
|
|
209
|
+
"idle": 0
|
|
205
210
|
},
|
|
206
211
|
"network": {
|
|
207
212
|
"allowedOrigins": ["example.com", "trusted-site.com"],
|
|
208
213
|
"blockedOrigins": ["ads.example.com"]
|
|
214
|
+
},
|
|
215
|
+
"snapshot": {
|
|
216
|
+
"boxes": true
|
|
209
217
|
}
|
|
210
218
|
}
|
|
211
219
|
```
|
|
@@ -213,28 +221,54 @@ Create a `config.json` file with the following options:
|
|
|
213
221
|
**Available Options:**
|
|
214
222
|
|
|
215
223
|
- `browser.browserName`: Browser to use (`chromium`, `firefox`, `webkit`)
|
|
224
|
+
- `browser.allowedUploadDirs`: Restrict files sent by `browser_file_upload` and `browser_drop` to regular files inside these directories, including resolved symlink targets. Restricted uploads and drops use a checked file handle and accept up to 50 MiB total per call. Unset allows any path; `[]` denies all file uploads and drops (text-only drops still work). Blank list entries are rejected. CLI: `--allowed-upload-dirs` (semicolon-separated; `""` denies all), env: `PLAYWRIGHT_MCP_ALLOWED_UPLOAD_DIRS` (empty string denies all).
|
|
225
|
+
|
|
226
|
+
The list must be an array, not `null`. Roots must exist at startup: their canonical paths are resolved once and retained for the server's lifetime, so retargeting a configured symlink does not grant access to a new tree. Non-empty upload allowlists require macOS or Linux with `/proc/self/fd` available. macOS blocks ancestor symlinks during the file open; Linux checks the opened descriptor's path. Other platforms reject restricted file uploads and drops rather than rely on race-prone pathname checks. Unrestricted uploads, deny-all lists, and text-only drops keep working on all platforms.
|
|
216
227
|
- `browser.launchOptions.headless`: Run browser in headless mode (default: `true` on Linux without display, `false` otherwise)
|
|
217
228
|
- `browser.launchOptions.channel`: Browser channel (`chrome`, `chrome-beta`, `msedge`, etc.)
|
|
229
|
+
- `browser.launchOptions.chromiumSandbox`: Defaults to `false` for downloaded Chromium builds on Linux because they lack the setuid sandbox helper, and `true` otherwise. Remote and VS Code endpoints choose on the remote host. An explicit config or `PLAYWRIGHT_MCP_SANDBOX` value wins; `--no-sandbox` always disables it.
|
|
218
230
|
- `browser.cdpEndpoint`: Attach to an already-running Chromium-family app with CDP enabled
|
|
219
231
|
- `browser.cdpHeaders`: Map of HTTP headers to send with the CDP connect request, e.g. `{ "Authorization": "Bearer <token>" }`, for endpoints that require header-based authentication
|
|
220
232
|
- `browser.cdpTimeout`: Maximum time in milliseconds to wait when connecting to the CDP endpoint (default: `30000`)
|
|
221
233
|
- `browser.cdpLaunch`: Launch a Chromium-family desktop app with CDP enabled, wait for the endpoint, and manage the child process lifecycle
|
|
222
234
|
- CDP attach modes preserve the target browser's existing default-context settings instead of applying Playwright's defaults.
|
|
223
|
-
- `browser.contextOptions.storageState`: Start
|
|
235
|
+
- `browser.contextOptions.storageState`: Start a fresh context from a recorded Playwright storage state. Imports into existing CDP or VS Code contexts are rejected; use `--isolated` for CDP or sign in interactively. The default persistent mode uses a fresh disposable profile. See [Auditing pages behind a login](#auditing-pages-behind-a-login).
|
|
236
|
+
- `browser.profileDirName`: Chrome profile directory name used in extension mode, for example `Default` or `Profile 1` (CLI: `--profile-dir-name`, env: `PLAYWRIGHT_MCP_PROFILE_DIR_NAME`). Requires `--user-data-dir` and extension mode (`--extension` or `--connect-tool`); defaults to the last-used profile that has the extension installed.
|
|
224
237
|
- `timeouts.navigationTimeout`: Maximum time for page navigation in milliseconds (default: `60000`)
|
|
225
238
|
- `timeouts.defaultTimeout`: Default timeout for Playwright operations in milliseconds (default: `5000`)
|
|
226
239
|
- `timeouts.settle`: How long to wait after every action before responding (default: `500`). An action that finishes quietly is first watched for up to 100ms (or the settle delay, whichever is shorter) so scheduled network work can still be awaited before the settle delay.
|
|
240
|
+
- `timeouts.idle`: Release the default browser context after this many idle milliseconds (default: `0`, disabled). Accepts integers from `0` to `2147483647`.
|
|
227
241
|
- `network.allowedOrigins`: List of origins to allow (blocks all others if specified)
|
|
228
242
|
- `network.blockedOrigins`: List of origins to block
|
|
243
|
+
- `snapshot.boxes`: Include each element's viewport-relative bounding box as `[box=x,y,width,height]` in snapshots (default: `false`; CLI: `--snapshot-boxes`, env: `PLAYWRIGHT_MCP_SNAPSHOT_BOXES=1`)
|
|
244
|
+
- `imageResponses`: `allow` (default) returns text and images; `omit` excludes images; `only` omits text from successful responses containing images. Errors, browser lifecycle notices, and responses without images (including full-page screenshots) keep their text. Structured results and resource links are always preserved. In `only` mode, screenshot save-path text, generated code and any accompanying text-only findings are omitted; use `allow` if you need them. Interactive mode rejects `only` because its REPL prints text only; use `allow` or `omit` there. `auto` remains a legacy alias for `allow`. CLI: `--image-responses only`; env: `PLAYWRIGHT_MCP_IMAGE_RESPONSES=only`. Precedence: CLI, then environment, then config file.
|
|
245
|
+
- `server.authToken`: When set, Streamable HTTP requests (`--port`) require `Authorization: Bearer <token>` or return `401` (env: `PLAYWRIGHT_MCP_AUTH_TOKEN`). Blank or malformed tokens fail at startup. The scheme is case-insensitive; the token is exact. Bearer auth does not encrypt traffic: authenticated listeners must bind to loopback, such as `--host 127.0.0.1`; use a TLS reverse proxy for remote access. The printed client config includes a header placeholder to replace locally, without logging the secret. Unset keeps unauthenticated access.
|
|
229
246
|
- `outputDir`: Directory for output files — reports, screenshots, traces, and session logs (CLI: `--output-dir`, env: `PLAYWRIGHT_MCP_OUTPUT_DIR`). Defaults to a fresh directory under the system temp folder, resolved once per server run so all of a run's artifacts land together. The output location is always server configuration; the deprecated MCP roots capability (client workspace folders) is no longer consulted.
|
|
230
247
|
|
|
231
248
|
CLI equivalents are also available: `--cdp-launch-command`, `--cdp-launch-args`, `--cdp-launch-cwd`, `--cdp-launch-port`, `--cdp-launch-startup-timeout`, `--cdp-endpoint`, `--cdp-header` (repeat for multiple headers, e.g. `--cdp-header "Authorization: Bearer <token>"`), and `--cdp-timeout`. The CDP headers and timeout can also be set via the `PLAYWRIGHT_MCP_CDP_HEADERS` (one `Name: Value` entry per line) and `PLAYWRIGHT_MCP_CDP_TIMEOUT` environment variables.
|
|
232
249
|
|
|
250
|
+
If CDP attachment times out after the WebSocket connects, an existing sleeping or unresponsive tab may be blocking Playwright's browser initialization ([upstream report](https://github.com/microsoft/playwright/issues/42730)). Use an explicit positive `--cdp-timeout` to bound the attempt. Inspect or wake the affected tabs yourself, or attach to a separate disposable browser. `noDefaults` and `--isolated` do not skip initialization of existing tabs; the server does not close your tabs or bypass Playwright's initialization to work around this.
|
|
251
|
+
|
|
252
|
+
For remote HTTP access, configure the TLS reverse proxy explicitly. For example, with the MCP server bound using `--host 127.0.0.1 --port 8931` and `PLAYWRIGHT_MCP_AUTH_TOKEN` set:
|
|
253
|
+
|
|
254
|
+
- Accept only your configured public hostname over HTTPS and forward `/mcp` to `http://127.0.0.1:8931/mcp`.
|
|
255
|
+
- Set the upstream `Host` header to `127.0.0.1:8931`, not the public hostname. Forward the client's `Authorization` header unchanged; do not inject a shared token for unauthenticated clients.
|
|
256
|
+
- Before removing `Origin`, reject any non-empty value outside your explicit trusted HTTPS origin list (for example, `https://mcp.example.com`). Allow absent `Origin` for non-browser clients. Then remove `Origin` upstream, or rewrite it to `http://127.0.0.1:8931`. Never strip arbitrary origins without checking them first.
|
|
257
|
+
- Disable response buffering for SSE streams. Browser clients on a different origin also need a narrowly scoped CORS policy at the proxy.
|
|
258
|
+
|
|
259
|
+
The server does not trust `Forwarded` or `X-Forwarded-*` to bypass its checks. Preserving the public `Host` or HTTPS `Origin` upstream returns `403`, even with a valid bearer token.
|
|
260
|
+
|
|
261
|
+
Caller-supplied screenshot, PDF, scan-page-matrix, and audit report filenames use a no-clobber policy: an existing file causes the tool call to fail instead of being overwritten. Windows-reserved basenames and names ending in a dot or space are rejected on every platform so configured names behave consistently across hosts.
|
|
262
|
+
|
|
233
263
|
Use `--timeout-settle` or `PLAYWRIGHT_MCP_TIMEOUT_SETTLE` to override the post-action settle delay. It applies after every action so delayed DOM-only updates are included in the response; a short observation window also catches scheduled requests and waits for them before that delay.
|
|
234
264
|
|
|
265
|
+
Use `--timeout-idle 300000`, `timeouts.idle`, or `PLAYWRIGHT_MCP_TIMEOUT_IDLE` to release the default browser after five idle minutes. Shared contexts stay open while any client is working; the idle window starts after the last tool call or download finishes. Explicit recordings prevent idle release until `browser_stop_recording` finishes; passive `--save-session` capture does not. Cleanup finalizes traces. The next browser tool call reopens the connection and includes a note to navigate again and refresh element references. Attached CDP, extension, and VS Code browsers are disconnected; their external pages remain open. Close and session-management tools do not relaunch an idle browser. Explicit `browser_session_open` handles keep their separate `PLAYWRIGHT_MCP_BROWSER_SESSION_TTL_MS` behavior. Zero disables this feature; blank environment values leave the existing configuration unchanged.
|
|
266
|
+
|
|
267
|
+
The VS Code `browser_connect` tool accepts only `playwright` or `playwright-core` libraries and loopback WebSocket URLs. Set `PLAYWRIGHT_MCP_VSCODE_ALLOW_REMOTE=1` to allow remote endpoints, which must use `wss:`. URL userinfo credentials are rejected.
|
|
268
|
+
|
|
235
269
|
#### HTTP Heartbeat
|
|
236
270
|
|
|
237
|
-
When the server runs with `--port`, it sends MCP heartbeat pings
|
|
271
|
+
When the server runs with `--port`, it sends MCP heartbeat pings after a Streamable HTTP client opens the optional event stream. POST-only clients stay connected without heartbeat because server-initiated requests cannot reach them. Set `PLAYWRIGHT_MCP_PING_TIMEOUT_MS` to override the default `5000` ms timeout, or to `0` or any negative value to disable heartbeat pings. A client that answers `ping` with a JSON-RPC "method not found" error is treated as alive: the server stops heartbeating that session instead of closing it. Only an unanswered ping (timeout) or a transport failure closes the session.
|
|
238
272
|
|
|
239
273
|
#### Clients without the initialize handshake
|
|
240
274
|
|
|
@@ -262,7 +296,7 @@ This works out of the box in every mode, including the default persistent-profil
|
|
|
262
296
|
Record a session once with Playwright's codegen, then hand the file to the server:
|
|
263
297
|
|
|
264
298
|
```bash
|
|
265
|
-
npx playwright@1.63.0
|
|
299
|
+
npx playwright@1.63.0 codegen --save-storage=auth.json https://example.com/login
|
|
266
300
|
```
|
|
267
301
|
|
|
268
302
|
Sign in in the opened browser, then close it — `auth.json` now holds the cookies and local storage.
|
|
@@ -290,10 +324,14 @@ PLAYWRIGHT_MCP_ISOLATED=true PLAYWRIGHT_MCP_STORAGE_STATE=./auth.json npx mcp-ac
|
|
|
290
324
|
|
|
291
325
|
> **Every supported mode handles the state — by applying it or refusing it.**
|
|
292
326
|
>
|
|
327
|
+
> **Playwright 1.63.0 safety restriction:** importing into an existing context is rejected before taking a rollback snapshot or resetting any storage. On this pin, snapshot capture can execute service-worker-served scripts for a previously visited origin whose tab is no longer open ([upstream fix](https://github.com/microsoft/playwright/pull/42664)). Use a fresh context, or omit `--storage-state` and sign in interactively. Service workers are not disabled. A future dependency upgrade must also pass the recorder/shared-client checks in [#218](https://github.com/JustasMonkev/mcp-accessibility-scanner/issues/218) and IndexedDB checks in [#224](https://github.com/JustasMonkev/mcp-accessibility-scanner/issues/224) before this restriction is reconsidered.
|
|
328
|
+
>
|
|
329
|
+
> **IndexedDB snapshot limitation:** on pinned Playwright 1.63.0 with Chromium 153.0.8010.12 and Firefox 155.0, `storageState({ indexedDB: true })` loses `Map` and `Set` contents. Both `newContext({ storageState })` and `setStorageState()` restore them as empty plain objects; ordinary JSON records survive. Fresh contexts protect existing browser data, but cannot recover values already lost during capture. The [upstream fix](https://github.com/microsoft/playwright/pull/42707) is merged but is not in this pin. Before allowing imports into existing contexts again, verify both restore paths preserve Map/Set types and entries on each supported engine, including after a failed import. The real-browser regression in `tests/browser-failures.integration.test.ts` checks that rejecting an import leaves the original Map/Set records intact and that isolated JSON IndexedDB imports still work.
|
|
330
|
+
>
|
|
293
331
|
> - **Fresh-context modes** (`--isolated`, the remote-endpoint mode, or either CDP mode combined with `--isolated`): the context is created with the storage state directly.
|
|
294
332
|
> - **Default persistent-profile mode with `--storage-state`**: the session runs in a fresh, disposable profile — unique to that session and removed when it closes — built from the state, so the recorded state is provably the only session data (without `--storage-state` the regular persistent profile is used and survives restarts, as before). Any page the launch opened (for example from a URL in `browser.launchOptions.args`) is parked on a blank replacement before the state lands, then the replacement is navigated to the same URL, so a still-running anonymous page cannot overwrite the recorded identity and a scan never reads its DOM. This also means `--storage-state` cannot be combined with `--user-data-dir` (a user-supplied profile carries its own session and will not be wiped; the server refuses the combination).
|
|
295
|
-
> - **CDP modes without `--isolated
|
|
296
|
-
> - **`--extension`** (with or without `--isolated`)
|
|
333
|
+
> - **CDP modes without `--isolated` and the VS Code provider**: `--storage-state` is rejected when the browser already has a context. Add `--isolated` in CDP mode to create a fresh context; otherwise omit the state and sign in interactively. If the browser exposes no context, the server creates one with the state. CDP sessions joining that same server-created context inherit its live state without resetting it.
|
|
334
|
+
> - **`--extension`** (with or without `--isolated`) refuses storage imports entirely: it works through the browser you are already running, where wiping cookies to install a recorded state is not an acceptable side effect, so the server refuses to start rather than doing that silently. There, sign in interactively instead — the persistent profile also keeps the session across restarts.
|
|
297
335
|
|
|
298
336
|
### Keep the crawl from destroying its own session
|
|
299
337
|
|
|
@@ -313,6 +351,8 @@ The check compares which cookies the crawled URLs carry, not their values, so a
|
|
|
313
351
|
|
|
314
352
|
## Available Tools
|
|
315
353
|
|
|
354
|
+
Page-registered WebMCP tools are not currently exposed. See the [WebMCP adoption decision](https://github.com/JustasMonkev/mcp-accessibility-scanner/blob/main/docs/decisions/001-webmcp-adoption.md) for the deferral and conditions for revisiting an opt-in capability.
|
|
355
|
+
|
|
316
356
|
The MCP server provides comprehensive browser automation and accessibility scanning tools:
|
|
317
357
|
|
|
318
358
|
### Core Accessibility Tool
|
|
@@ -331,7 +371,7 @@ Performs a comprehensive accessibility scan on the current page using Axe-core.
|
|
|
331
371
|
**Annotated screenshots:**
|
|
332
372
|
When `annotateScreenshot` is `true`, each violating element is outlined and labelled with the rule ids it failed, a full-page PNG is written to the MCP output directory (`scan-page-annotated-{timestamp}-{token}.png`) and returned as a resource link, and the markers are then removed so the page is left exactly as it was. The markers are drawn in an out-of-flow overlay clipped to each element's own box, so they never reflow the page. The overlay uses a fresh id per scan, is placed in the browser's top layer so it stays visible over an open dialog, popover or fullscreen element, and compensates for a CSS `zoom` or a scaled ancestor so markers line up with what is rendered.
|
|
333
373
|
An element that fails several rules gets one box listing every rule id, and elements inside open shadow roots are marked by walking the shadow path Axe reports.
|
|
334
|
-
Running animations are
|
|
374
|
+
Running animations are frozen at their current time before the elements are measured and resumed after the capture, so a moving target keeps its marker. The markers themselves live in a shadow root under an overlay whose own styles are `!important`, so page CSS cannot restyle or hide what the report counts, and each rule label sits outside the clipped box so it stays readable on an element smaller than its own label.
|
|
335
375
|
At most 50 elements are annotated per scan. The result text always reports how many nodes were marked out of the total, plus how many were left out because they exceeded the limit, were hidden, zero-size or off-canvas (a full-page screenshot is clipped to the document box), or were inside an iframe (cross-frame selectors cannot be resolved from the top document).
|
|
336
376
|
|
|
337
377
|
**Supported Violation Tags:**
|
|
@@ -380,6 +420,7 @@ A frame you scoped out yourself is not reported: with `excludeSelectors: ["ifram
|
|
|
380
420
|
Crawls and scans multiple internal pages, then aggregates violations across the site.
|
|
381
421
|
- Default strategy: link-based BFS from the current URL
|
|
382
422
|
- Supports `links`, `nav`, `sitemap`, and `provided` URL strategies
|
|
423
|
+
- Sitemap URLs and every redirect must pass the server network policy and crawl scope. Fetches run on the MCP host, use HTTP(S) without browser cookies or auth headers, and have a 15-second total timeout, 20-redirect cap, and 10 MiB response limit. Browser proxy settings, `browser.remoteEndpoint`, `browser.cdpEndpoint` (including loopback endpoints, which may tunnel to remote browsers), and switched `browser_connect` providers are rejected for this strategy; use `provided` URLs in these modes. Sitemap TLS certificates must be valid even when browser HTTPS errors are ignored.
|
|
383
424
|
- Always writes a JSON report (default filename: `audit-site-{timestamp}-{token}.json`)
|
|
384
425
|
- Warns and records `sessionLosses` if the crawl loses cookies it started with — see [Auditing pages behind a login](#auditing-pages-behind-a-login)
|
|
385
426
|
|
|
@@ -497,9 +538,10 @@ Set default operation timeout for existing tabs.
|
|
|
497
538
|
Capture accessibility snapshot of the current page (better than screenshot for analysis).
|
|
498
539
|
Large `data:` URL payloads in snapshot output are truncated to their media type prefix.
|
|
499
540
|
AI snapshots mark a visually present subtree excluded from accessibility queries with `[aria-hidden]` on its boundary element. Descendants are not marked again.
|
|
500
|
-
- Parameters: `compress` (optional boolean, default false)
|
|
501
|
-
- When true, repeated non-interactive ARIA snapshot nodes are collapsed in the rendered response when a repeated structural pattern appears more than 100 times. The first 10 examples of each collapsed pattern are kept.
|
|
541
|
+
- Parameters: `compress` (optional boolean, default false), `boxes` (optional boolean; overrides `snapshot.boxes` for this call)
|
|
542
|
+
- When `compress` is true, repeated non-interactive ARIA snapshot nodes are collapsed in the rendered response when a repeated structural pattern appears more than 100 times. The first 10 examples of each collapsed pattern are kept.
|
|
502
543
|
- Use `browser_evaluate()` to retrieve the full uncompressed list when needed.
|
|
544
|
+
- When `boxes` is true, each element includes `[box=x,y,width,height]` in viewport-relative CSS pixels.
|
|
503
545
|
|
|
504
546
|
#### `browser_find`
|
|
505
547
|
Search the current page accessibility snapshot without returning the full snapshot.
|
|
@@ -541,6 +583,14 @@ Fill multiple fields with one call.
|
|
|
541
583
|
Press a key on the keyboard.
|
|
542
584
|
- Parameters: `key` (e.g., 'ArrowLeft' or 'a')
|
|
543
585
|
|
|
586
|
+
#### `browser_start_recording` / `browser_stop_recording`
|
|
587
|
+
Record browser actions and return them as Playwright JavaScript. Start the server with `--caps devtools`, call `browser_start_recording`, perform the flow, then call `browser_stop_recording`.
|
|
588
|
+
|
|
589
|
+
Multi-tab recordings include the `context.newPage()` declarations needed by generated page aliases.
|
|
590
|
+
Recorded assertions include the `playwright/test` `expect` setup they need to run.
|
|
591
|
+
|
|
592
|
+
Handshake-free HTTP clients must first call `browser_session_open`, then pass its `browserSessionId` to both recording tools so the recording survives across requests. Modes that cannot open separate browser sessions, such as `--extension` and non-isolated CDP attach, need a stateful MCP connection for recording.
|
|
593
|
+
|
|
544
594
|
#### `browser_evaluate`
|
|
545
595
|
Evaluate a JavaScript expression on the page, or on a specific element when a `ref` is provided. The function's return value is serialized back as the result.
|
|
546
596
|
- Parameters: `function` (e.g., `() => document.title` or `(element) => element.textContent`), `element` (optional), `ref` (optional)
|
|
@@ -554,6 +604,7 @@ Evaluate a JavaScript expression on the page, or on a specific element when a `r
|
|
|
554
604
|
Take a screenshot of the current page.
|
|
555
605
|
- Parameters: `filename` (optional), `type` (`png`, `jpeg`, or `webp`), `scale` (`css` or `device`, default `css`), `fullPage` (optional), `element`/`ref` pair (for element screenshots)
|
|
556
606
|
- `scale: device` captures a high-resolution screenshot using device pixels (accounts for the device pixel ratio); `scale: css` keeps the image sized in CSS pixels.
|
|
607
|
+
- An empty capture is an error, and its output file is removed, including automatically named files. The requested format is never silently changed. If a WebP capture is empty, reduce its dimensions or explicitly request PNG/JPEG.
|
|
557
608
|
|
|
558
609
|
#### `browser_pdf_save`
|
|
559
610
|
Save page as PDF.
|
|
@@ -565,6 +616,12 @@ This tool requires `--caps pdf` in the CLI.
|
|
|
565
616
|
Install the configured browser engine (use when browser executable is missing).
|
|
566
617
|
- Parameters: none
|
|
567
618
|
|
|
619
|
+
Disabled by default. Enable it at server startup with `--caps install`, `PLAYWRIGHT_MCP_CAPS=install`, or `"capabilities": ["install"]` in the config file. Explicit `core-install` settings remain supported as a deprecated alias; use `install` in new configurations. Without this opt-in, the tool is neither listed nor callable; existing browser installations can still be used.
|
|
620
|
+
|
|
621
|
+
This tool invokes Playwright's installer, which downloads executable code. In [Playwright 1.63.0](https://github.com/microsoft/playwright/blob/v1.63.0/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts), browser archives have no checksum or signature verification before extraction; the default download hosts use HTTPS. Only enable installation when you trust the download source and TLS configuration, including any custom `PLAYWRIGHT_DOWNLOAD_HOST`, browser-specific host overrides, or TLS-inspecting proxy. Do not disable TLS certificate validation.
|
|
622
|
+
|
|
623
|
+
For deployments that require independently verified binaries, provision the browser through your trusted deployment process and use `--executable-path` or an existing browser connection. The capability opt-in limits MCP-triggered installation; it does not add archive verification or change manual, CI, or Docker build downloads.
|
|
624
|
+
|
|
568
625
|
### Browser Management
|
|
569
626
|
|
|
570
627
|
#### `browser_close`
|
|
@@ -574,6 +631,10 @@ Close the page.
|
|
|
574
631
|
Resize the browser window.
|
|
575
632
|
- Parameters: `width`, `height`
|
|
576
633
|
|
|
634
|
+
#### `browser_emulate_media`
|
|
635
|
+
Emulate CSS media features on the current page without resetting omitted features.
|
|
636
|
+
- Parameters: `colorScheme` (`light` or `dark`), `reducedMotion` (`reduce` or `no-preference`), `forcedColors` (`active` or `none`), `contrast` (`more` or `no-preference`), and `media` (`screen` or `print`); provide at least one.
|
|
637
|
+
|
|
577
638
|
### Tab Management
|
|
578
639
|
|
|
579
640
|
#### `browser_tabs`
|
|
@@ -637,6 +698,7 @@ Handle browser dialogs (alerts, confirms, prompts).
|
|
|
637
698
|
#### `browser_file_upload`
|
|
638
699
|
Upload files to the page.
|
|
639
700
|
- Parameters: `paths` (array of absolute file paths)
|
|
701
|
+
- If `setFiles` fails, the chooser stays available for another upload attempt; `paths: []` clears the selection and completes the chooser. A successful upload clears only that chooser and waits for page activity and the configured settle delay.
|
|
640
702
|
|
|
641
703
|
#### `browser_verify_element_visible`
|
|
642
704
|
Verify an element by ARIA role/name.
|
|
@@ -733,6 +795,79 @@ cd mcp-accessibility-scanner
|
|
|
733
795
|
npm install
|
|
734
796
|
```
|
|
735
797
|
|
|
798
|
+
### Playwright upgrade gate
|
|
799
|
+
|
|
800
|
+
The September 16, 2026 review keeps `playwright` and `playwright-core` paired at
|
|
801
|
+
**1.63.0**, the [latest stable release](https://github.com/microsoft/playwright/releases/tag/v1.63.0)
|
|
802
|
+
on that date. Keep the local `InputRecorder` hub and the existing factory reference
|
|
803
|
+
counts: multiple MCP clients share one client-side browser context, while the hub
|
|
804
|
+
multiplexes session logs and explicit recordings and excludes sibling tool actions.
|
|
805
|
+
A dependency bump alone must not change that ownership model.
|
|
806
|
+
|
|
807
|
+
Before adopting a stable release containing [upstream #42627](https://github.com/microsoft/playwright/pull/42627),
|
|
808
|
+
adapt the hub from `_enableRecorder` / `_disableRecorder` to
|
|
809
|
+
`_startRecording({ language: 'javascript' }, sink)` / `_stopRecording()` and verify
|
|
810
|
+
the per-client event contract against the installed runtime. Do not ship a
|
|
811
|
+
prerelease bump or an untested method-name fallback. Migrating to the separate
|
|
812
|
+
connections in [#42622](https://github.com/microsoft/playwright/pull/42622) is a
|
|
813
|
+
separate ownership change requiring the same lifecycle checks.
|
|
814
|
+
|
|
815
|
+
Install the pinned Chromium browser, then run the real recorder gate alongside
|
|
816
|
+
its failure and concurrency tests:
|
|
817
|
+
|
|
818
|
+
```bash
|
|
819
|
+
npx playwright install chromium
|
|
820
|
+
npx vitest run tests/recorder.integration.test.ts tests/context.test.ts tests/browserSessions.test.ts tests/browserContextFactory.test.ts tests/tools-recorder.test.ts tests/sessionLog.test.ts
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
The real-browser tests cover concurrent starts, duplicate-start rejection,
|
|
824
|
+
shared CDP clients, sibling-action attribution, stop/disconnect/restart,
|
|
825
|
+
`--save-session`, and recording across stateless explicit sessions. Existing unit
|
|
826
|
+
tests also cover failed-start recovery and overlapping start/stop. The recorder
|
|
827
|
+
must receive the final input event before stop; unbuffered input delivered after
|
|
828
|
+
stop begins is excluded, while buffered clicks/navigation get a 500 ms drain.
|
|
829
|
+
|
|
830
|
+
Also recheck the dependency fixes motivating the upgrade. On 1.63.0 Chromium,
|
|
831
|
+
both full-page and oversized element screenshots changed `navigator.maxTouchPoints`
|
|
832
|
+
from 1 to 0 and `(pointer: coarse)` from true to false; navigation restored the
|
|
833
|
+
properties ([#42617](https://github.com/microsoft/playwright/pull/42617)).
|
|
834
|
+
The fixed-header/smooth-scroll retry fixture clicked successfully but emitted 19
|
|
835
|
+
scroll events rather than instant jumps ([#42626](https://github.com/microsoft/playwright/pull/42626)).
|
|
836
|
+
A candidate upgrade must preserve touch properties after full-page and element
|
|
837
|
+
screenshots and navigation, and complete retry scrolling without smooth animation.
|
|
838
|
+
These are dependency limitations; the recorder gate alone does not verify them.
|
|
839
|
+
|
|
840
|
+
### MCP harnesses
|
|
841
|
+
|
|
842
|
+
The npm wrappers build first, then the direct harness calls every exposed MCP
|
|
843
|
+
tool with prepared fixtures:
|
|
844
|
+
|
|
845
|
+
```bash
|
|
846
|
+
npm run test:mcp
|
|
847
|
+
npm run test:mcp:install
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
The Luna wrapper runs each prompt through Codex `gpt-5.6-luna` with xhigh
|
|
851
|
+
reasoning. It uses a repo-scoped scanner MCP server, read-only Codex sandbox,
|
|
852
|
+
structured PASS/FAIL evidence, and a per-prompt timeout:
|
|
853
|
+
|
|
854
|
+
```bash
|
|
855
|
+
npm run test:mcp:luna
|
|
856
|
+
npm run test:mcp:luna -- --only browser_snapshot
|
|
857
|
+
npm run test:mcp:luna -- --skip-optional --limit 1
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
Results are written under `test-results/mcp-direct-harness-results/` or
|
|
861
|
+
`test-results/mcp-tool-loop-results/`. Set `MCP_HARNESS_RESULTS_DIR` to use another output root.
|
|
862
|
+
The Luna harness checks Codex login before starting any prompts. Its site-audit
|
|
863
|
+
prompt uses a local HTTP fixture, not a public website.
|
|
864
|
+
PASS requires a completed target MCP call, no failed or unfinished MCP calls,
|
|
865
|
+
and a successful structured result. Invalid logs, failed turns, and timeouts
|
|
866
|
+
fail the run. Non-fatal startup notices about ignored malformed local agent
|
|
867
|
+
roles remain in the logs; they do not count as tool failures. Recovered Codex
|
|
868
|
+
connection retries are accepted only when the turn completes successfully.
|
|
869
|
+
Canceling the run exits with status 130.
|
|
870
|
+
|
|
736
871
|
### Benchmarking tool latency
|
|
737
872
|
|
|
738
873
|
`bench/mcp-bench.mjs` measures what a client actually waits for: it serves a fixed
|
package/config.d.ts
CHANGED
|
@@ -25,8 +25,9 @@ export type ToolCapability =
|
|
|
25
25
|
| 'files'
|
|
26
26
|
| 'install'
|
|
27
27
|
| 'testing'
|
|
28
|
-
| 'core-install'
|
|
28
|
+
| 'core-install' // Deprecated alias for 'install'; requires explicit opt-in.
|
|
29
29
|
| 'core-tabs'
|
|
30
|
+
| 'devtools'
|
|
30
31
|
| 'vision'
|
|
31
32
|
| 'verify';
|
|
32
33
|
|
|
@@ -56,6 +57,13 @@ export type Config = {
|
|
|
56
57
|
*/
|
|
57
58
|
userDataDir?: string;
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Chrome profile directory name used in extension mode (for example
|
|
62
|
+
* "Default" or "Profile 1"); defaults to the last-used profile that
|
|
63
|
+
* has the extension installed.
|
|
64
|
+
*/
|
|
65
|
+
profileDirName?: string;
|
|
66
|
+
|
|
59
67
|
/**
|
|
60
68
|
* Launch options passed to
|
|
61
69
|
* @see https://playwright.dev/docs/api/class-browsertype#browser-type-launch-persistent-context
|
|
@@ -104,6 +112,18 @@ export type Config = {
|
|
|
104
112
|
* Remote endpoint to connect to an existing Playwright server.
|
|
105
113
|
*/
|
|
106
114
|
remoteEndpoint?: string;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Directories that browser_file_upload and browser_drop may read files from.
|
|
118
|
+
* When unset (default), any absolute path is allowed; when set, upload
|
|
119
|
+
* canonical file paths must stay inside these directories. Restricted
|
|
120
|
+
* uploads accept regular files up to 50 MiB total per call. [] denies all;
|
|
121
|
+
* non-empty lists require macOS or Linux with /proc/self/fd available.
|
|
122
|
+
* Roots must exist and are canonicalized once at startup. null is invalid.
|
|
123
|
+
* blank entries are invalid. Also PLAYWRIGHT_MCP_ALLOWED_UPLOAD_DIRS or
|
|
124
|
+
* --allowed-upload-dirs (semicolon-separated; empty string means []).
|
|
125
|
+
*/
|
|
126
|
+
allowedUploadDirs?: string[];
|
|
107
127
|
},
|
|
108
128
|
|
|
109
129
|
server?: {
|
|
@@ -116,6 +136,14 @@ export type Config = {
|
|
|
116
136
|
* The host to bind the server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.
|
|
117
137
|
*/
|
|
118
138
|
host?: string;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* When set, HTTP transport requests must carry `Authorization: Bearer <token>`.
|
|
142
|
+
* Blank or malformed tokens are rejected. Requires a loopback listener;
|
|
143
|
+
* remote access must use a TLS reverse proxy. Also configurable through
|
|
144
|
+
* PLAYWRIGHT_MCP_AUTH_TOKEN.
|
|
145
|
+
*/
|
|
146
|
+
authToken?: string;
|
|
119
147
|
},
|
|
120
148
|
|
|
121
149
|
/**
|
|
@@ -127,6 +155,7 @@ export type Config = {
|
|
|
127
155
|
* - 'wait': Wait and timing utilities.
|
|
128
156
|
* - 'files': File upload/download support.
|
|
129
157
|
* - 'install': Browser installation utilities.
|
|
158
|
+
* - 'devtools': Browser recording utilities.
|
|
130
159
|
*/
|
|
131
160
|
capabilities?: ToolCapability[];
|
|
132
161
|
|
|
@@ -163,9 +192,19 @@ export type Config = {
|
|
|
163
192
|
};
|
|
164
193
|
|
|
165
194
|
/**
|
|
166
|
-
*
|
|
195
|
+
* Image response policy. Defaults to "allow"; "auto" is a legacy alias for "allow".
|
|
196
|
+
* "omit" excludes images. "only" omits text from successful responses containing images,
|
|
197
|
+
* but preserves errors, browser lifecycle notices, structured content and resource links. Responses without images keep text.
|
|
167
198
|
*/
|
|
168
|
-
imageResponses?: 'allow' | 'omit' | 'auto';
|
|
199
|
+
imageResponses?: 'allow' | 'omit' | 'auto' | 'only';
|
|
200
|
+
|
|
201
|
+
snapshot?: {
|
|
202
|
+
/**
|
|
203
|
+
* Include each element's bounding box as [box=x,y,width,height] in snapshots.
|
|
204
|
+
* Coordinates are viewport-relative CSS pixels.
|
|
205
|
+
*/
|
|
206
|
+
boxes?: boolean;
|
|
207
|
+
};
|
|
169
208
|
|
|
170
209
|
/**
|
|
171
210
|
* Timeout settings for Playwright operations.
|
|
@@ -185,5 +224,11 @@ export type Config = {
|
|
|
185
224
|
* How long to wait after each action for triggered work to settle before responding. Defaults to 500ms.
|
|
186
225
|
*/
|
|
187
226
|
settle?: number;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Release the default browser context after this many idle milliseconds. Zero (the default) disables it.
|
|
230
|
+
* Explicit browser sessions retain their separate idle TTL.
|
|
231
|
+
*/
|
|
232
|
+
idle?: number;
|
|
188
233
|
};
|
|
189
234
|
};
|