Files
Johan Gorter 0877ee00d2 feat: add logpoints built on the DevTools BreakpointManager (#3211)
Implements #2584 (logpoints) on top of the devtools-frontend logpoint
code, as requested in
https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2584#issuecomment-6169778436.

## What

One tool, `set_logpoints`, in the `debugging` category
(`--category-debugging` turns it off together with the other debugging
tools). It takes the complete set of logpoints for the selected page as
strings formatted `<url>:<lineNumber>[:<columnNumber>] <expression>`:

- logpoints not in the list are removed, new ones are added, and the
expression of a logpoint at an existing location is replaced; an empty
list removes all logpoints;
- `url` is the URL of a script as served to the browser or the path of
an original source file from a source map, matched exactly or as a path
suffix (e.g. `src/app.ts`);
- `expression` is formatted like `console.log()` arguments and evaluated
in the scope of the location (original variable names work at
source-mapped locations);
- the response lists the resulting logpoints with the generated
locations they are bound to. When a location has no executable code, the
other logpoints are still applied and the response lists them before the
error.

Output arrives as ordinary console messages via `list_console_messages`.
A logpoint on a line that runs during initial script evaluation can miss
executions that happen before the source map is fetched after a rebuild;
the tool response and the skill note say so.

## How

A logpoint is a DevTools breakpoint with `isLogpoint = true`, created
through `BreakpointManager.setBreakpoint()` on the `BreakpointManager`
that the DevTools `Universe` of the page constructs
(`universe.breakpointManager`). The breakpoint manager builds the
backend condition, resolves original source positions through
`DebuggerWorkspaceBinding`, substitutes minified variable names,
normalizes locations (a generated location maps to its original source
line) and re-binds the breakpoint when scripts and source maps re-attach
after reloads and rebuilt bundles. No CDP breakpoint calls are made
directly.

`src/LogpointManager.ts` is the adapter: it maps `url` onto a workspace
`UISourceCode` (loading source maps on demand, since the universe loads
them lazily), calls `setBreakpoint()`, and keeps the resulting
`Breakpoint` objects; two requested locations that normalize to the same
breakpoint share one entry. While logpoints exist, the lazy source-map
setting of the universe is switched off so that the original sources of
a rebuilt bundle re-appear and the breakpoint can re-bind.

`BreakpointManager` and `Workspace` come from the `mcp.ts` entrypoint
(devtools-frontend CLs 8608769 and 8616700, both in the pinned
submodule). `src/formatters/LogpointFormatter.ts` renders the result
(`toJSON()` / `toString()`). `src/tools/toolNames.ts` holds the
`list_console_messages` name that the tool description references.

## Limitations

- Original-source locations need source maps (`--no-source-maps` turns
them off).
- Only scripts of the page's main frame are supported; scripts in
workers and out-of-process iframes do not match.
- A line without executable code slides to the next valid location, as
in DevTools; an original source line with no mapping is reported as an
error.

## Tests

- `tests/LogpointManager.test.ts`: real-browser scenarios (logging
without pausing, path-suffix matching, reloads; replace/remove/clear;
source-mapped locations and re-binding after a rebuilt bundle; locations
that normalize to the same breakpoint; unknown, ambiguous and
non-executable locations) plus unit tests for `parseLogpoint` and
`validateExpression`.
- `tests/tools/logpoints.test.ts`: mock-based handler tests.
- `tests/formatters/LogpointFormatter.test.ts`: snapshot tests.
- `tests/McpPage.test.ts`: `setLogpoints()` with an empty list, manager
reuse, and `dispose()`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-11-04 08:16:15 +00:00
..
2025-09-11 12:46:05 +02:00