## Summary
Adds storage-isolated browser contexts via an optional `isolatedContext`
parameter on the `new_page` tool, following the simplified design
proposed by @OrKoN in #926.
Pages created with the same `isolatedContext` name share cookies,
localStorage, and storage. Pages in different isolated contexts (or the
default context) are fully isolated — ideal for testing multi-user
real-time features like chat, notifications, or collaborative editing.
## Changes
### `new_page` tool
- New optional `isolatedContext: string` parameter
- If specified, creates/reuses a named `BrowserContext` and opens a page
in it
- If omitted, uses the default browser context (existing behavior
unchanged)
### `McpContext`
- `#isolatedContexts` Map: LLM-provided names → Puppeteer
`BrowserContext` instances
- `#pageToIsolatedContextName` WeakMap: GC-safe page → context name
reverse lookup
- Auto-discovery: externally created browser contexts get
`isolated-context-1`, `isolated-context-2`, etc.
- `getIsolatedContextName(page)`: returns the isolated context name for
a page (used by response formatting)
- `page.browserContext()` used for context membership detection (no
custom target event forwarding needed)
- No context cleanup in `dispose()` or `closePage()` — either the entire
browser is closed or we disconnect without destroying state
### `McpResponse`
- Page list includes `isolatedContext=${name}` labels (both text and
structured JSON output)
### `ToolDefinition`
- `Context` interface extended with `getIsolatedContextName(page)`
method
## What's NOT included (by design)
- **No `TargetEventEmitter`**: Puppeteer forwards target events from
`BrowserContext` → `Browser` internally
- **No context cleanup**: Browser contexts are not closed on `dispose()`
or page close, per maintainer guidance
- **No `about:blank` cleanup**: Default context and isolated contexts
coexist side-by-side
## Example
```
> new_page url="https://app.example.com/chat" isolatedContext="userA"
> new_page url="https://app.example.com/chat" isolatedContext="userB"
> list_pages
Page 1: [app.example.com/chat] isolatedContext=userA
Page 2: [app.example.com/chat] isolatedContext=userB [selected]
```
Pages in different isolated contexts have fully independent cookies,
localStorage, IndexedDB, and WebSocket connections.
## Tests
- 6 new tests covering `isolatedContext` feature in
`tests/tools/pages.test.ts`
- All existing tests pass (333+)
- Zero type errors, lint clean
Closes#926
---------
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
## Summary
Adds `screencast_start` and `screencast_stop` MCP tools that allow
agents to record a video of a page using Puppeteer's `page.screencast()`
API.
Only enabled if the command line option `--experimental-screencast` is
provided
Closes#878.
## New Tools
### `screencast_start`
Starts recording a screencast (video) of the selected page in mp4
format.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `path` | string (optional) | temp file | Output file path |
### `screencast_stop`
Stops the active recording and reports the saved file path.
## Design
- **Start/stop pair** following the `performance_start_trace` /
`performance_stop_trace` pattern
- **State management** via `getScreenRecorder()` / `setScreenRecorder()`
on the Context interface
- **Category**: `DEBUGGING` (alongside `take_screenshot`)
- **ffmpeg dependency**: Clear error message when ffmpeg is not
installed
- **Temp file fallback**: When no `path` is provided, creates a temp
file with the correct extension
---------
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
LLM are trained to know the common status code so we can rely on that
when displaying the status code and fall back to text in case of errors
or pending reponse.
This PR wires up the default DevTools ignore listing to hide frames from
third party scripts in stack traces. By default, we ignore:
* Scripts with `/node_modules/` in their URL or where the URL starts
with `node:/`
* Scripts that are marked as ignore listed in the source map
* Content scripts from extensions
The PR adds both, unit tests and an e2e test. This is because we allow
the unit test to pass a mocked ignore checker, where-as the e2e uses the
real DevTools one.
This PR refactors the stack trace formatting logic a bit: We split the
`formatStackTrace` function into 2: One for the top-level stack trace
and the rest for the recursive ones. We also return lines separately so
we can slice the result later.
This PR implements formatting for `SymbolizedError` objects that are
part of "resolved arguments". A follow-up PR will handle the actual
conversion of `Error` remote objects to `SymbolizedError`s.
The "SymbolizedError" class represents a fully resolved error: The stack
trace is fully resolved and (in the future), the full `Error.cause`
chain is also fully resolved.
We'll use the `SymbolizedError` for both "uncaught exceptions" as well
as when logging `Error` objects to the console (e.g. `console.log(new
Error())`. This means the `resolvedArgs` array in `ConsoleFormatter`
will contain one `SymbolizedError` instance for every `Error` object
logged.
We upgrade the performance trace tools to include real-user experience
data from the Chrome User Experience Report (CrUX).
https://developer.chrome.com/docs/cruxhttps://developer.chrome.com/docs/crux/methodology
### Deets
* When a trace is stopped, the server now extracts the primary
navigation URLs from the trace (determined by insightSets).
* It calls the public CrUX API to fetch field metrics (LCP, INP, CLS)
for each unique URL/Origin.
* The formatting of crux data is handled by upstream TraceFormatter, but
it looks like this:
```md
Metrics (field / real users):
- LCP: 2595 ms (scope: url)
- LCP breakdown:
- TTFB: 1273 ms (scope: url)
- Load delay: 86 ms (scope: url)
- Load duration: 451 ms (scope: url)
- Render delay: 786 ms (scope: url)
- INP: 140 ms (scope: url)
- CLS: 0.06 (scope: url)
- The above data is from CrUX–Chrome User Experience Report. It's how the page performs for real users.
- The values shown above are the p75 measure of all real Chrome users
- The scope indicates if the data came from the entire origin, or a specific url
- Lab metrics describe how this specific page load performed, while field metrics are an aggregation of results from real-world users. Best practice is to prioritize metrics that are bad in field data. Lab metrics may be better or worse than fields metrics depending on the developer's machine, network, or the actions performed while tracing.
```
**Privacy Considerations:**
* Updates the server README to inform users that performance analysis tools may send trace URLs to the Google CrUX API.
* Adds a notification message to the server startup logs regarding the CrUX API interaction.
Doc: go/crux-in-bifrost
Fixes b/446630695
---------
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
Co-authored-by: Alex Rudenko <OrKoN@users.noreply.github.com>
Note that we replace the existing "pageerror" handler with our new
`UncaughtError` handler. The latter has a structured stack trace
attached which we can source map via DevTools.
This regresses the current functionality slightly, as we lose
"pageerror"s for workers and oopif.
## **Usage statistics**
Google collects usage statistics (such as tool invocation success rates,
latency, and environment information) to improve the reliability and
performance of Chrome DevTools MCP.
Data collection is **enabled by default**. You can opt-out by passing
the `--no-usage-statistics` flag when starting the server:
```json
"args": ["-y", "chrome-devtools-mcp@latest", "--no-usage-statistics"]
```
Google handles this data in accordance with the [Google Privacy
Policy](https://policies.google.com/privacy).
Google's collection of usage statistics for Chrome DevTools MCP is
independent from the Chrome browser's usage statistics. Opting out of
Chrome metrics does not automatically opt you out of this tool, and
vice-versa.
The code determining statistics that are collected is in here
https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/src/telemetry.
This PR completes the telemetry system by implementing the transport
layer for `ClearcutSender`. It enables actual HTTP communication with
the Clearcut backend, handling event batching, rate limiting, and
reliable delivery, including robust shutdown handling.
**Key Changes:**
* **HTTP Transport**: Implemented `fetch`-based transport sending `POST`
requests to the Clearcut HTTP server.
* **Event Batching**: Events are now buffered and flushed periodically
(default: 15 minutes) or on shutdown.
* **Reliability & Rate Limiting**:
* **Server-Side Backoff**: Respects `next_request_wait_millis` from
server responses to handle rate limiting dynamically.
* **Transient Error Retries**: Failed requests (5xx, 429) result in
events being requeued for the next flush.
* **Request Timeouts**: Enforced 30s timeout on requests to prevent
hanging processes.
* **Session Rotation**: Automatically rotates session IDs every 24
hours.
* **Safety & Stability**:
* **Buffer Overflow Protection**: Caps the buffer at 1000 events to
prevent memory leaks, dropping oldest events if necessary.
* **Optimistic Removal**: Prevents race conditions and duplicate events
during shutdown by optimistically removing events from the buffer before
sending.
* **Testing Improvements**:
* **E2E Robustness**: Updated E2E tests to use a mock web server instead
of relying on the logger to log specific lines.
**Implementation Roadmap:**
These changes finalize the planned telemetry architecture:
1. **CLI & Opt-out Mechanism
([Merged](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/757))**
2. **Logger Scaffolding & Integration
([Merged](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/758))**
3. **Persistence Layer
([Merged](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/766))**
4. **Watchdog Process Architecture
([Merged](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/769))**
5. **Transport, Batching & Retries (This PR):**
* Finalized `ClearcutSender` with HTTP transport, batching, and
server-directed backoff strategies.
---------
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
## Summary
- Add `background` boolean parameter to the `new_page` tool
- When set to `true`, the new page opens in the background without
bringing it to the front
- Uses Puppeteer's existing `background` option for `browser.newPage()`
Fixes#826
---------
Co-authored-by: Alex Rudenko <OrKoN@users.noreply.github.com>
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
previously, Chrome DevTools MCP was strictly requiring the client to use
the latest snapshot. This change updates the behavior to be more
lenient. Previously issued uids will be recognized if the underlying
backend Id (loaderId + backendNodeId) still exists.
Related https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/726