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>
This PR adds an experimental allowlist for the page navigate tool call
(requires `--experimentalNavigationAllowlist`, off by default). The
feature uses a list of URLPatterns to decline navigations that land on
disallowed URLs. If that happens, the client can update the allowlist
and re-try. The purpose of the this feature is to offer additional
guardrails on top of the MCP server. It does not restrict subresources
or JS/iframe navigations in any way. The performance impact is minimized
by turning off interception as soon as the navigation request is done.
Previously, we would show the notification if the local version string
was *different* from the latest version string published to npm.
With this patch, we actually check if the npm-published version is newer
and avoid showing the notification otherwise.
Closes#1886
DOM elements are non-serializable and therefore cannot be directly sent
between the inspected page and the MCP server. JSONSchema also has no
native type for DOM elements.
If an in-page tool expects a DOM element as an input parameter, it
should specify this in its input schema by adding `'x-mcp-type':
'HTMLElement'` to the object it expects to be a DOM element.
The MCP server internally refers to DOM elements by a UID (UIDs are
assigned when generating a page snapshot which is based on the page's
accessibility tree).
This change provides the mapping between DOM element and UID in both
directions:
1) The tool's input schema is rewritten internally, adding a required
UID attribute to objects with `'x-mcp-type': 'HTMLElement'`. This allows
the MCP server to call the in-page tool with UIDs where the tool expects
DOM elements.
2) In the page context, the UIDs are replaced with the corresponding DOM
elements, before the actual in-page tool is called. This means that the
in-page tool receives DOM elements as parameters where it expects them.
This allows the MCP server to call the in-page tools provided by the
inspected page.
Handling of (non-serializable) DOM elements as tool parameters or tool
output will be added in follow-ups.
This adds functions to sanitize the tool call parameters. They are not
called as of now since we don't have server side changes landed yet to
support these.
This adds a `list_in_page_tools` MCP tool. When called, it dispatches a
`devtoolstooldiscovery` event on the active page. The page announces its
exposing tools by calling the event's `respondWith` method, which causes
the exposed tools to be stashed on the page's `window` object. This list
of in-page tools is then appended to the `list_in_page_tools` response.
Calling the exposed in-page tools from the MCP server will be handled in
a follow-up.
Implements a daemon process needed for the CLI. The daemon has commands
to start/stop itself as well as an ability to forward data to the
managed MCP server. Local sockets or named pipes are used depending on
the platform.
The .sock and .pid files are placed under
XDG_RUNTIME_DIR/chrome-devtools-mcp or /tmp/chrome-devtools-mcp for
short socket paths.
It uses Puppeteer's PipeTransport to avoid re-implementing \0 terminated
messages.
Note the code is not used anywhere at the moment.
This is the stack trace of the console message itself. If the argument
is an Error object or an "Error.stack" like string we don't do anything
special (yet).
The stack trace is source mapped if source maps are available.
The function matches the target ID of the console message to the
`SDK.Target` of DevTools. The only oddity is that DevTools works in a
lazy manor: It creates stack traces upfront and as source maps come in,
stack traces get updated. This does not work for the MCP server.
Instead, we wait for script parsed events and source maps to attach
before creating the stack trace. Since this could take potentially a
while, we guard it with a time out.
build/src/third_party/devtools.js is only used during bundling, but we
publish it unnecessarily. We should remove it to not cause confusion and
slightly decrease package size.
Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org>
The `devtools-formatter-worker` is a separate entrypoint from the MCP
entrypoint. It is identical to the upstream
`front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.js`
and a required part to make source mapping, formatting and other
AST-based DevTools features work.
The implementation consists of 3 parts:
1) A trivial `devtools-formatter-worker.ts` file that imports the
DevTools entrypoint.
2) A new bundle output, bundling everything that needs to run in the
worker.
3) A call that initializes the `FormatterWorkerPool` with the custom
entrypoint. Otherwise we'd use the unbundled entrypoint from
`chrome-devtools-frontend` not available to us at runtime.
Note that we could improve code splitting in the future as some things
like `core/common` are now bundled twice.
---------
Co-authored-by: Alex Rudenko <OrKoN@users.noreply.github.com>
This PR integrates `--user-data-dir` with the `--auto-connect` feature.
If `--user-data-dir` is provided as well `--auto-connect`, the specified
dir is used to locate a running browser server.
This PR prevents license notices being dropped when creating package for
publication.
This can happen when first import in the file is type-only import that
gets removed during build. When there is no empty line between the
license block comment and such import, the comment is treated as related
to the import and gets removed alongside it.
Adding an empty line between copyright notice and the import fixes the
issue.
Co-authored-by: Piotr Paulski <piotrpaulski@chromium.org>
Rather then adapting on the transport layer, we adapt the puppeteer
`CDPSession`/`Connection` and make them look like a `CDPConnection`. The
class assumes that callers create a dedicated `CDPSession` to be used.
The `PuppeteerDevToolsConnection` installs a generic `'*'` event
listener on all child sessions to funnel all CDP events into DevTools
via `CDPConnectionObservers`. As pointed out in the code comment, we
don't need to recursively listen to `'sessionattached'` events on child
sessions: Nested `sessionattached` events are reported on all parent
sessions.
While not strictly necessary, `PuppeteerDevToolsConnection` also
uninstalls the CDP event listener when a session gets detached (modulo
the root puppeteer `CDPSession`).
The CI jobs will still bundle by default but I think the risk of the
differences between the bundled and unbundled version is fairly low for
local development.