chrome-devtools-mcp 0.20.3 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -20
- package/build/src/HeapSnapshotManager.js +94 -0
- package/build/src/McpContext.js +26 -49
- package/build/src/McpPage.js +16 -0
- package/build/src/McpResponse.js +220 -12
- package/build/src/PageCollector.js +14 -28
- package/build/src/WaitForHelper.js +31 -0
- package/build/src/bin/check-latest-version.js +25 -0
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +28 -9
- package/build/src/bin/chrome-devtools-mcp-main.js +2 -0
- package/build/src/bin/chrome-devtools-mcp.js +1 -0
- package/build/src/bin/chrome-devtools.js +9 -3
- package/build/src/bin/cliDefinitions.js +15 -9
- package/build/src/daemon/client.js +1 -1
- package/build/src/daemon/daemon.js +2 -6
- package/build/src/daemon/utils.js +1 -0
- package/build/src/formatters/HeapSnapshotFormatter.js +38 -0
- package/build/src/formatters/NetworkFormatter.js +24 -7
- package/build/src/index.js +22 -1
- package/build/src/telemetry/ClearcutLogger.js +145 -6
- package/build/src/telemetry/flagUtils.js +46 -4
- package/build/src/telemetry/toolMetricsUtils.js +88 -0
- package/build/src/telemetry/types.js +5 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +4 -3
- package/build/src/third_party/THIRD_PARTY_NOTICES +1400 -483
- package/build/src/third_party/bundled-packages.json +6 -5
- package/build/src/third_party/devtools-formatter-worker.js +61 -66
- package/build/src/third_party/devtools-heap-snapshot-worker.js +9690 -0
- package/build/src/third_party/index.js +61622 -52803
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -0
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +10589 -4647
- package/build/src/tools/categories.js +5 -0
- package/build/src/tools/console.js +42 -39
- package/build/src/tools/emulation.js +1 -1
- package/build/src/tools/extensions.js +5 -11
- package/build/src/tools/inPage.js +105 -0
- package/build/src/tools/input.js +18 -16
- package/build/src/tools/lighthouse.js +3 -3
- package/build/src/tools/memory.js +50 -5
- package/build/src/tools/network.js +2 -2
- package/build/src/tools/pages.js +14 -6
- package/build/src/tools/performance.js +1 -1
- package/build/src/tools/screencast.js +2 -1
- package/build/src/tools/screenshot.js +3 -3
- package/build/src/tools/script.js +22 -16
- package/build/src/tools/tools.js +4 -0
- package/build/src/tools/webmcp.js +63 -0
- package/build/src/utils/check-for-updates.js +73 -0
- package/build/src/utils/files.js +4 -0
- package/build/src/utils/id.js +15 -0
- package/build/src/version.js +1 -1
- package/package.json +13 -9
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorNoCorpCrossOriginNoCorsRequest.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoCorpCossOriginNoCorsRequest.md +0 -3
- package/build/src/utils/ExtensionRegistry.js +0 -35
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
# Chrome DevTools
|
|
1
|
+
# Chrome DevTools for Agents
|
|
2
2
|
|
|
3
3
|
[](https://npmjs.org/package/chrome-devtools-mcp)
|
|
4
4
|
|
|
5
|
-
`chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot)
|
|
5
|
+
Chrome DevTools for Agents (`chrome-devtools-mcp`) lets your coding agent (such as Gemini, Claude, Cursor or Copilot)
|
|
6
6
|
control and inspect a live Chrome browser. It acts as a Model-Context-Protocol
|
|
7
7
|
(MCP) server, giving your AI coding assistant access to the full power of
|
|
8
8
|
Chrome DevTools for reliable automation, in-depth debugging, and performance analysis.
|
|
9
|
+
A [CLI](docs/cli.md) is also provided for use without MCP.
|
|
9
10
|
|
|
10
11
|
## [Tool reference](./docs/tool-reference.md) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design Principles](./docs/design-principles.md)
|
|
11
12
|
|
|
@@ -27,6 +28,10 @@ allowing them to inspect, debug, and modify any data in the browser or DevTools.
|
|
|
27
28
|
Avoid sharing sensitive or personal information that you don't want to share with
|
|
28
29
|
MCP clients.
|
|
29
30
|
|
|
31
|
+
`chrome-devtools-mcp` officially supports Google Chrome and [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) only.
|
|
32
|
+
Other Chromium-based browsers may work, but this is not guaranteed, and you may encounter unexpected behavior. Use at your own discretion.
|
|
33
|
+
We are committed to providing fixes and support for the latest version of [Extended Stable Chrome](https://chromiumdash.appspot.com/schedule).
|
|
34
|
+
|
|
30
35
|
Performance tools may send trace URLs to the Google CrUX API to fetch real-user
|
|
31
36
|
experience data. This helps provide a holistic performance picture by
|
|
32
37
|
presenting field data alongside lab data. This data is collected by the [Chrome
|
|
@@ -47,13 +52,18 @@ Google handles this data in accordance with the [Google Privacy Policy](https://
|
|
|
47
52
|
|
|
48
53
|
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.
|
|
49
54
|
|
|
50
|
-
Collection is disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.
|
|
55
|
+
Collection is disabled if `CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS` or `CI` env variables are set.
|
|
56
|
+
|
|
57
|
+
## Update checks
|
|
58
|
+
|
|
59
|
+
By default, the server periodically checks the npm registry for updates and logs a notification when a newer version is available.
|
|
60
|
+
You can disable these update checks by setting the `CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS` environment variable.
|
|
51
61
|
|
|
52
62
|
## Requirements
|
|
53
63
|
|
|
54
64
|
- [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version.
|
|
55
65
|
- [Chrome](https://www.google.com/chrome/) current stable version or newer.
|
|
56
|
-
- [npm](https://www.npmjs.com/)
|
|
66
|
+
- [npm](https://www.npmjs.com/)
|
|
57
67
|
|
|
58
68
|
## Getting started
|
|
59
69
|
|
|
@@ -70,7 +80,7 @@ Add the following config to your MCP client:
|
|
|
70
80
|
}
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
> [!NOTE]
|
|
83
|
+
> [!NOTE]
|
|
74
84
|
> Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server.
|
|
75
85
|
|
|
76
86
|
If you are interested in doing only basic browser tasks, use the `--slim` mode:
|
|
@@ -139,7 +149,7 @@ claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
|
|
|
139
149
|
|
|
140
150
|
**Install as a Plugin (MCP + Skills)**
|
|
141
151
|
|
|
142
|
-
> [!NOTE]
|
|
152
|
+
> [!NOTE]
|
|
143
153
|
> If you already had Chrome DevTools MCP installed previously for Claude Code, make sure to remove it first from your installation and configuration files.
|
|
144
154
|
|
|
145
155
|
To install Chrome DevTools MCP with skills, add the marketplace registry in Claude Code:
|
|
@@ -194,6 +204,17 @@ startup_timeout_ms = 20_000
|
|
|
194
204
|
|
|
195
205
|
</details>
|
|
196
206
|
|
|
207
|
+
<details>
|
|
208
|
+
<summary>Command Code</summary>
|
|
209
|
+
|
|
210
|
+
Use the Command Code CLI to add the Chrome DevTools MCP server (<a href="https://commandcode.ai/docs/mcp">MCP guide</a>):
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
cmd mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
</details>
|
|
217
|
+
|
|
197
218
|
<details>
|
|
198
219
|
<summary>Copilot CLI</summary>
|
|
199
220
|
|
|
@@ -220,6 +241,22 @@ Configure the following fields and press `CTRL+S` to save the configuration:
|
|
|
220
241
|
<details>
|
|
221
242
|
<summary>Copilot / VS Code</summary>
|
|
222
243
|
|
|
244
|
+
**Install as a Plugin (Recommended)**
|
|
245
|
+
|
|
246
|
+
The easiest way to get up and running is to install `chrome-devtools-mcp` as an agent plugin.
|
|
247
|
+
This bundles the **MCP server** and all **skills** together, so your agent gets both the tools
|
|
248
|
+
and the expert guidance it needs to use them effectively.
|
|
249
|
+
|
|
250
|
+
1. Open the **Command Palette** (`Cmd+Shift+P` on macOS or `Ctrl+Shift+P` on Windows/Linux).
|
|
251
|
+
2. Search for and run the **Chat: Install Plugin From Source** command.
|
|
252
|
+
3. Paste in our repository URL: `https://github.com/ChromeDevTools/chrome-devtools-mcp`
|
|
253
|
+
|
|
254
|
+
That's it! Your agent is now supercharged with Chrome DevTools capabilities.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
**Install as an MCP Server (MCP only)**
|
|
259
|
+
|
|
223
260
|
**Click the button to install:**
|
|
224
261
|
|
|
225
262
|
[<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF" alt="Install in VS Code">](https://vscode.dev/redirect/mcp/install?name=io.github.ChromeDevTools%2Fchrome-devtools-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22chrome-devtools-mcp%22%5D%2C%22env%22%3A%7B%7D%7D)
|
|
@@ -228,8 +265,7 @@ Configure the following fields and press `CTRL+S` to save the configuration:
|
|
|
228
265
|
|
|
229
266
|
**Or install manually:**
|
|
230
267
|
|
|
231
|
-
Follow the MCP
|
|
232
|
-
with the standard config from above. You can also install the Chrome DevTools MCP server using the VS Code CLI:
|
|
268
|
+
Follow the VS Code [MCP configuration guide](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server) using the standard config from above, or use the CLI:
|
|
233
269
|
|
|
234
270
|
For macOS and Linux:
|
|
235
271
|
|
|
@@ -338,6 +374,21 @@ Once connected, the Chrome DevTools MCP tools will be available in StudioAssist.
|
|
|
338
374
|
|
|
339
375
|
</details>
|
|
340
376
|
|
|
377
|
+
<details>
|
|
378
|
+
<summary>Mistral Vibe</summary>
|
|
379
|
+
|
|
380
|
+
Add in ~/.vibe/config.toml:
|
|
381
|
+
|
|
382
|
+
```toml
|
|
383
|
+
[[mcp_servers]]
|
|
384
|
+
name = "chrome-devtools"
|
|
385
|
+
transport = "stdio"
|
|
386
|
+
command = "npx"
|
|
387
|
+
args = ["chrome-devtools-mcp@latest"]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
</details>
|
|
391
|
+
|
|
341
392
|
<details>
|
|
342
393
|
<summary>OpenCode</summary>
|
|
343
394
|
|
|
@@ -387,10 +438,11 @@ qodercli mcp add -s user chrome-devtools -- npx chrome-devtools-mcp@latest
|
|
|
387
438
|
|
|
388
439
|
<details>
|
|
389
440
|
<summary>Visual Studio</summary>
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
441
|
+
|
|
442
|
+
**Click the button to install:**
|
|
443
|
+
|
|
444
|
+
[<img src="https://img.shields.io/badge/Visual_Studio-Install-C16FDE?logo=visualstudio&logoColor=white" alt="Install in Visual Studio">](https://vs-open.link/mcp-install?%7B%22name%22%3A%22chrome-devtools%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22chrome-devtools-mcp%40latest%22%5D%7D)
|
|
445
|
+
|
|
394
446
|
</details>
|
|
395
447
|
|
|
396
448
|
<details>
|
|
@@ -416,7 +468,7 @@ Check the performance of https://developers.chrome.com
|
|
|
416
468
|
|
|
417
469
|
Your MCP client should open the browser and record a performance trace.
|
|
418
470
|
|
|
419
|
-
> [!NOTE]
|
|
471
|
+
> [!NOTE]
|
|
420
472
|
> The MCP server will start the browser automatically once the MCP client uses a tool that requires a running browser instance. Connecting to the Chrome DevTools MCP server on its own will not automatically start the browser.
|
|
421
473
|
|
|
422
474
|
## Tools
|
|
@@ -445,11 +497,10 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
|
|
|
445
497
|
- **Emulation** (2 tools)
|
|
446
498
|
- [`emulate`](docs/tool-reference.md#emulate)
|
|
447
499
|
- [`resize_page`](docs/tool-reference.md#resize_page)
|
|
448
|
-
- **Performance** (
|
|
500
|
+
- **Performance** (3 tools)
|
|
449
501
|
- [`performance_analyze_insight`](docs/tool-reference.md#performance_analyze_insight)
|
|
450
502
|
- [`performance_start_trace`](docs/tool-reference.md#performance_start_trace)
|
|
451
503
|
- [`performance_stop_trace`](docs/tool-reference.md#performance_stop_trace)
|
|
452
|
-
- [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)
|
|
453
504
|
- **Network** (2 tools)
|
|
454
505
|
- [`get_network_request`](docs/tool-reference.md#get_network_request)
|
|
455
506
|
- [`list_network_requests`](docs/tool-reference.md#list_network_requests)
|
|
@@ -460,6 +511,14 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
|
|
|
460
511
|
- [`list_console_messages`](docs/tool-reference.md#list_console_messages)
|
|
461
512
|
- [`take_screenshot`](docs/tool-reference.md#take_screenshot)
|
|
462
513
|
- [`take_snapshot`](docs/tool-reference.md#take_snapshot)
|
|
514
|
+
- **Extensions** (5 tools)
|
|
515
|
+
- [`install_extension`](docs/tool-reference.md#install_extension)
|
|
516
|
+
- [`list_extensions`](docs/tool-reference.md#list_extensions)
|
|
517
|
+
- [`reload_extension`](docs/tool-reference.md#reload_extension)
|
|
518
|
+
- [`trigger_extension_action`](docs/tool-reference.md#trigger_extension_action)
|
|
519
|
+
- [`uninstall_extension`](docs/tool-reference.md#uninstall_extension)
|
|
520
|
+
- **Memory** (1 tools)
|
|
521
|
+
- [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)
|
|
463
522
|
|
|
464
523
|
<!-- END AUTO GENERATED TOOLS -->
|
|
465
524
|
|
|
@@ -470,7 +529,7 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
470
529
|
<!-- BEGIN AUTO GENERATED OPTIONS -->
|
|
471
530
|
|
|
472
531
|
- **`--autoConnect`/ `--auto-connect`**
|
|
473
|
-
If 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
|
|
532
|
+
If 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.
|
|
474
533
|
- **Type:** boolean
|
|
475
534
|
- **Default:** `false`
|
|
476
535
|
|
|
@@ -506,7 +565,7 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
506
565
|
- **`--channel`**
|
|
507
566
|
Specify a different Chrome channel that should be used. The default is the stable channel version.
|
|
508
567
|
- **Type:** string
|
|
509
|
-
- **Choices:** `
|
|
568
|
+
- **Choices:** `canary`, `dev`, `beta`, `stable`
|
|
510
569
|
|
|
511
570
|
- **`--logFile`/ `--log-file`**
|
|
512
571
|
Path to a file to write debug logs to. Set the env variable `DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports.
|
|
@@ -524,10 +583,18 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
524
583
|
If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.
|
|
525
584
|
- **Type:** boolean
|
|
526
585
|
|
|
586
|
+
- **`--experimentalVision`/ `--experimental-vision`**
|
|
587
|
+
Whether 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.
|
|
588
|
+
- **Type:** boolean
|
|
589
|
+
|
|
527
590
|
- **`--experimentalScreencast`/ `--experimental-screencast`**
|
|
528
591
|
Exposes experimental screencast tools (requires ffmpeg). Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH.
|
|
529
592
|
- **Type:** boolean
|
|
530
593
|
|
|
594
|
+
- **`--experimentalWebmcp`/ `--experimental-webmcp`**
|
|
595
|
+
Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=WebMCPTesting,DevToolsWebMCPSupport`
|
|
596
|
+
- **Type:** boolean
|
|
597
|
+
|
|
531
598
|
- **`--chromeArg`/ `--chrome-arg`**
|
|
532
599
|
Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
|
|
533
600
|
- **Type:** array
|
|
@@ -551,13 +618,18 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
551
618
|
- **Type:** boolean
|
|
552
619
|
- **Default:** `true`
|
|
553
620
|
|
|
621
|
+
- **`--categoryExtensions`/ `--category-extensions`**
|
|
622
|
+
Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.
|
|
623
|
+
- **Type:** boolean
|
|
624
|
+
- **Default:** `false`
|
|
625
|
+
|
|
554
626
|
- **`--performanceCrux`/ `--performance-crux`**
|
|
555
627
|
Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.
|
|
556
628
|
- **Type:** boolean
|
|
557
629
|
- **Default:** `true`
|
|
558
630
|
|
|
559
631
|
- **`--usageStatistics`/ `--usage-statistics`**
|
|
560
|
-
Set 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 if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.
|
|
632
|
+
Set 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 if `CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS` or `CI` env variables are set.
|
|
561
633
|
- **Type:** boolean
|
|
562
634
|
- **Default:** `true`
|
|
563
635
|
|
|
@@ -565,6 +637,11 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
565
637
|
Exposes a "slim" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.
|
|
566
638
|
- **Type:** boolean
|
|
567
639
|
|
|
640
|
+
- **`--redactNetworkHeaders`/ `--redact-network-headers`**
|
|
641
|
+
If true, redacts some of the network headers considered senstive before returning to the client.
|
|
642
|
+
- **Type:** boolean
|
|
643
|
+
- **Default:** `false`
|
|
644
|
+
|
|
568
645
|
<!-- END AUTO GENERATED OPTIONS -->
|
|
569
646
|
|
|
570
647
|
Pass them via the `args` property in the JSON configuration. For example:
|
|
@@ -671,7 +748,7 @@ Make sure your browser is running. Open gemini-cli and run the following prompt:
|
|
|
671
748
|
Check the performance of https://developers.chrome.com
|
|
672
749
|
```
|
|
673
750
|
|
|
674
|
-
> [!NOTE]
|
|
751
|
+
> [!NOTE]
|
|
675
752
|
> The <code>autoConnect</code> option requires the user to start Chrome. If the user has multiple active profiles, the MCP server will connect to the default profile (as determined by Chrome). The MCP server has access to all open windows for the selected profile.
|
|
676
753
|
|
|
677
754
|
The Chrome DevTools MCP server will try to connect to your running Chrome
|
|
@@ -707,7 +784,7 @@ Add the `--browser-url` option to your MCP client configuration. The value of th
|
|
|
707
784
|
|
|
708
785
|
**Step 2: Start the Chrome browser**
|
|
709
786
|
|
|
710
|
-
> [!WARNING]
|
|
787
|
+
> [!WARNING]
|
|
711
788
|
> Enabling the remote debugging port opens up a debugging port on the running browser instance. Any application on your machine can connect to this port and control the browser. Make sure that you are not browsing any sensitive websites while the debugging port is open.
|
|
712
789
|
|
|
713
790
|
Start the Chrome browser with the remote debugging port enabled. Make sure to close any running Chrome instances before starting a new one with the debugging port enabled. The port number you choose must be the same as the one you specified in the `--browser-url` option in your MCP client configuration.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import fsSync from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { DevTools } from './third_party/index.js';
|
|
9
|
+
import { createIdGenerator, stableIdSymbol, } from './utils/id.js';
|
|
10
|
+
export class HeapSnapshotManager {
|
|
11
|
+
#snapshots = new Map();
|
|
12
|
+
async getSnapshot(filePath) {
|
|
13
|
+
const absolutePath = path.resolve(filePath);
|
|
14
|
+
const cached = this.#snapshots.get(absolutePath);
|
|
15
|
+
if (cached) {
|
|
16
|
+
return cached.snapshot;
|
|
17
|
+
}
|
|
18
|
+
const { snapshot, worker } = await this.#loadSnapshot(absolutePath);
|
|
19
|
+
this.#snapshots.set(absolutePath, {
|
|
20
|
+
snapshot,
|
|
21
|
+
worker,
|
|
22
|
+
uidToClassKey: new Map(),
|
|
23
|
+
classKeyToUid: new Map(),
|
|
24
|
+
idGenerator: createIdGenerator(),
|
|
25
|
+
});
|
|
26
|
+
return snapshot;
|
|
27
|
+
}
|
|
28
|
+
async getAggregates(filePath) {
|
|
29
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
30
|
+
const filter = new DevTools.HeapSnapshotModel.HeapSnapshotModel.NodeFilter();
|
|
31
|
+
const aggregates = await snapshot.aggregatesWithFilter(filter);
|
|
32
|
+
for (const key of Object.keys(aggregates)) {
|
|
33
|
+
const uid = await this.getOrCreateUidForClassKey(filePath, key);
|
|
34
|
+
const aggregate = aggregates[key];
|
|
35
|
+
if (aggregate) {
|
|
36
|
+
aggregate[stableIdSymbol] = uid;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return aggregates;
|
|
40
|
+
}
|
|
41
|
+
async getStats(filePath) {
|
|
42
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
43
|
+
return await snapshot.getStatistics();
|
|
44
|
+
}
|
|
45
|
+
async getStaticData(filePath) {
|
|
46
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
47
|
+
return snapshot.staticData;
|
|
48
|
+
}
|
|
49
|
+
async getOrCreateUidForClassKey(filePath, classKey) {
|
|
50
|
+
const cached = this.#getCachedSnapshot(filePath);
|
|
51
|
+
let uid = cached.classKeyToUid.get(classKey);
|
|
52
|
+
if (!uid) {
|
|
53
|
+
uid = cached.idGenerator();
|
|
54
|
+
cached.classKeyToUid.set(classKey, uid);
|
|
55
|
+
cached.uidToClassKey.set(uid, classKey);
|
|
56
|
+
}
|
|
57
|
+
return uid;
|
|
58
|
+
}
|
|
59
|
+
#getCachedSnapshot(filePath) {
|
|
60
|
+
const absolutePath = path.resolve(filePath);
|
|
61
|
+
const cached = this.#snapshots.get(absolutePath);
|
|
62
|
+
if (!cached) {
|
|
63
|
+
throw new Error(`Snapshot not loaded for ${filePath}`);
|
|
64
|
+
}
|
|
65
|
+
return cached;
|
|
66
|
+
}
|
|
67
|
+
async #loadSnapshot(absolutePath) {
|
|
68
|
+
const workerProxy = new DevTools.HeapSnapshotModel.HeapSnapshotProxy.HeapSnapshotWorkerProxy(() => {
|
|
69
|
+
/* noop */
|
|
70
|
+
}, import.meta.resolve('./third_party/devtools-heap-snapshot-worker.js'));
|
|
71
|
+
const { promise: snapshotPromise, resolve: resolveSnapshot } = Promise.withResolvers();
|
|
72
|
+
const loaderProxy = workerProxy.createLoader(1, snapshotProxy => {
|
|
73
|
+
resolveSnapshot(snapshotProxy);
|
|
74
|
+
});
|
|
75
|
+
const fileStream = fsSync.createReadStream(absolutePath, {
|
|
76
|
+
encoding: 'utf-8',
|
|
77
|
+
highWaterMark: 1024 * 1024,
|
|
78
|
+
});
|
|
79
|
+
for await (const chunk of fileStream) {
|
|
80
|
+
await loaderProxy.write(chunk);
|
|
81
|
+
}
|
|
82
|
+
await loaderProxy.close();
|
|
83
|
+
const snapshot = await snapshotPromise;
|
|
84
|
+
return { snapshot, worker: workerProxy };
|
|
85
|
+
}
|
|
86
|
+
dispose(filePath) {
|
|
87
|
+
const absolutePath = path.resolve(filePath);
|
|
88
|
+
const cached = this.#snapshots.get(absolutePath);
|
|
89
|
+
if (cached) {
|
|
90
|
+
cached.worker.dispose();
|
|
91
|
+
this.#snapshots.delete(absolutePath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/build/src/McpContext.js
CHANGED
|
@@ -6,31 +6,17 @@
|
|
|
6
6
|
import fs from 'node:fs/promises';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { UniverseManager } from './DevtoolsUtils.js';
|
|
9
|
+
import { HeapSnapshotManager } from './HeapSnapshotManager.js';
|
|
9
10
|
import { McpPage } from './McpPage.js';
|
|
10
11
|
import { NetworkCollector, ConsoleCollector, } from './PageCollector.js';
|
|
11
12
|
import { Locator } from './third_party/index.js';
|
|
12
13
|
import { PredefinedNetworkConditions } from './third_party/index.js';
|
|
13
14
|
import { listPages } from './tools/pages.js';
|
|
14
15
|
import { CLOSE_PAGE_ERROR } from './tools/ToolDefinition.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { WaitForHelper } from './WaitForHelper.js';
|
|
16
|
+
import { ensureExtension, saveTemporaryFile } from './utils/files.js';
|
|
17
|
+
import { getNetworkMultiplierFromString } from './WaitForHelper.js';
|
|
18
18
|
const DEFAULT_TIMEOUT = 5_000;
|
|
19
19
|
const NAVIGATION_TIMEOUT = 10_000;
|
|
20
|
-
function getNetworkMultiplierFromString(condition) {
|
|
21
|
-
const puppeteerCondition = condition;
|
|
22
|
-
switch (puppeteerCondition) {
|
|
23
|
-
case 'Fast 4G':
|
|
24
|
-
return 1;
|
|
25
|
-
case 'Slow 4G':
|
|
26
|
-
return 2.5;
|
|
27
|
-
case 'Fast 3G':
|
|
28
|
-
return 5;
|
|
29
|
-
case 'Slow 3G':
|
|
30
|
-
return 10;
|
|
31
|
-
}
|
|
32
|
-
return 1;
|
|
33
|
-
}
|
|
34
20
|
export class McpContext {
|
|
35
21
|
browser;
|
|
36
22
|
logger;
|
|
@@ -45,7 +31,6 @@ export class McpContext {
|
|
|
45
31
|
#networkCollector;
|
|
46
32
|
#consoleCollector;
|
|
47
33
|
#devtoolsUniverseManager;
|
|
48
|
-
#extensionRegistry = new ExtensionRegistry();
|
|
49
34
|
#isRunningTrace = false;
|
|
50
35
|
#screenRecorderData = null;
|
|
51
36
|
#nextPageId = 1;
|
|
@@ -56,6 +41,7 @@ export class McpContext {
|
|
|
56
41
|
#traceResults = [];
|
|
57
42
|
#locatorClass;
|
|
58
43
|
#options;
|
|
44
|
+
#heapSnapshotManager = new HeapSnapshotManager();
|
|
59
45
|
constructor(browser, logger, options, locatorClass) {
|
|
60
46
|
this.browser = browser;
|
|
61
47
|
this.logger = logger;
|
|
@@ -70,7 +56,7 @@ export class McpContext {
|
|
|
70
56
|
uncaughtError: event => {
|
|
71
57
|
collect(event);
|
|
72
58
|
},
|
|
73
|
-
|
|
59
|
+
devtoolsAggregatedIssue: event => {
|
|
74
60
|
collect(event);
|
|
75
61
|
},
|
|
76
62
|
};
|
|
@@ -604,9 +590,9 @@ export class McpContext {
|
|
|
604
590
|
async saveTemporaryFile(data, filename) {
|
|
605
591
|
return await saveTemporaryFile(data, filename);
|
|
606
592
|
}
|
|
607
|
-
async saveFile(data,
|
|
593
|
+
async saveFile(data, clientProvidedFilePath, extension) {
|
|
608
594
|
try {
|
|
609
|
-
const filePath = path.resolve(
|
|
595
|
+
const filePath = ensureExtension(path.resolve(clientProvidedFilePath), extension);
|
|
610
596
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
611
597
|
await fs.writeFile(filePath, data);
|
|
612
598
|
return { filename: filePath };
|
|
@@ -624,16 +610,6 @@ export class McpContext {
|
|
|
624
610
|
recordedTraces() {
|
|
625
611
|
return this.#traceResults;
|
|
626
612
|
}
|
|
627
|
-
getWaitForHelper(page, cpuMultiplier, networkMultiplier) {
|
|
628
|
-
return new WaitForHelper(page, cpuMultiplier, networkMultiplier);
|
|
629
|
-
}
|
|
630
|
-
waitForEventsAfterAction(action, options) {
|
|
631
|
-
const page = this.#getSelectedMcpPage();
|
|
632
|
-
const cpuMultiplier = page.cpuThrottlingRate;
|
|
633
|
-
const networkMultiplier = getNetworkMultiplierFromString(page.networkConditions);
|
|
634
|
-
const waitForHelper = this.getWaitForHelper(page.pptrPage, cpuMultiplier, networkMultiplier);
|
|
635
|
-
return waitForHelper.waitForEventsAfterAction(action, options);
|
|
636
|
-
}
|
|
637
613
|
getNetworkRequestStableId(request) {
|
|
638
614
|
return this.#networkCollector.getIdForResource(request);
|
|
639
615
|
}
|
|
@@ -668,33 +644,34 @@ export class McpContext {
|
|
|
668
644
|
}
|
|
669
645
|
async installExtension(extensionPath) {
|
|
670
646
|
const id = await this.browser.installExtension(extensionPath);
|
|
671
|
-
await this.#extensionRegistry.registerExtension(id, extensionPath);
|
|
672
647
|
return id;
|
|
673
648
|
}
|
|
674
649
|
async uninstallExtension(id) {
|
|
675
650
|
await this.browser.uninstallExtension(id);
|
|
676
|
-
this.#extensionRegistry.remove(id);
|
|
677
651
|
}
|
|
678
652
|
async triggerExtensionAction(id) {
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const session = await this.browser.target().createCDPSession();
|
|
684
|
-
try {
|
|
685
|
-
await session.send('Extensions.triggerAction', {
|
|
686
|
-
id,
|
|
687
|
-
targetId: theTarget,
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
finally {
|
|
691
|
-
await session.detach();
|
|
653
|
+
const extensions = await this.browser.extensions();
|
|
654
|
+
const extension = extensions.get(id);
|
|
655
|
+
if (!extension) {
|
|
656
|
+
throw new Error(`Extension with ID ${id} not found.`);
|
|
692
657
|
}
|
|
658
|
+
const page = this.getSelectedPptrPage();
|
|
659
|
+
await extension.triggerAction(page);
|
|
693
660
|
}
|
|
694
661
|
listExtensions() {
|
|
695
|
-
return this
|
|
662
|
+
return this.browser.extensions();
|
|
663
|
+
}
|
|
664
|
+
async getExtension(id) {
|
|
665
|
+
const pptrExtensions = await this.browser.extensions();
|
|
666
|
+
return pptrExtensions.get(id);
|
|
667
|
+
}
|
|
668
|
+
async getHeapSnapshotAggregates(filePath) {
|
|
669
|
+
return await this.#heapSnapshotManager.getAggregates(filePath);
|
|
670
|
+
}
|
|
671
|
+
async getHeapSnapshotStats(filePath) {
|
|
672
|
+
return await this.#heapSnapshotManager.getStats(filePath);
|
|
696
673
|
}
|
|
697
|
-
|
|
698
|
-
return this.#
|
|
674
|
+
async getHeapSnapshotStaticData(filePath) {
|
|
675
|
+
return await this.#heapSnapshotManager.getStaticData(filePath);
|
|
699
676
|
}
|
|
700
677
|
}
|
package/build/src/McpPage.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { takeSnapshot } from './tools/snapshot.js';
|
|
7
|
+
import { getNetworkMultiplierFromString, WaitForHelper, } from './WaitForHelper.js';
|
|
7
8
|
/**
|
|
8
9
|
* Per-page state wrapper. Consolidates dialog, snapshot, emulation,
|
|
9
10
|
* and metadata that were previously scattered across Maps in McpContext.
|
|
@@ -26,6 +27,7 @@ export class McpPage {
|
|
|
26
27
|
// Dialog
|
|
27
28
|
#dialog;
|
|
28
29
|
#dialogHandler;
|
|
30
|
+
inPageTools;
|
|
29
31
|
constructor(page, id) {
|
|
30
32
|
this.pptrPage = page;
|
|
31
33
|
this.id = id;
|
|
@@ -43,6 +45,12 @@ export class McpPage {
|
|
|
43
45
|
clearDialog() {
|
|
44
46
|
this.#dialog = undefined;
|
|
45
47
|
}
|
|
48
|
+
getInPageTools() {
|
|
49
|
+
return this.inPageTools;
|
|
50
|
+
}
|
|
51
|
+
getWebMcpTools() {
|
|
52
|
+
return this.pptrPage.webmcp.tools();
|
|
53
|
+
}
|
|
46
54
|
get networkConditions() {
|
|
47
55
|
return this.emulationSettings.networkConditions ?? null;
|
|
48
56
|
}
|
|
@@ -61,6 +69,14 @@ export class McpPage {
|
|
|
61
69
|
get colorScheme() {
|
|
62
70
|
return this.emulationSettings.colorScheme ?? null;
|
|
63
71
|
}
|
|
72
|
+
// Public for testability: tests spy on this method to verify throttle multipliers.
|
|
73
|
+
createWaitForHelper(cpuMultiplier, networkMultiplier) {
|
|
74
|
+
return new WaitForHelper(this.pptrPage, cpuMultiplier, networkMultiplier);
|
|
75
|
+
}
|
|
76
|
+
waitForEventsAfterAction(action, options) {
|
|
77
|
+
const helper = this.createWaitForHelper(this.cpuThrottlingRate, getNetworkMultiplierFromString(this.networkConditions));
|
|
78
|
+
return helper.waitForEventsAfterAction(action, options);
|
|
79
|
+
}
|
|
64
80
|
dispose() {
|
|
65
81
|
this.pptrPage.off('dialog', this.#dialogHandler);
|
|
66
82
|
}
|