orkon/debug-in-devtools
514 次代码提交
| 作者 | SHA1 | 备注 | 提交日期 | |
|---|---|---|---|---|
|
|
8cfd214229 | chore: debug in devtools | ||
|
|
16db01f79c |
refactor: clean up page management (#2333)
- remove `#pages` and Puppeteer page getters - rename methods for clarity |
||
|
|
ca8d219ede |
revert: support experimental allowlist for navigate tool calls (#1935) (#2203)
This reverts commit
|
||
|
|
15a6b789da |
feat: Print object count and total sizes in get_heapsnapshot_details (#2325)
This emits object count and total shallow sizes for get_heapsnapshot_details. |
||
|
|
9bc61b43d6 | refactor: make collectors work per page (#2324) | ||
|
|
2812902ba9 |
feat: Support filter with heap snapshots aggregates (#2323)
This exposes DevTools named filters in get_heapsnapshot_details and get_heapsnapshot_class_nodes tools. This allows the client to list e.g. all objects retained through detached DOM objects. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
c065fd90ce |
fix(telemetry): resolve enum values through nested schema wrappers (#2315)
## What
`generateToolMetrics` reads an enum parameter's values by unwrapping
**at most
one** `optional` wrapper:
```ts
if (schema._def.values?.length > 0) {
values = schema._def.values;
} else {
values = schema._def.innerType._def.values; // only one level
}
```
An enum parameter wrapped in `.default().optional()` (or any nested
`optional`/`default`/`nullable` combination) therefore falls through to
`schema._def.innerType._def.values === undefined`, and `npm run
update-metrics`
(run as part of `npm run gen`) crashes:
```
TypeError: Cannot read properties of undefined (reading '0')
at validateEnumHomogeneity (build/src/telemetry/metricsRegistry.js:12)
at generateToolMetrics (build/src/telemetry/metricsRegistry.js:59)
```
## Why it matters
`npm run gen` is required whenever a tool is added or changed (per
`CONTRIBUTING.md`). Declaring an enum parameter with a default — a
natural,
documented zod pattern — silently breaks docs/metrics generation.
## Fix
Add `getEnumValues()` in `transformation.ts` that recursively unwraps
`optional` / `default` / `nullable` / `effects` wrappers, mirroring the
existing
`getZodType()`, and use it in `generateToolMetrics`. Behavior is
unchanged for
the existing bare-enum and single-`optional` cases.
## Tests
- `getEnumValues` unit tests: bare enum, `optional`, `default`, both
orders of
`default`+`optional`, and throws for a non-enum type.
- `generateToolMetrics` regression test with
`zod.enum(...).default(...).optional()`.
- `npm run typecheck`, the telemetry tests, and `npm run check-format`
pass.
---
First-time contributor here — happy to sign the CLA.
|
||
|
|
c645eee875 |
fix: keep a still-open selected page instead of falling back to the first page (#2328)
Follow-up to #2304. `createPagesSnapshot()` reselects `#pages[0]` whenever the selected page is missing from `#pages`, even when that page is still open. So a live selection can be silently swapped, not only a closed one. The case that hit us is a `devtools://` page: - the server connects with `handleDevToolsAsPage: true` (`src/browser.ts`), so DevTools frontends are pages and land in `#mcpPages` - `#pages` filters `devtools://` out (`src/McpContext.ts`, unless `experimentalDevToolsDebugging` is set) - `getPageById()` (used by `select_page`) reads `#mcpPages`, not `#pages`, so a devtools page can be selected even though `list_pages` never lists it - the next snapshot finds it missing from `#pages` and, because the fallback keys on `#pages` membership rather than `isClosed()`, reselects `#pages[0]` with the page still open (`isClosed() === false`) This reproduces on a normal Chrome (details and a repro in #2304). This change gates the fallback on `isClosed()`, as proposed in #2304. A still-open selection is kept; a genuinely closed page still auto-advances, so the browser-like behavior for closed tabs is unchanged. One consequence: the "is no longer listed" wording added in #2308 becomes unreachable, since a live page missing from the list no longer triggers a fallback. I left it in place to keep this diff focused, but I'm happy to simplify it here or in a follow-up. The unit test that covered the missing-but-open case now asserts the selection is retained. Refs: #2304 |
||
|
|
ed7e95d3e0 | fix: Wait until daemon is started (#2327) | ||
|
|
6e56c028cf |
feat: support --allow-unrestricted-paths configuration (#2296)
## Summary validatePath() in McpContext returned immediately, with no restriction at all, whenever roots() returned undefined. roots() only returns undefined when the connecting MCP client never negotiates the optional roots capability during initialize, which any minimal client can trigger simply by omitting it from its declared capabilities. Since roots() already always appends the OS temp directory to whatever explicit roots are configured, this change makes it return that same default (temp directory only) instead of undefined when no roots have been set. This removes the early return in validatePath() entirely, so path validation now runs unconditionally rather than being conditional on whether the connecting client happened to negotiate a capability it was never required to declare per the MCP spec. Any filePath-accepting tool (take_screenshot, saveFile, and the performance/Lighthouse export tools that route through the same check) had its only path-traversal guard silently disabled for the lifetime of a connection whenever the client omitted the optional roots capability. Since this server is designed to let an LLM drive a browser, and browsed page content is not trusted input, this meant a client that simply doesn't implement roots (a plausible, non-adversarial default for lightweight or custom MCP clients) removed the only boundary preventing the connected agent from writing to any path the process can reach. Added a test that exercises the actual default state of roots (never calling setRoots()) directly, since the existing tests always call setRoots(), even with an empty array, before validating. Verified locally with a minimal MCP client that declares no capabilities: before this change, take_screenshot with a filePath outside any root wrote a real file to an arbitrary path with no error; after this change, the same call is rejected with the existing Access denied error. Also verified that a client that does declare roots is unaffected, and that writes to the OS temp directory continue to succeed with no roots negotiated, matching prior behavior for that path. |
||
|
|
ff53b7bb82 |
refactor: Use array instead of Map for idToClassKey (#2321)
Switches idToClassKey to an array since ids are strictly incremented from 1. This also allows us to drop the id generator use. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
2c16ac311b |
fix: report when the selected page was auto-replaced by the fallback (#2308)
Follow-up to #2304 (the "note" part discussed there). When the selected page disappears from the page list, `createPagesSnapshot()` silently re-selects the first page. The agent gets no signal: if its next call is `list_pages` (which is what the closed-page error message recommends), the listing already shows the new selection and every subsequent tool call runs against a page the agent never picked. This PR records the automatic fallback and surfaces it as a one-line note in the pages section of the same response: ``` ## Pages Note: the previously selected page was closed. Page 1 is now selected. 1: about:blank [selected] ``` For a selected page that is missing from the list without being closed, the note reads "is no longer listed" instead. If the expectation from #2304 holds (a page stays listed as long as it is not closed), that wording never renders; if the transient case discussed there does occur in the wild, the note will make it visible. The fallback behavior itself is unchanged (as discussed in #2304, closed tabs keep the browser-like auto-selection). No note is emitted on first connect, when nothing was selected before. Tests: two unit tests for the fallback bookkeeping (closed page, regular selection), one for the missing-but-open case via a stubbed page list, and the one affected snapshot updated (`close_page` now includes the note). Refs: #2304 |
||
|
|
ffc6060acf |
feat: update Lighthouse to 13.4.0 (#2317)
See https://github.com/GoogleChrome/lighthouse/releases/tag/v13.4.0 |
||
|
|
b2c63e644e |
perf: concurrent I/O in Root Path Resolution (#2279)
💡 **What:** Modified `McpContext.validatePath` to resolve the absolute paths for all configured workspace roots concurrently using `Promise.allSettled`, replacing the previous sequential iteration. 🎯 **Why:** The previous implementation executed potentially expensive disk I/O operations (`fs.realpath()`) synchronously one-by-one in a `for...of` loop. This caused a performance bottleneck when a user had several configured roots or during heavy file load activity, as each root had to fully resolve before proceeding to the next. 📊 **Measured Improvement:** Measured with 10 workspace roots (where only the last one matches). The change reduced execution time for a 1,000-iteration micro-benchmark from ~1,350ms to ~400ms, yielding a 70% speedup in this code path. --- *PR created automatically by Jules for task [14748109266156669449](https://jules.google.com/task/14748109266156669449) started by @Lightning00Blade* Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
3d2138945c |
feat: add experimentalGcfFormat flag for GCF-encoded tool responses (#2235)
## Summary Add `--experimentalGcfFormat` as a hidden experimental flag alongside the existing `--experimentalToonFormat`. When enabled, tool responses encode structured data using GCF (Graph Compact Format) instead of formatted JSON. No changes to existing behavior or default output. ## Why ### Benchmarked on Chrome DevTools data shapes Data shapes verified from source code and test snapshots (`ConsoleMessageConcise`, `NetworkRequestConcise`, `HeapSnapshotFormatter.toJSON()`, `SnapshotFormatter.toJSON()`): | Dataset | JSON | TOON | GCF | TOON vs JSON | GCF vs JSON | GCF vs TOON | |---------|------|------|-----|-------------|-------------|-------------| | Console (100) | 2,534 | 1,716 | 1,663 | 32.3% | 34.4% | +3.1% | | Console (500) | 12,879 | 8,761 | 8,475 | 32.0% | 34.2% | +3.3% | | Network (100) | 3,287 | 1,776 | 1,682 | 46.0% | 48.8% | +5.3% | | Network (500) | 16,547 | 8,936 | 8,442 | 46.0% | 49.0% | +5.5% | | Heap (100) | 2,210 | 797 | 753 | 63.9% | 65.9% | +5.5% | | DOM (3x3) | 282 | 295 | 244 | -4.6% | 13.5% | +17.3% | | DOM (4x3) | 396 | 464 | 407 | -17.2% | -2.8% | +12.3% | TOON increases token count on DOM snapshots (-4.6% to -17.2% vs JSON). GCF saves tokens on every data type. ### Console message corruption TOON's decoder crashes on console messages containing bracket-colon patterns, which are standard browser output: ``` [Error]: net::ERR_CONNECTION_REFUSED [React DevTools]: Component rendered 3 times [Violation]: Forced reflow while executing JavaScript took 42ms [Performance]: Long task detected (duration: 234ms) ``` 10 of 20 console messages fail TOON round-trip. GCF: zero failures. While Chrome DevTools MCP encodes only (no decode), the structurally ambiguous output can affect downstream consumers. ### LLM comprehension GCF scores 100% on general structured data and 90.7% on adversarial payloads across GPT-4o, GPT-5.5, Claude, and Gemini. JSON scores 53.6%. TOON scores 68.5%. (1,700+ evaluations.) Full eval data: [GCF benchmarks](https://gcformat.com/guide/benchmarks) ### Data integrity GCF verified lossless across 43 billion+ round-trips in 5 formats and 6 languages. Zero failures. Zero runtime dependencies. ## Implementation Mirrors the existing `experimentalToonFormat` pattern exactly: - Hidden boolean CLI flag, defaults to false - `useGcf` parameter threaded through `handle()` → `format()` - `compactEncode` helper selects GCF, TOON, or null (formatted JSON) - GCF takes precedence if both flags are set ## Changes | File | Change | |------|--------| | `src/bin/chrome-devtools-mcp-cli-options.ts` | Add `experimentalGcfFormat` flag | | `src/third_party/index.ts` | Export `gcfEncode` from `@blackwell-systems/gcf` | | `src/McpResponse.ts` | Add `useGcf` parameter, `compactEncode` helper | | `src/ToolHandler.ts` | Pass `experimentalGcfFormat` to `handle()` | | `package.json` | Add `@blackwell-systems/gcf` (pinned 2.1.2, zero deps) | ## Links - GCF spec: https://gcformat.com - TypeScript SDK: https://www.npmjs.com/package/@blackwell-systems/gcf - Benchmarks: https://gcformat.com/guide/benchmarks - Lossless verification: https://gcformat.com/guide/lossless-verification --------- Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org> |
||
|
|
b06e39b164 |
fix: enforce .gz instead of json.gz in performance tools (#2305)
Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2303 |
||
|
|
b703f2ce20 |
fix(snapshot): resolve element ids on the correct snapshot (#2295)
closes https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2243 This probably regressed with the addition of third party developer tools because the resolveCdpElementId was not moved from page to TextSnapshot. |
||
|
|
913308263b |
chore(main): release chrome-devtools-mcp 1.5.0 (#2252)
publish-on-tag / publish-to-npm (push) Has been cancelled
publish-on-tag / publish-to-mcp-registry (push) Has been cancelled
🤖 I have created a release *beep* *boop* --- ## [1.5.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v1.4.0...chrome-devtools-mcp-v1.5.0) (2026-07-03) ### 🎉 Features * Add get_heapsnapshot_duplicate_strings MCP tool ([#2280](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2280)) ([ |
||
|
|
67a56c0557 |
feat: Add get_heapsnapshot_duplicate_strings MCP tool (#2280)
This PR adds a new MCP tool to find duplicated strings in the heap snapshot. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
a9228141ae |
fix: validate extension-enforced output paths (#2269)
Fixes output path validation so tools cannot validate one path and then write to a different canonical target after extension enforcement. Changes: - Resolve dangling symlinks to their target path during canonicalization. - Validate the final extension-enforced output path before writing. - Apply the same final-path validation to heap snapshots and screencasts. - Add regression coverage for dangling symlinks that point outside configured roots. Validation: - npm run format - npm run check-format - npm run test tests/utils/files.test.ts - npm run test tests/roots.test.ts - npm run test tests/tools/memory.test.ts tests/tools/screencast.test.ts Note: I also ran the full npm test suite locally. The targeted tests above passed, but the full suite hit local WSL daemon/e2e startup timeouts while waiting for daemon.pid / server_start, which appear unrelated to this path-validation change. --------- Co-authored-by: huynhtrungcsc <huynhtrungcsc@users.noreply.github.com> |
||
|
|
cf00305170 |
fix(cli): improve error messages to guide AI agents and developers (#2161)
Co-authored-by: Nicholas Roscino <nroscino@google.com> Co-authored-by: Piotr Paulski <31672205+zyzyzyryxy@users.noreply.github.com> Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org> |
||
|
|
3f4a49a89a |
refactor: Merge MCP tools for comparing heap snapshots (#2281)
Instead of two separate MCP tools, we can have one instead which takes classIndex as optional argument. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
8d8cf1299d |
docs: fix formatting and indentation of tool descriptions (#2275)
Follow-up on formatting changes introduced by dependency update in #2266 Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org> |
||
|
|
ce5edbd6a3 |
chore(deps-dev): bump the dev-dependencies group across 1 directory with 7 updates (#2266)
Bumps the dev-dependencies group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@google/genai](https://github.com/googleapis/js-genai) | `2.9.0` | `2.10.0` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.0.0` | `26.0.1` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.61.1` | `8.62.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.61.1` | `8.62.0` | | [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` | | [prettier](https://github.com/prettier/prettier) | `3.8.4` | `3.9.3` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.61.1` | `8.62.0` | Updates `@google/genai` from 2.9.0 to 2.10.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/googleapis/js-genai/releases">@google/genai's releases</a>.</em></p> <blockquote> <h2>v2.10.0</h2> <h2><a href="https://github.com/googleapis/js-genai/compare/v2.9.0...v2.10.0">2.10.0</a> (2026-06-24)</h2> <h3>Features</h3> <ul> <li>[Interactions] Add ComputerUse.disabled_safety_policies (<a href="https://github.com/googleapis/js-genai/commit/a2ca95cb81230ac371864914d2ad655c3f83c7bb">a2ca95c</a>)</li> <li>[Models] Add ComputerUse.disabled_safety_policies (<a href="https://github.com/googleapis/js-genai/commit/3618023147fe8ba63a9ecfa00253ab489e74aba8">3618023</a>)</li> <li>add usage fields for steps (<a href="https://github.com/googleapis/js-genai/commit/048db9a660d6cb7107212baab64e694db8498dfc">048db9a</a>)</li> <li>add video generation and response format parameters. (<a href="https://github.com/googleapis/js-genai/commit/84e795cf4add4ca9dffe47828d6528e19d684d54">84e795c</a>)</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/googleapis/js-genai/blob/main/CHANGELOG.md">@google/genai's changelog</a>.</em></p> <blockquote> <h2><a href="https://github.com/googleapis/js-genai/compare/v2.9.0...v2.10.0">2.10.0</a> (2026-06-24)</h2> <h3>Features</h3> <ul> <li>[Interactions] Add ComputerUse.disabled_safety_policies (<a href="https://github.com/googleapis/js-genai/commit/a2ca95cb81230ac371864914d2ad655c3f83c7bb">a2ca95c</a>)</li> <li>[Models] Add ComputerUse.disabled_safety_policies (<a href="https://github.com/googleapis/js-genai/commit/3618023147fe8ba63a9ecfa00253ab489e74aba8">3618023</a>)</li> <li>add usage fields for steps (<a href="https://github.com/googleapis/js-genai/commit/048db9a660d6cb7107212baab64e694db8498dfc">048db9a</a>)</li> <li>add video generation and response format parameters. (<a href="https://github.com/googleapis/js-genai/commit/84e795cf4add4ca9dffe47828d6528e19d684d54">84e795c</a>)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/googleapis/js-genai/commit/31223a3e02a5d1c8146ad2673df5a1c7e4bababb"><code>31223a3</code></a> chore(main): release 2.10.0 (<a href="https://redirect.github.com/googleapis/js-genai/issues/1725">#1725</a>)</li> <li><a href="https://github.com/googleapis/js-genai/commit/628f3f2e83202fc040cbc502e98108689489be69"><code>628f3f2</code></a> chore: Disable ComputerUse.disabled_safety_policies in Gemini Enterprise API</li> <li><a href="https://github.com/googleapis/js-genai/commit/84e795cf4add4ca9dffe47828d6528e19d684d54"><code>84e795c</code></a> feat: add video generation and response format parameters.</li> <li><a href="https://github.com/googleapis/js-genai/commit/048db9a660d6cb7107212baab64e694db8498dfc"><code>048db9a</code></a> feat: add usage fields for steps</li> <li><a href="https://github.com/googleapis/js-genai/commit/a2ca95cb81230ac371864914d2ad655c3f83c7bb"><code>a2ca95c</code></a> feat: Add ComputerUse.disabled_safety_policies</li> <li><a href="https://github.com/googleapis/js-genai/commit/3618023147fe8ba63a9ecfa00253ab489e74aba8"><code>3618023</code></a> feat: Add ComputerUse.disabled_safety_policies</li> <li><a href="https://github.com/googleapis/js-genai/commit/eeee71122760ddba9df72611a013c1bd78fc0d7d"><code>eeee711</code></a> docs: fix typos across docstrings</li> <li><a href="https://github.com/googleapis/js-genai/commit/a12a590062760dd75899dc3c28564d3ae62bf67a"><code>a12a590</code></a> chore: Upgrade stalebot action to use v10 (due to Node20 deprecation)</li> <li>See full diff in <a href="https://github.com/googleapis/js-genai/compare/v2.9.0...v2.10.0">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 26.0.0 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@typescript-eslint/eslint-plugin` from 8.61.1 to 8.62.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/releases">@typescript-eslint/eslint-plugin's releases</a>.</em></p> <blockquote> <h2>v8.62.0</h2> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>🩹 Fixes</h3> <ul> <li>add "files" to rule-schema-to-typescript-types (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12441">#12441</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md">@typescript-eslint/eslint-plugin's changelog</a>.</em></p> <blockquote> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/54e285728e5d8cb83fadb8041189f0c3b4ab436a"><code>54e2857</code></a> chore(release): publish 8.62.0</li> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/81e4c2654c3f4d923766a888691add2c45b5d64a"><code>81e4c26</code></a> feat: remove redundant package.json "files" (<a href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/12444">#12444</a>)</li> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/b784054b6f8fbb51eb742304852b37b0436a8a58"><code>b784054</code></a> chore: use <code>stableTypeOrdering</code> compiler option (<a href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/12427">#12427</a>)</li> <li>See full diff in <a href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.0/packages/eslint-plugin">compare view</a></li> </ul> </details> <br /> Updates `@typescript-eslint/parser` from 8.61.1 to 8.62.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/releases">@typescript-eslint/parser's releases</a>.</em></p> <blockquote> <h2>v8.62.0</h2> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>🩹 Fixes</h3> <ul> <li>add "files" to rule-schema-to-typescript-types (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12441">#12441</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md">@typescript-eslint/parser's changelog</a>.</em></p> <blockquote> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/54e285728e5d8cb83fadb8041189f0c3b4ab436a"><code>54e2857</code></a> chore(release): publish 8.62.0</li> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/81e4c2654c3f4d923766a888691add2c45b5d64a"><code>81e4c26</code></a> feat: remove redundant package.json "files" (<a href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser/issues/12444">#12444</a>)</li> <li>See full diff in <a href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.0/packages/parser">compare view</a></li> </ul> </details> <br /> Updates `globals` from 17.6.0 to 17.7.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/sindresorhus/globals/releases">globals's releases</a>.</em></p> <blockquote> <h2>v17.7.0</h2> <ul> <li>Update globals (2026-06-22) (<a href="https://redirect.github.com/sindresorhus/globals/issues/345">#345</a>) 33b75f9</li> </ul> <hr /> <p><a href="https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0">https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/sindresorhus/globals/commit/a19670cc86c1218e915657c55ea02ba3e7623834"><code>a19670c</code></a> 17.7.0</li> <li><a href="https://github.com/sindresorhus/globals/commit/9611620bad0ea45531ae0261b986ce694374e42c"><code>9611620</code></a> Update actions (<a href="https://redirect.github.com/sindresorhus/globals/issues/346">#346</a>)</li> <li><a href="https://github.com/sindresorhus/globals/commit/33b75f9ddeb6f9ddd81251b043667eb8104a8d15"><code>33b75f9</code></a> Update globals (2026-06-22) (<a href="https://redirect.github.com/sindresorhus/globals/issues/345">#345</a>)</li> <li><a href="https://github.com/sindresorhus/globals/commit/887dd529bde24486b7f9e31d1b2c515df2b7cf5c"><code>887dd52</code></a> Fix build script (<a href="https://redirect.github.com/sindresorhus/globals/issues/344">#344</a>)</li> <li>See full diff in <a href="https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0">compare view</a></li> </ul> </details> <br /> Updates `prettier` from 3.8.4 to 3.9.3 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>3.9.3</h2> <ul> <li>Markdown: Fix unexpected removal of characters in liquid syntax (<a href="https://redirect.github.com/prettier/prettier/pull/19489">prettier/prettier#19489</a> by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</li> <li>TypeScript: Allow decorators to be used with declare on class fields (<a href="https://redirect.github.com/prettier/prettier/pull/19492">prettier/prettier#19492</a> by <a href="https://github.com/evoactivity"><code>@evoactivity</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.9.3/CHANGELOG.md#393">Changelog</a></p> <h2>3.9.1</h2> <ul> <li>CLI: Fix ignored file has been cached incorrectly (<a href="https://redirect.github.com/prettier/prettier/pull/19483">#19483</a> by <a href="https://github.com/kovsu"><code>@kovsu</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.9.1/CHANGELOG.md#391">Changelog</a></p> <h2>3.9.0</h2> <p><a href="https://github.com/prettier/prettier/compare/3.8.5...3.9.0">diff</a></p> <p>🔗 <a href="https://prettier.io/blog/2026/06/27/3.9.0">Prettier 3.9: Major parser upgrades and Formatting improvements</a></p> <h2>3.8.5</h2> <ul> <li>Fix Flow variance annotation print (<a href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a> by <a href="https://github.com/marcoww6"><code>@marcoww6</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.8.5/CHANGELOG.md#385">Changelog</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>3.9.3</h1> <p><a href="https://github.com/prettier/prettier/compare/3.9.1...3.9.3">diff</a></p> <h4>Markdown: Fix unexpected removal of characters in liquid syntax (<a href="https://redirect.github.com/prettier/prettier/pull/19489">#19489</a> by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</h4> <!-- raw HTML omitted --> <pre lang="md"><code>// Input <!-- Input --> {{ page.title }} text <p><!-- Prettier 3.9.1 --><br /> {{ page.title<br /> text</p> <p><!-- Prettier 3.9.3 --><br /> {{ page.title<br /> }} text<br /> </code></pre></p> <h4>TypeScript: Allow decorators to be used with declare on class fields (<a href="https://redirect.github.com/prettier/prettier/pull/19492">#19492</a> by <a href="https://github.com/evoactivity"><code>@evoactivity</code></a>)</h4> <p>Extensively used within the Ember ecosystem, decorators with <code>declare</code> on class fields will ignore the babel parser error and allow Prettier to format the code without breaking it.</p> <!-- raw HTML omitted --> <pre lang="ts"><code>// Input export default class ProjectStatusComponent extends Component<ProjectStatusSig> { @service declare server: ServerService; } <p>// Prettier 3.9.1<br /> // SyntaxError: Decorators can't be used with a declare field. (2:3)<br /> // 1 | export default class ProjectStatusComponent extends Component<ProjectStatusSig> {<br /> //> 2 | <a href="https://github.com/service"><code>@service</code></a> declare server: ServerService;<br /> // | ^<br /> // 3 | }</p> <p>// Prettier 3.9.3<br /> export default class ProjectStatusComponent extends Component<ProjectStatusSig> {<br /> <a href="https://github.com/service"><code>@service</code></a> declare server: ServerService;<br /> }<br /> </code></pre></p> <h1>3.9.1</h1> <p><a href="https://github.com/prettier/prettier/compare/3.9.0...3.9.1">diff</a></p> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/prettier/prettier/commit/3732e1dee6a36bdb2e77a722d206a79ac7e67aa3"><code>3732e1d</code></a> Release 3.9.3</li> <li><a href="https://github.com/prettier/prettier/commit/a74a7b05dee7fbef39a6aeff378c3741e1a8ee15"><code>a74a7b0</code></a> Allow decorators to be used with <code>declare</code> on class fields (<a href="https://redirect.github.com/prettier/prettier/issues/19492">#19492</a>)</li> <li><a href="https://github.com/prettier/prettier/commit/bd9e11ab41e17a4f61f363a981c1ec24d2a4167a"><code>bd9e11a</code></a> Correct text identification in liquid syntax (<a href="https://redirect.github.com/prettier/prettier/issues/19489">#19489</a>)</li> <li><a href="https://github.com/prettier/prettier/commit/269eee3faa1f82b1de07bb7e4d15e1cee70f80d4"><code>269eee3</code></a> Bump Prettier dependency to 3.9.1</li> <li><a href="https://github.com/prettier/prettier/commit/ec7ccd1ea47c965bda3c958239899737e899603d"><code>ec7ccd1</code></a> Clean changelog_unreleased</li> <li><a href="https://github.com/prettier/prettier/commit/c47654c003fe525572e10d5cc1ea64d7b9c0ee55"><code>c47654c</code></a> Release 3.9.1</li> <li><a href="https://github.com/prettier/prettier/commit/06159aa254e662514d1c6f4de13fbac805984232"><code>06159aa</code></a> Fix bug in release script</li> <li><a href="https://github.com/prettier/prettier/commit/4bc5ab40582921f5283af4ff5d6511b58d25ec00"><code>4bc5ab4</code></a> Update file-entry-cache to 11.1.5 (<a href="https://redirect.github.com/prettier/prettier/issues/19483">#19483</a>)</li> <li><a href="https://github.com/prettier/prettier/commit/b7fd58bba027282038ad312af0522d4598e8b769"><code>b7fd58b</code></a> Release <code>@prettier/plugin-oxc@0.2.0</code> and <code>@prettier/plugin-hermes@0.2.0</code></li> <li><a href="https://github.com/prettier/prettier/commit/3006400fc2560e297b54d82c58cbc331ec87902c"><code>3006400</code></a> Revert changes in release script</li> <li>Additional commits viewable in <a href="https://github.com/prettier/prettier/compare/3.8.4...3.9.3">compare view</a></li> </ul> </details> <br /> Updates `typescript-eslint` from 8.61.1 to 8.62.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/releases">typescript-eslint's releases</a>.</em></p> <blockquote> <h2>v8.62.0</h2> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>🩹 Fixes</h3> <ul> <li>add "files" to rule-schema-to-typescript-types (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12441">#12441</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md">typescript-eslint's changelog</a>.</em></p> <blockquote> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/54e285728e5d8cb83fadb8041189f0c3b4ab436a"><code>54e2857</code></a> chore(release): publish 8.62.0</li> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/81e4c2654c3f4d923766a888691add2c45b5d64a"><code>81e4c26</code></a> feat: remove redundant package.json "files" (<a href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint/issues/12444">#12444</a>)</li> <li>See full diff in <a href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.0/packages/typescript-eslint">compare view</a></li> </ul> </details> <br /> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nikolay Vitkov <nvitkov@chromium.org> |
||
|
|
7fa95d3c33 |
fix: create PID directory with secure permissions (0o700) (#2262)
## Summary
- Add `mode: 0o700` to `fs.mkdirSync` when creating the PID directory
- Ensures the directory is always created with owner-only access
regardless of system umask
## Problem
The daemon creates the PID directory with `fs.mkdirSync(pidDir,
{recursive: true})` without specifying a mode. On systems with `umask
002`, the directory lands at mode 0775, which the daemon's own security
check rejects as "insecure permissions" and exits.
The daemon's test (`tests/daemon/symlink.test.ts`) already expects 0700
permissions, but nothing enforced it at runtime.
Fixes #2258
## Test Plan
- [ ] `umask 0002 && npx chrome-devtools-mcp@latest` no longer crashes
- [ ] `umask 0077 && npx chrome-devtools-mcp@latest` still works
- [ ] Existing daemon tests pass
|
||
|
|
5d7b656050 |
feat: Add MCP tools for heap snapshot comparison (#2198)
This commit adds two MCP tools for comparing heap snapshots. `compare_heapsnapshot_summary` compares two memory snapshot and returns which classes have new/deleted objects. `compare_heapsnapshot_class_nodes` can then be used to list the object ids added and deleted for a specific class. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
e5bd334c97 |
chore: make TOON dependency optional (#2260)
Since toon dependency is only needed for `--experimentalToonFormat` flag, we can make it optional to decrease package size and security footprint for users that don't use it. Testing npx optional peer dependency resolution before the release: ``` npm i -g verdaccio verdaccio ``` On a separate terminal: ``` npm adduser --registry http://localhost:4873/ # follow prompts to create user and login # replace the published package in verdaccio npm unpublish chrome-devtools-mcp@1.4.0 --force --registry http://localhost:4873 npm publish --registry http://localhost:4873 # clear npx cache rm -rf ~/.npm/_npx # run the server from commandline and observe both packages being installed: npx --registry http://localhost:4873 --package chrome-devtools-mcp@latest --package @toon-format/toon chrome-devtools-mcp --experimentalToonFormat ``` Paste the following commands (each line separately) to manually interact with the mcp server and observe TOON formatted response directly ### 1. Initialize the session {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}}} ### 2. Confirm initialization {"jsonrpc":"2.0","method":"notifications/initialized"} ### 3. Navigate to Google (this will already create snapshot in most recent versions) {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"navigate_page","arguments":{"url":"https://google.com"}}} ### 4. Take Snapshot (if not returned by the previous command) {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"take_snapshot","arguments":{}}} --------- Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org> |
||
|
|
6a9466378c |
fix: respecte allow/block list in loadResouce (#2254)
Fixes https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2218 Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2225 |
||
|
|
d1449654ac |
perf: use concurrent reads for loadIssueDescriptions (#2249)
💡 **What:** Refactored `loadIssueDescriptions` in `src/issue-descriptions.ts` to use `Promise.all` for reading all the `.md` description files concurrently rather than sequentially. 🎯 **Why:** Sequential file I/O operations create unnecessary blocking. The order in which files are read does not matter when populating a map, making it safe and more performant to read them concurrently. 📊 **Measured Improvement:** A local benchmark running against the 271 generated `.md` files in `build/src/third_party/issue-descriptions` showed a decrease from ~195ms (sequential) to ~56ms (concurrent), a >70% improvement. --- *PR created automatically by Jules for task [15785526133454041422](https://jules.google.com/task/15785526133454041422) started by @Lightning00Blade* --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
0aaa8e3cc0 |
chore(main): release chrome-devtools-mcp 1.4.0 (#2228)
publish-on-tag / publish-to-npm (push) Has been cancelled
publish-on-tag / publish-to-mcp-registry (push) Has been cancelled
🤖 I have created a release *beep* *boop* --- ## [1.4.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v1.3.0...chrome-devtools-mcp-v1.4.0) (2026-06-23) ### 🎉 Features * publish the skills folder ([#2229](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2229)) ([ |
||
|
|
e559765740 |
docs: update security.md (#2248)
Clarifies the MCP roots and network guardrails. |
||
|
|
6225ffbaf1 |
fix: hide Windows update check consoles (#2231)
## Summary Fixes #2230. - Sets `windowsHide: true` on the detached update-check process so Windows does not flash a console window. - Also hides the `npm config get registry` subprocess used by the updater helper. - Covers the update-check spawn options in the existing tests. ## Verification - `NODE_OPTIONS=--max-old-space-size=4096 npm run build` - `npm run test:no-build -- tests/check-for-updates.test.ts` - `NODE_OPTIONS=--max-old-space-size=4096 npx eslint src/utils/check-for-updates.ts src/bin/check-latest-version.ts tests/check-for-updates.test.ts` - `npx prettier --check src/utils/check-for-updates.ts src/bin/check-latest-version.ts tests/check-for-updates.test.ts` - `git diff --check` Note: plain `npm run build` and full-repo `npm run check-format` hit the local Node heap limit in this runner; the same build passed with the heap limit raised, and touched-file lint/format checks passed. Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com> |
||
|
|
5a9d6af743 |
fix(network): keep redirect chain order consistent between text and JSON (#2221)
## Problem `get_network_request` returns, from the **same call**, both a human-readable text block (`toStringDetailed()`) and a `structuredContent.networkRequest` object (`toJSONDetailed()`) — emitted together in `McpResponse.ts`. For a request that went through HTTP redirects, the redirect chain comes out in **opposite orders** in the two representations: - `toJSONDetailed()` (`NetworkFormatter.ts`) reverses `redirectChain()` once → newest→oldest in the JSON. - the text formatter then reverses it **a second time** → oldest→newest in the text. Because each path calls `redirectChain()` separately and Puppeteer returns a fresh copy on every call (`HTTPRequest#redirectChain()` does `this._redirectChain.slice()`), the two reverses operate on different arrays and don't cancel. So a consumer reading the text and a consumer parsing the structured JSON from the same response see contradictory redirect orders. ## Solution Drop the redundant `.reverse()` in the text formatter so the rendered text uses the order already produced by `toJSONDetailed()`. Both representations are now consistent (newest→oldest), and `structuredContent` is unchanged. ## Why the existing tests didn't catch it - The existing "handles redirect chain" test uses a **single-element** chain, where reversing is a no-op. - `getMockRequest().redirectChain()` returned the **same array reference** on every call, unlike real Puppeteer — so the two reverses accidentally agreed in tests. This PR makes the mock return a fresh copy per call (matching Puppeteer) and adds a regression test with a multi-element chain that asserts the text and JSON orders match. ## Testing - `npm test` for the formatter suite passes. New test `renders the redirect chain in the same order in text and JSON` is **red** before the fix (text `[first, second]` vs JSON `[second, first]`) and **green** after, with no change to existing snapshots. - `npm run typecheck` and Prettier/ESLint are clean. No existing issue tracked this; found via code inspection and confirmed empirically. |
||
|
|
4716a72017 |
chore(main): release chrome-devtools-mcp 1.3.0 (#2195)
publish-on-tag / publish-to-npm (push) Has been cancelled
publish-on-tag / publish-to-mcp-registry (push) Has been cancelled
🤖 I have created a release *beep* *boop* --- ## [1.3.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v1.2.0...chrome-devtools-mcp-v1.3.0) (2026-06-18) ### 🎉 Features * Add get_heapsnapshot_dominators MCP tool ([#2215](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2215)) ([ |
||
|
|
ba80096521 |
fix: handle screencast file extensions case-insensitively and clean up temp dir on failure (#2207)
Fixes #2206 ### Problem `screencast_start` matched the requested file extension with a **case-sensitive** `endsWith()` against `['.webm', '.mp4']` and **silently fell back to `.mp4`** when nothing matched. Combined with `ensureExtension()` (which replaces the extension), a request for `demo.WEBM` was recorded as **MP4** to **`demo.mp4`** — a different format *and* path than requested — and any unsupported extension (e.g. `recording.avi`) silently became `.mp4`. Separately, when `screencast_start` is called without a `filePath`, it creates a temp directory via `mkdtemp()`. If `page.screencast()` then throws (e.g. ffmpeg missing), that directory was leaked. ### Changes Two commits: 1. **`fix: match screencast extension case-insensitively and reject unsupported ones`** — match via `path.extname().toLowerCase()`; reject an explicitly requested but unsupported extension with an explicit error listing the supported formats; a missing extension still defaults to `.mp4`. 2. **`fix: clean up screencast temp directory when recording fails to start`** — remove the generated temp dir in the `catch` handler, but only when we own the generated path (never when the caller supplied `filePath`). | requested | before | after | | --------------- | --------------- | -------------- | | `demo.WEBM` | mp4 → `demo.mp4`| webm → `demo.webm` | | `recording.avi` | mp4 → `recording.mp4` | error (rejected) | | `demo.webm` | webm → `demo.webm` | unchanged | | *(no filePath)* | mp4 temp | unchanged | The matched extension is normalized to lower case (`demo.WEBM` → `demo.webm`). ### Testing Added three regression tests to `tests/tools/screencast.test.ts` using the existing `sinon`/`withMcpContext` harness. Verified locally against Chrome for Testing 149 (`PUPPETEER_EXECUTABLE_PATH`): - With the fix reverted, the two extension tests fail (uppercase `.WEBM` → mp4, `.avi` not rejected) and the cleanup test fails (temp dir left behind) — i.e. they fail for the right reason. - With the fix applied, the full `screencast.test.ts` suite passes (11/11). - `tsc --noEmit` and `npm run check-format` (eslint + prettier) are clean. > Note: I ran the `screencast` test file (which stubs `page.screencast`) plus typecheck/lint locally; the rest of the browser-based suite I left to CI. ### Notes for reviewers - I chose to **`throw`** for an unsupported explicit extension (consistent with the ffmpeg-missing `throw` in the same handler and with the issue's "reject with an explicit error"). Happy to switch to the softer `appendResponseLine(...) + return` style used by the in-progress guard if you'd prefer. - The two commits are independent and can be split if you'd rather take them separately. - I left the pre-existing `as \`${string}.webm\`` assertion on `resolvedPath` untouched to keep the diff focused, though it's slightly misleading now that the default is `.mp4`. --------- Co-authored-by: Nicholas Roscino <nroscino@google.com> |
||
|
|
8fe398eb5d |
fix: handle missing third-party tool toolGroup description gracefully (#2224)
Angular's third-party tools currently do not provide a description of the toolGroup, only of the individual tools. We don't want to fail in this case. |
||
|
|
163a581cc1 |
chore(webmcp): s/enable-features=WebMCPTesting/enable-features=WebMCP/g (#2223)
Following https://github.com/puppeteer/puppeteer/pull/15121, this PR updates WebMCP documentation and tests to switch to the blink feature WebMCP instead of WebMCPTesting which is removed in https://chromium-review.googlesource.com/c/chromium/src/+/7921035/comment/1f0982d8_fb3efb91/ |
||
|
|
55c8a541d4 |
feat(screenshot): add CLI options to cap screenshot size at the source (#1823)
## Summary Adds **opt-in** CLI flags so operators can cap the size of screenshots returned by `take_screenshot` before they are embedded in the MCP response. Refs #879. The flags address two related symptoms reported when MCP clients display screenshots inline: 1. **Per-image dimension limit**: hosted LLM APIs commonly reject images exceeding per-image dimension constraints (typical caps are in the 2000-8000 px range, sometimes scaling down further when many images are in the same request). This is the exact error reported in #879. 2. **Cumulative request size**: after many captures, the cumulative base64 payload eventually pushes a request over the per-call body size limit imposed by the LLM API. Both can be mitigated at the source by reducing format/quality and downscaling the capture. ## New flags (all opt-in) - `--screenshot-format <jpeg|png|webp>`: override the default format used by `take_screenshot` when the caller does not specify one - `--screenshot-quality <0-100>`: override the default JPEG/WebP quality. Ignored for PNG - `--screenshot-max-width <px>`: downscale screenshots wider than this before they are returned - `--screenshot-max-height <px>`: downscale screenshots taller than this. Combines with `--screenshot-max-width`; the smaller scale wins so both bounds are respected while preserving aspect ratio For the exact error in #879, the recipe is `--screenshot-max-width=8000 --screenshot-max-height=8000` (or a smaller value such as `2000` if many images may end up in the same request, depending on the operator's chosen API). ## Implementation - Resizing leverages Puppeteer's `clip.scale` (CDP `Page.captureScreenshot`), so **no new dependencies**. - Source dimensions per capture mode: - viewport: `page.viewport()` - full page: `document.documentElement.scrollWidth/scrollHeight` via `page.evaluate()` - element (`uid`): `elementHandle.boundingBox()` - For element and full-page captures with a downscale clip, the call routes through `page.screenshot({clip})` so the scale parameter applies. `captureBeyondViewport` is left to Puppeteer's default (`true` when a clip is set), preserving correct behavior for elements below the fold and full-page captures. - ~150 lines of source code, ~200 lines of new tests. ## Backwards compatibility **Fully opt-in**: when no flags are set, `take_screenshot` returns the exact same bytes as before. No behavioral change for existing users. ## Design alignment - Aligned with the **"Reference over Value"** principle in `docs/design-principles.md`: the existing 2 MB threshold still routes oversized screenshots to a temporary file. This change only reduces the size of the **inline base64 fallback path**, which the principles document calls out as an acceptable exception when MCP clients display images natively. - The MCP server **hardcodes no LLM-specific size limits**. Operators pick the values that match their client/model combination. This keeps the maintenance surface here minimal as model limits evolve, and is intended as a **complement to, not a replacement for**, fixes in the MCP client itself. ## Addressing concerns raised in #879 > "It's not feasible for us to maintain this. Limits will change when models change." (@natorion) The flags are pure parameters; nothing about the upstream LLM is encoded in the server. When a vendor raises (or lowers) a limit, no code change is needed here, only the operator's CLI args change. > "`filePath` / `page_resize` already work as a workaround." (@OrKoN) `filePath` is great when the call site knows it's about to take a huge screenshot, but as you noted earlier in the thread, an oversized image already in the request history keeps causing failures even on subsequent calls. `page_resize` works but mutates the page being debugged. The resize in this PR happens **between Puppeteer and the MCP response**, so the inspected page is untouched and the failure mode is prevented at the source. > "Should be fixed client side." Agreed, this PR is intended as a complement, not a substitute. A client-side fix (e.g. compaction evicts/downsamples old images) handles the cumulative case for *any* MCP. A server-side cap handles the per-call dimension limit for users who hit it before compaction can kick in. The two address overlapping but distinct failure modes. Happy to drop or rework any of this if the maintainers prefer a different shape, for example making the threshold automatic from a single `--max-image-bytes` knob, or rejecting the PR entirely in favor of waiting for a client-side fix. Just wanted to put a concrete option on the table. ## Tests Added 6 new tests: - `honors screenshotFormat default from CLI args` - `keeps "png" as default format when no CLI override is set` - `downscales viewport screenshot when screenshotMaxWidth is set` - `downscales using the smaller scale when both max-width and max-height are set` - `does not resize when source is smaller than the max bounds` - `downscales full page screenshot when screenshotMaxWidth is set` All 627 tests in the suite pass. `npm run typecheck` and `npm run check-format` are clean. ## Notes for reviewers - The dimensions compared against `--screenshot-max-width/height` are **CSS pixels** (`page.viewport()`), not raw bitmap pixels. With `deviceScaleFactor > 1` (HiDPI emulation) the actual bitmap may still be larger. Happy to clarify this in the option description if preferred. - For element captures with a downscale clip, the call routes through `page.screenshot({clip})` instead of `element.screenshot()`. Same-frame elements are correct (boundingBox returns main-frame coords). I have **not** exercised this path against cross-origin iframe elements; let me know if you'd like a fallback there. - The PR is currently in **Draft** state pending CLA verification and any feedback on the framing above. Refs #879 Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/879 |
||
|
|
08c234ea4b |
feat: Add get_heapsnapshot_dominators MCP tool (#2215)
Adding the get_heapsnapshot_dominators MCP tool to show the dominators for a given node. In combination with get_heapsnapshot_retaining_paths this should help understand what keeps an object reachable and thus alive. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> Co-authored-by: Nicholas Roscino <nroscino@google.com> |
||
|
|
9e32002a69 |
fix: return error message when screencast_stop is called with no active recording (#2209)
## Summary
`screencast_stop` returns an empty response when no recording is active,
making it impossible for the calling agent to distinguish "stopped
successfully" from "nothing was recording."
`screencast_start` already handles its inverse case with an explicit
error (`"a screencast recording is already in progress"`), so this makes
`stop` consistent.
## Change
Added an error message when `screencast_stop` is called without an
active recording:
```ts
if (!data) {
response.appendResponseLine(
'Error: no active screencast recording to stop.',
);
return;
}
```
## Before
Empty tool response — agent cannot tell what happened.
## After
`Error: no active screencast recording to stop.`
---------
Co-authored-by: Nicholas Roscino <nroscino@google.com>
|
||
|
|
ed02047ae9 |
fix: Reset toolGroups before gathering toolGroups (#2200)
`getToolGroups` can be called multiple times. We want to reset the `window.__dtmcp.toolGroups` array each time to prevent duplications. |
||
|
|
4f8eb7ad6b |
feat: Add the get_heapsnapshot_edges MCP tool (#2180)
This PR adds the get_heapsnapshot_edges MCP tool. Agents can use it to look at the outgoing edges for a specifc object. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
6bd8c91678 |
feat: Use HeapSnapshotProxy.nodeIndexById (#2193)
Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
b646feb4f3 |
feat: include page title in list_pages output (#2166)
## Motivation `list_pages` shows each page's URL but not its title, which is painful when multiple pages share a host — e.g. several tabs under `app.example.com/u/0/`, `/u/1/`, `/u/2/`. There's no way to tell which is which without visiting each one, even though every page has a usable `document.title`. Fixes #2156. Closes #2175 ## What this changes - `list_pages` text output now shows the title before the URL when available: `1: My Page (https://example.com) [selected]`. If the page has no title (e.g. `about:blank`), the format is unchanged. - The structured content entry for each page now includes a `title` field alongside `id`, `url`, and `selected`. - `page.title()` is awaited with a `.catch(() => '')` so a closed or erroring page silently falls back to the URL-only format. - `format()` is made `async` to support the `await` inside the page loop; `createStructuredPage()` likewise becomes `async`. ## Testing Start the MCP server with multiple tabs open. Call `list_pages` — pages with titles now display as `id: Title (url)`. Pages without titles (`about:blank`, data URLs) display as before. --------- Co-authored-by: Piotr Paulski <31672205+zyzyzyryxy@users.noreply.github.com> |
||
|
|
834b259eb2 |
chore: expose loadResouce HostBinding (#2194)
This makes sure that if any resource that is loaded via the HostBinding will be correctly checked agains the roots object. |
||
|
|
a97c642d43 |
feat: Add retaining paths MCP tool (#2187)
This PR adds the `get_heapsnapshot_retaining_paths` MCP tool. This can be used to find the paths from the target object to the GC roots which keep that object alive. Co-authored-by: Dominik Inführ <dinfuehr@chromium.org> |
||
|
|
bede4fbdfa |
chore: install HostBindingAdapter (#2186)
This PR introduces the HostBindingAdapter to utilize the functions usually available to DevTools. Additionally I moved all the DevTools related files under a `devtools` directory to better separate the extractor logic. The patch scripts for DevTools were moved under a function to remove the side-effect nature of the file. Now gets called in a the creation of the McpContext (and a before hook in test.) |
||
|
|
702d3734f2 |
chore(main): release chrome-devtools-mcp 1.2.0 (#2153)
publish-on-tag / publish-to-npm (push) Has been cancelled
publish-on-tag / publish-to-mcp-registry (push) Has been cancelled
🤖 I have created a release *beep* *boop* --- ## [1.2.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v1.1.1...chrome-devtools-mcp-v1.2.0) (2026-06-08) ### 🎉 Features * add experimental TOON support for structured content output ([#2042](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2042)) ([ |
||
|
|
aa33bff19f |
feat: add experimental TOON support for structured content output (#2042)
Adds `--experimentalToonFormat` boolean flag, controlling how structured content is formatted in text response. By default, custom shorthand format is used. With this flag, TOON format (see https://github.com/toon-format/toon) is used instead. TOON format is supposed to be more token-efficient and less error-prone for agents to understand than json, but it's not clear if it will be better on those metrics than the custom format used so far. (Evals pending) One clear benefit over custom format would be less code to maintain if we decide to fully switch to TOON, due to dropping custom formatters and reusing json formatters used for structuredContent anyways. Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org> |
||
|
|
29e389848f |
feat: implement extension service worker logs (#1915)
This PR introduces the possiblity to collect console messages from service workers. |