Closes #1004. Adds one opt-in tool, `configure_webauthn`, behind a new `--categoryWebauthn` flag (off by default), so agents can test passkey and security key flows with a virtual authenticator. It goes through the `WebAuthnModel` exported from devtools-frontend in https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/8606246, which is included in the current `third_party/devtools-frontend` roll. **Depends on** https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/8629668 (landed 2026-10-22, not rolled yet), which makes `WebAuthnModel` throw when a CDP command fails. Until that CL lands and is rolled into `third_party/devtools-frontend`, the model still ignores CDP errors, so the error and reset paths below only run in the unit tests. This PR should land after that roll. ### Shape One authenticator per page, all params top-level primitives so the tool also works from the CLI (reworked from an `authenticators: [...]` list during review): ``` configure_webauthn({ enabled, // false disables the virtual authenticator environment for the page; other params are ignored protocol?, // 'ctap2' | 'u2f', default ctap2 transport?, // 'internal' | 'usb' | 'nfc' | 'ble' | 'hybrid', default internal hasResidentKey?, // default true; false for u2f hasUserVerification?, // default true; false for u2f isUserVerified?, // default true; false tests a failed verification }) ``` - On a later call, omitted params keep the current values. - Changing only `isUserVerified` updates the authenticator in place, so passkeys the page registered survive (e.g. register, then make verification fail and check that sign-in is rejected). - Changing `protocol`, `transport`, `hasResidentKey` or `hasUserVerification` replaces the authenticator, since CDP can't change those on an existing one. - `enabled: false` always disables the environment for the whole page, which also removes authenticators other clients (such as the DevTools WebAuthn panel) added. - u2f supports neither resident keys nor user verification, so both are `false` for u2f, also when a later call switches from ctap2 with them omitted. An explicit `true` with u2f is rejected before any CDP call. - The tool description asks the agent to call it before the page calls `navigator.credentials`: a request made without a virtual authenticator stays pending, and later requests fail with `OperationError: A request is already pending` until the page navigates. - When a CDP command fails, the tool throws `Failed to configure WebAuthn for page <id>: <CDP message>`, drops its stored authenticator, removes it from the browser on a best-effort basis, and marks the environment as disabled, so the next call starts from scratch instead of reusing a stale authenticator id. - The response shows the authenticator and its stored credentials (`credentialId` as base64url without padding, matching `PublicKeyCredential.id`, `rpId`, `discoverable`, `signCount`, `userName`), formatted by `WebAuthnFormatter` and included in structured content. Private keys are never printed. - Page listings (`list_pages` and the other tools that print the page list) show `webauthn=<protocol>/<transport>` for pages that have one (`webauthn` in structured content). - The authenticator is scoped to the page and goes away when it closes. The tool uses `concurrency: 'page'`. - Importing credentials with a known private key is left out for now; it could come back as a follow-up. ### Testing - `tests/McpPage.test.ts`: `configureWebAuthn()` against a mocked `WebAuthnModel`: create with defaults, update `isUserVerified` in place and keep omitted options, replace on a creation option change, disable (also when another client enabled the environment), list stored credentials, u2f with both options false after a ctap2 authenticator, an explicit `true` with u2f rejected without a CDP call, no model, and a failing call for each CDP command (enable, add, remove, disable, `setUserVerified`, `getCredentials`), including that the next call creates a new authenticator. - `tests/tools/webauthn.test.ts`: the handler passes params through and attaches the result, plus the only real-browser run: register and sign in through (the response lists the ID the page got) `navigator.credentials.create()` / `get()`, the `list_pages` label, a rejected sign-in after `isUserVerified: false`, the passkey gone after a `transport` change, and disabling. - `tests/formatters/WebAuthnFormatter.test.ts`: snapshot tests for `toString` / `toJSON`, and a test that credential IDs print as base64url. - `McpPage`, `webauthn` and `WebAuthnFormatter` test files pass locally; `npm run gen`, eslint and prettier produce no further changes.
19 KiB
Configuration
The Chrome DevTools MCP server supports the following configuration option:
-
--categoryInput/--category-inputSet to false to exclude tools related to input.- Type: boolean
- Default:
true
-
--categoryNavigation/--category-navigationSet to false to exclude tools related to navigation.- Type: boolean
- Default:
true
-
--categoryEmulation/--category-emulationSet to false to exclude tools related to emulation.- Type: boolean
- Default:
true
-
--categoryPerformance/--category-performanceSet to false to exclude tools related to performance.- Type: boolean
- Default:
true
-
--categoryNetwork/--category-networkSet to false to exclude tools related to network.- Type: boolean
- Default:
true
-
--categoryDebugging/--category-debuggingSet to false to exclude tools related to debugging.- Type: boolean
- Default:
true
-
--categoryExtensions/--category-extensionsSet to true to include tools related to extensions.- Type: boolean
- Default:
false
-
--categoryExperimentalThirdParty/--category-experimental-third-partySet to true to enable third-party developer tools exposed by the inspected page itself (via WebMCP or devtoolstooldiscovery)- Type: boolean
- Default:
false
-
--categoryMemory/--category-memorySet to false to exclude tools related to memory.- Type: boolean
- Default:
true
-
--categoryExperimentalWebmcp/--category-experimental-webmcpSet to true to enable WebMCP tools (excluding debugging tools, which are exposed under the third-party developer tools category). Requires Chrome 150+ with the following flag:--enable-features=WebMCP- Type: boolean
- Default:
false
-
--categoryPwa/--category-pwaSet to true to include tools for automating Progressive Web Apps (install, launch, uninstall, and OS state). This feature is only supported with a pipe connection; autoConnect, browserUrl, and wsEndpoint are not supported.- Type: boolean
- Default:
false
-
--categoryWebauthn/--category-webauthnSet to true to include a tool that manages virtual WebAuthn authenticators, for testing passkey and security key flows.- Type: boolean
- Default:
false
-
--autoConnect/--auto-connectIf specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remote debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.- Type: boolean
- Default:
false
-
--browserUrl/--browser-url,-uConnect to a running, debuggable Chrome instance (e.g.http://127.0.0.1:9222). For more details see: https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/advanced-usage.md#connecting-to-a-running-chrome-instance.- Type: string
-
--wsEndpoint/--ws-endpoint,-wWebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/). Alternative to --browserUrl.- Type: string
-
--wsHeaders/--ws-headersCustom headers for WebSocket connection in JSON format (e.g., '{"Authorization":"Bearer token"}'). Only works with --wsEndpoint.- Type: string
-
--headlessWhether to run in headless (no UI) mode.- Type: boolean
- Default:
false
-
--executablePath/--executable-path,-ePath to custom Chrome executable.- Type: string
-
--isolatedIf specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to false.- Type: boolean
- Default:
false
-
--userDataDir/--user-data-dirPath to the user data directory for Chrome. Default is $HOME/.cache/chrome-devtools-mcp/chrome-profile$CHANNEL_SUFFIX_IF_NON_STABLE- Type: string
-
--channelSpecify a different Chrome channel that should be used. The default is the stable channel version.- Type: string
- Choices:
canary,dev,beta,stable - Default:
stable
-
--proxyServer/--proxy-serverProxy server configuration for Chrome passed as --proxy-server when launching the browser. See https://www.chromium.org/developers/design-documents/network-settings/ for details.- Type: string
-
--chromeArg/--chrome-argAdditional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.- Type: array
-
--ignoreDefaultChromeArg/--ignore-default-chrome-argExplicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.- Type: array
-
--viewportInitial viewport size for the Chrome instances started by the server. For example,1280x720. In headless mode, max size is 3840x2160px.- Type: string
-
--acceptInsecureCerts/--accept-insecure-certsIf enabled, ignores errors relative to self-signed and expired certificates. Use with caution.- Type: boolean
- Default:
false
-
--blockedUrlPattern/--blocked-url-patternRestricts browser's network access by blocking specified URL patterns (uses https://urlpattern.spec.whatwg.org/). Silently detaches from targets with blocked URLs upon connection, and blocks runtime requests (including navigations and subresources); targets already open when patterns are updated via --watchConfig remain attached. Accepts an array of patterns. A pattern that uses a regexp group, a named group (:name), or a partial IPv4 wildcard (for example(127\.\d+\.\d+\.\d+),*://127.0.0.1::port/*, or*://127.0.0.*/*) is rejected, because it is not enforced on redirects or subresources; use an exact value or a*wildcard instead. Patterns follow URL Pattern defaults: an omitted port matches only the scheme's default port (for example,https://internal.corp/*does not matchhttps://internal.corp:8443/; usehttps://internal.corp:*/*to match any port), and the hostname must match exactly (a trailing-dot host such asinternal.corp.is a different hostname).- Type: array
-
--allowedUrlPattern/--allowed-url-patternRestricts browser's network access by allowing only specified URL patterns (uses https://urlpattern.spec.whatwg.org/). Requires Chrome 149+. Silently detaches from targets with unallowed URLs upon connection, and blocks runtime requests (including navigations and subresources); targets already open when patterns are updated via --watchConfig remain attached. Accepts an array of patterns. A pattern that uses a regexp group, a named group (:name), or a partial IPv4 wildcard (for example(127\.\d+\.\d+\.\d+),*://127.0.0.1::port/*, or*://127.0.0.*/*) is rejected, because it is not enforced on redirects or subresources; use an exact value or a*wildcard instead. Patterns follow URL Pattern defaults: an omitted port matches only the scheme's default port (for example,https://internal.corp/*does not matchhttps://internal.corp:8443/; usehttps://internal.corp:*/*to match any port), and the hostname must match exactly (a trailing-dot host such asinternal.corp.is a different hostname).- Type: array
-
--screenshotFormat/--screenshot-formatOverride the default output format used by take_screenshot when the caller does not specify one. JPEG and WebP are ~3-5x smaller than PNG, which reduces transfer and storage size. To reduce context size use --screenshotMaxWidth / --screenshotMaxHeight, since image tokens scale with dimensions rather than encoded bytes. Unset preserves the existing default ("png").- Type: string
- Choices:
jpeg,png,webp - Default:
png
-
--screenshotQuality/--screenshot-qualityOverride the default compression quality (0-100) used by take_screenshot for JPEG and WebP when the caller does not specify one. Lower values mean smaller files. Ignored for PNG. Unset preserves the Puppeteer default.- Type: number
-
--screenshotMaxWidth/--screenshot-max-widthMaximum width in pixels for screenshots. If the captured image is wider, it is downscaled (preserving aspect ratio) before being returned. Reduces context size in AI conversations. Unset means no resize.- Type: number
-
--screenshotMaxHeight/--screenshot-max-heightMaximum height in pixels for screenshots. If the captured image is taller, it is downscaled (preserving aspect ratio) before being returned. Can be combined with --screenshot-max-width; the smaller scale factor wins. Unset means no resize.- Type: number
-
--logFile/--log-filePath to a file to write debug logs to. Set the env variableNODE_DEBUGto*to enable verbose logs. Useful for submitting bug reports.- Type: string
-
--pageIdRouting/--page-id-routingRequire pageId on page-scoped tools and route requests by page ID (useful for concurrent agent sessions). Use --no-page-id-routing to disable.- Type: boolean
- Default:
true
-
--experimentalDevtools/--experimental-devtoolsWhether to enable automation over DevTools targets. This exposes the DevTools UI to input tools, including the Console, which can evaluate JavaScript in the inspected page. --no-javascript-evaluation does not restrict this path.- Type: boolean
- Default:
false
-
--experimentalVision/--experimental-visionWhether to enable coordinate-based tools such as click_at(x,y). Usually requires a computer-use model able to produce accurate coordinates by looking at screenshots.- Type: boolean
- Default:
false
-
--memoryDebugging/--memory-debugging,--experimentalMemoryWhether to enable memory debugging tools.- Type: boolean
- Default:
false
-
--experimentalStructuredContent/--experimental-structured-contentWhether to output structured formatted content.- Type: boolean
- Default:
false
-
--experimentalIncludeAllPages/--experimental-include-all-pagesWhether to include all kinds of pages such as webviews or background pages as pages.- Type: boolean
- Default:
false
-
--experimentalScreencast/--experimental-screencastUse the legacy ffmpeg-based screencast implementation instead of the built-in Chrome recorder. Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH. This option is deprecated and will be removed in favour of dependency-free screencast commands that are available by default.- Type: boolean
- Default:
false
-
--experimentalFfmpegPath/--experimental-ffmpeg-pathPath to ffmpeg executable for legacy screencast recording (requires --experimentalScreencast).- Type: string
-
--screencastFps/--screencast-fps,--experimentalScreencastFpsFrames per second to use for screencast recording. Lower values reduce file size and encoding load.- Type: number
-
--performanceCrux/--performance-cruxSet to false to disable sending URLs from performance traces to CrUX API to get field performance data.- Type: boolean
- Default:
true
-
--usageStatistics/--usage-statisticsSet to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled ifCHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICSorCIenv variables are set.- Type: boolean
- Default:
true
-
--javascriptEvaluation/--javascript-evaluationSet to false to disable the server entry points for evaluating caller-provided JavaScript: evaluation tools (evaluate_script and slim evaluate) are disabled, the initScript parameter in navigate_page is turned off, and navigating to javascript:, data:, or vbscript: URLs is disallowed. This is not a JavaScript sandbox: page scripts and JavaScript triggered through other permitted browser interactions (e.g. clicks or typing) still run. If --experimentalDevtools is also enabled, the DevTools UI, including the Console that evaluates code in the inspected page, can be automated and is not restricted by this option. The client remains responsible for validating tool calls and parameters.- Type: boolean
- Default:
true
-
--fileNavigations/--file-navigationsSet to false to disallow navigating to file: URLs. When disabled, new_page, navigate_page and the slim navigate tool reject file: URLs, including view-source: URLs that target them. This restricts navigations the server performs. It is not a filesystem sandbox: it does not affect pages the browser already had open when the server connected, and the browser can reach the filesystem by other means. Use OS sandboxing for full filesystem confinement.- Type: boolean
- Default:
true
-
--sourceMaps/--source-mapsWhether to enable source maps in DevTools. Use --no-source-maps to disable.- Type: boolean
- Default:
true
-
--maxNavigationSaved/--max-navigation-savedNumber of navigations (including the current one) for which network requests and console messages are retained per page. Must be between 1 and 25. For earlier navigations, request URLs, status codes, and request and response headers are retained, which is sufficient to trace redirect hops, but response bodies are generally no longer available.- Type: number
- Default:
3
-
--slimExposes a "slim" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.- Type: boolean
- Default:
false
-
--redactNetworkHeaders/--redact-network-headersIf true, redacts some of the network headers considered sensitive before returning to the client.- Type: boolean
- Default:
false
-
--allowUnrestrictedPaths/--allow-unrestricted-pathsIf set, disables the default path restriction that applies when the MCP client does not negotiate the roots capability. By default, tools that read or write local files are restricted to the OS temp directory when no roots are configured. Use this only when connecting a trusted local client that does not implement MCP roots and requires access to paths outside the temp directory.- Type: boolean
- Default:
false
-
--filesystemRoot/--filesystem-root,--workspaceA directory that filesystem tools are allowed to access. May be specified more than once.- Type: array
- Default:
OS temp directory
-
--configPath to JSON configuration file.- Type: string
-
--watchConfig/--watch-configWatch the config file for changes and apply them without restarting. Tools (except --categoryExtensions) are enabled, disabled and updated on the fly; options used to launch or connect to the browser still require a restart.- Type: boolean
- Default:
false
Pass them via the args property in the JSON configuration. For example:
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest",
"--channel=canary",
"--headless=true",
"--isolated=true"
]
}
}
}
Configuration file
Instead of passing flags, you can put the options in a JSON file. Keys use the camelCase option names:
{
"headless": true,
"channel": "canary",
"memoryDebugging": true,
"blockedUrlPattern": ["*://*.example.com/*"]
}
The server uses the first config file it finds in the following locations, from highest to lowest priority. Config files are not merged.
- The path passed via
--config. cd4a.config.jsonin the$PLUGIN_DATAdirectory, when running as an agent plugin.- The global config file:
- macOS and Linux:
$XDG_CONFIG_HOME/cd4a/config.json, falling back to~/.config/cd4a/config.json. - Windows:
%LOCALAPPDATA%/Google/cd4a/config.json, falling back to~/.config/cd4a/config.json.
- macOS and Linux:
Flags passed on the command line take precedence over the values in the config file.
Set the CHROME_DEVTOOLS_MCP_NO_CONFIG_DISCOVERY env variable to turn off the
search for config files, for example in tests. A config file passed via
--config is still used.
Applying changes without a restart
Pass --watchConfig to reload the config file whenever it changes. Watching is
off by default. On a change, the server re-reads the file, updates the list of
available tools, and notifies the MCP client with
notifications/tools/list_changed. If the new file is invalid, the server logs
the error to stderr and keeps the previous configuration.
Tool categories (except categoryExtensions), network URL restrictions
(blockedUrlPattern, allowedUrlPattern), and tool-specific options apply
immediately. When blockedUrlPattern or allowedUrlPattern is updated on the
fly, future requests and navigations are restricted, but targets already open on
a newly disallowed URL remain attached. Options that launch or connect to the
browser, such as headless, channel, viewport, or categoryExtensions,
only apply after restarting chrome-devtools-mcp. The server logs a message to
stderr when a change requires a restart.
Locking down the configuration file from agent access
Warning
Ensure that the configuration file and its parent directory are not writable by the agent.
The configuration file can set security-sensitive options such as
executablePath, chromeArg, allowedUrlPattern, blockedUrlPattern, etc.
If an agent can create or modify the configuration file in any of the
discovered locations (or at the path passed via --config), it can alter
these settings to bypass restrictions.
Connecting via WebSocket with custom headers
You can connect directly to a Chrome WebSocket endpoint and include custom headers (e.g., for authentication):
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest",
"--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/<id>",
"--wsHeaders={\"Authorization\":\"Bearer YOUR_TOKEN\"}"
]
}
}
}
To get the WebSocket endpoint from a running Chrome instance, visit http://127.0.0.1:9222/json/version and look for the webSocketDebuggerUrl field.
You can also run npx chrome-devtools-mcp@latest --help to see all available configuration options.