Add a get_heapsnapshot_object_details MCP tool which lets the agent
query all known information about a node in the heap snapshot.
Co-authored-by: Dominik Inführ <dinfuehr@chromium.org>
## 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.
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>
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>
Moves the `-y` flag before the package name in the Antigravity JSON
configuration example.
According to official npm documentation, `npx` requires all flags to
precede positional arguments. Placing `-y` at the end caused `npx` to
treat it as an argument for the MCP server, triggering an interactive
installation prompt that hangs indefinitely in headless CLI
environments.
## 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
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>
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>
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>
## Support for Network Blocklists and Allowlists
(`--blocked-url-pattern` & `--allowed-url-pattern` arguments)
This PR adds support for CLI options to restrict network access in the
browser session via URL patterns.
### Key Features & How It Works
- **Pattern Matching:** Utilizes the [URLPattern
Standard](https://urlpattern.spec.whatwg.org/) for pattern matching.
- **Target Detachment:** Silently detaches from targets (pages/tabs)
whose URLs match blocked patterns (or do not match allowed patterns)
upon connection.
- **Runtime Blocking:** Prevents navigations and blocks runtime requests
(such as fetch/XHR and subresources) if they violate the pattern rules.
- **Mutual Exclusivity:** `--blocked-url-pattern` and
`--allowed-url-pattern` conflict with each other and cannot be
configured simultaneously.
- **Browser Requirements:**
- **`--allowed-url-pattern`**: Requires **Chrome 149+**.
- **`--blocked-url-pattern`**: Works on Chrome versions older than 149,
but **Chrome 149+ is highly recommended**.
### Important Limitations & Side Effects
- **Network Emulation/Throttling Conflict:** Network throttling is
disabled when a network blocklist/allowlist is configured, to avoid
conflicting with Puppeteer's underlying blocking mechanisms.
- Using the `emulate` tool to modify `networkConditions` (e.g. setting
to `Offline`) will throw an error: *`Network throttling is not supported
when network blocking (allowlist/blocklist) is configured.`*
- Other emulation settings (e.g., `cpuThrottlingRate`, `geolocation`,
`viewport`) are unaffected and remain fully functional.
---
### Configuration Examples
#### 1. Blocking specific domains or endpoints (Blocklist)
Add the `--blocked-url-pattern` options to the `args` list in your MCP
settings file:
```json
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest",
"--blocked-url-pattern=*://*.blocked-example.com/*",
"--blocked-url-pattern=*://*.another-blocked-example.com/*"
]
}
}
}
```
#### 2. Restricting access to authorized domains (Allowlist)
Add the `--allowed-url-pattern` options to restrict the browser to
permitted hosts (requires Chrome 149+):
```json
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest",
"--allowed-url-pattern=https://*.allowed-example.com/*",
"--allowed-url-pattern=https://*.another-allowed-example.com/*"
]
}
}
}
```
---------
Co-authored-by: Natallia Harshunova <nharshunova@chromium.org>
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
Updates the flag for the memory tooling to remove the experimental bit
(keep alias for backwards compatibility).
And updates the SKILLs to reflected the update names and point to the
available tools.
Q: Should it be called `take_heapsnapshot` or `take_heap_snapshot`?
This commit adds the close_heapsnapshot MCP tool such that the coding
agent can close heap snapshots again.
Co-authored-by: Dominik Inführ <dinfuehr@chromium.org>
Co-authored-by: Nicholas Roscino <nroscino@google.com>
## Description
Updates the README example list of coding agents for terminology
consistency.
Google recently
[announced](https://antigravity.google/blog/introducing-google-antigravity-cli)
the transition from Gemini CLI to Antigravity CLI, positioning
Antigravity as the primary agent-first development platform and coding
agent experience going forward. ([Google Developers
Blog](https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/?utm_source=chatgpt.com))
This PR updates:
> "such as Gemini, Claude, Cursor or Copilot"
to:
> "such as Antigravity, Claude Code, Cursor, or Copilot"
The updated wording aligns the README with current product naming and
makes the examples more consistent by referencing agent/tool products
instead of model families.
Co-authored-by: Nicholas Roscino <nroscino@google.com>
Update the tools to all include the `heapsnapshot` term for easier
handling.
Renames UID to ID to reduce confusion with the snapshot UIDs.
Renames Id to NodeId to better differentiate from the base Id.
Remove EdgeIndex as it was not useful.
Closes:
https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1970
## Summary
- Add a README section explaining how to configure concurrent MCP
sessions
- Document when to use `--experimentalPageIdRouting` for shared server
instances
- Point independent sessions at `--isolated` to avoid sharing the
default user data directory
Refs #2052
## Testing
- `npm run check-format`
Enables "third-party developer tools" feature. This allows the inspected
web page to expose tools which provide debugging information to Chrome
DevTools for Agents.
Third-party developer tools enable web applications to expose internal
state, component hierarchies, or specific debug data that cannot be
deduced through static analysis. This allows Chrome DevTools for Agents
to provide richer, more actionable context to AI agents during debugging
sessions.
2 additional tools are enabled in Chrome DevTools for Agents for
interacting with third-party developer tools:
`list_3p_developer_tools()` and `execute_3p_developer_tool`.
Code changes in this PR:
- Rename "in-page tools" to "third-party developer tools"
- Unhide
- Make available in CLI
- Add documentation
Extracting WebMCP tools into a separate category for better grouping in
the docs. This changes `--experimentalWebmcp` to
`--categoryExperimentalWebmcp` to align with other experimental
categories. Debugging category was not a good fit since the tools
provided by WebMCP are not necessarily used for debugging.
cc @beaufortfrancois
This refactors the code to extract the Id logic from the PageCollector
and provide it in the heapsnapshot.
We need to use an UID as we need the internal ClassKey to query the
heapsnapshot, but that is a strange string (usually looking like
`,ClassName`) which may get the LLM confused as we use comma separated
output.
This is the second most highly touched metric areas - so let's automate
this portion first. The approach is similar to what we have for tool
call args. The append-only logic will be added in the follow-up PR:
#1882
This PR adds a CLI flag to enable redacting network headers in the same
way they are redacted in DevTools. Note that sometimes it might prevent
the agent from properly analysing network issues. Pass
`--redact-headers=false` to revert to the previous behavior.
## Summary
This PR fixes several documentation and skill-reference issues across
the repo to improve accuracy and reduce confusion in implementation and
troubleshooting workflows.
## Changes
- corrected CLI examples in skill docs
- fixed the documented argument order for `performance_analyze_insight`
- updated the memory leak fallback script path
- corrected generated tool reference wording by updating the
source-of-truth tool descriptions
---------
Co-authored-by: ojonesjr <50652264+ojonesjr@users.noreply.github.com>
Both `chrome-devtools` and `chrome-devtools-mcp` now log a notification
when a newer version is detected to be available.
This detection is implemented as follows:
1. Read the latest version from a local 24-hour cache
(`~/.cache/chrome-devtools-mcp/latest.json`).
2. If the cache is stale or missing, spawn a detached background process
to fetch the latest version from the npm registry and update the cache
file.
Specify `--experimental-vision` argument for `chrome-devtools-mcp` to
enable additional tools for vision models. Currently, only
`click_at(x,y)` tool is supported. Usually you need a specialized model
that can provide accurate coordinates based on the screenshots.
Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/403
## Summary
When installing `chrome-devtools-mcp` as a Claude Code plugin (from the
official Anthropic marketplace or via `/plugin marketplace add`), the
plugin system clones the repository using HTTPS
(`https://github.com/ChromeDevTools/chrome-devtools-mcp.git`). In
environments where outbound HTTPS connectivity to GitHub is restricted —
such as servers behind corporate firewalls, restrictive proxy
configurations, or hosts with port 443 blocked — this clone operation
fails with a timeout:
```
chrome-devtools-mcp@claude-plugins-official: Failed to download/cache plugin chrome-devtools-mcp:
Failed to clone repository: Cloning into '...'...
fatal: unable to access 'https://github.com/ChromeDevTools/chrome-devtools-mcp.git/':
Failed to connect to github.com port 443 after 136078 ms: Couldn't connect to server
```
This is a real-world scenario encountered on production Linux servers
where SSH to GitHub (port 22) works but HTTPS (port 443) is blocked or
unreliable. The Claude Code plugin marketplace
(`anthropics/claude-plugins-official`) specifies the HTTPS URL as the
plugin source, and users have no way to override this URL within the
plugin system itself.
## Changes
### `docs/troubleshooting.md`
Added a new troubleshooting section **Claude Code plugin installation
fails with `Failed to clone repository`** under Specific problems that
documents:
- **The exact error message** users encounter, making it searchable
- **Root cause explanation**: restricted HTTPS connectivity, firewalls,
proxy configs
- **Workaround 1 — SSH redirect**: Using `git config --global
url."git@github.com:".insteadOf "https://github.com/"` to transparently
redirect all GitHub HTTPS git operations to use SSH
- **Workaround 2 — CLI installation**: Using `claude mcp add
chrome-devtools --scope user npx chrome-devtools-mcp@latest` to install
the MCP server via npm/npx instead of git clone
### `README.md`
Added a `[!TIP]` callout in the Claude Code **Install as a Plugin**
section that cross-references the troubleshooting guide.
## Motivation
The HTTPS clone URL for this plugin is defined in the Anthropic official
plugin marketplace, not in this repository. Since users cannot change
the marketplace URL configuration, the most actionable fix from this
repository's side is to document the issue and provide clear
workarounds.
## Test plan
- [x] `npm run check-format` passes (eslint + prettier)
- [x] `npm run gen` produces no unexpected diff (auto-generated docs
unchanged)
- [x] Documentation-only change — no code, tool, or schema modifications
- [x] Markdown anchor link in README TIP callout correctly references
the troubleshooting section heading
- [x] Both workaround commands verified in the environment where this
issue was encountered
Fix#1139
Powershell uses different rules regarding escaping quotes, so default
installation command doesn't work there. This PR adds version of the
command reporter of the issue confirms is working.
Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org>