chrome-devtools-mcp 0.21.0 → 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 +83 -21
- package/build/src/HeapSnapshotManager.js +94 -0
- package/build/src/McpContext.js +26 -56
- package/build/src/McpPage.js +16 -0
- package/build/src/McpResponse.js +145 -11
- package/build/src/PageCollector.js +10 -24
- 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 +24 -10
- package/build/src/bin/chrome-devtools-mcp-main.js +2 -0
- package/build/src/bin/chrome-devtools.js +3 -0
- package/build/src/bin/cliDefinitions.js +14 -8
- package/build/src/daemon/client.js +1 -1
- package/build/src/daemon/daemon.js +0 -4
- package/build/src/formatters/HeapSnapshotFormatter.js +38 -0
- package/build/src/formatters/NetworkFormatter.js +24 -7
- package/build/src/index.js +12 -1
- package/build/src/telemetry/ClearcutLogger.js +34 -12
- package/build/src/telemetry/flagUtils.js +46 -4
- package/build/src/telemetry/toolMetricsUtils.js +88 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +4 -3
- package/build/src/third_party/THIRD_PARTY_NOTICES +32 -32
- package/build/src/third_party/bundled-packages.json +5 -4
- package/build/src/third_party/devtools-formatter-worker.js +61 -64
- package/build/src/third_party/devtools-heap-snapshot-worker.js +9690 -0
- package/build/src/third_party/index.js +61443 -59378
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +3501 -2658
- package/build/src/tools/categories.js +3 -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 +27 -6
- package/build/src/tools/input.js +15 -16
- package/build/src/tools/lighthouse.js +2 -2
- package/build/src/tools/memory.js +48 -3
- package/build/src/tools/network.js +2 -2
- package/build/src/tools/pages.js +8 -5
- 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 +2 -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 +12 -8
- 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
|
|
|
@@ -28,7 +29,7 @@ Avoid sharing sensitive or personal information that you don't want to share wit
|
|
|
28
29
|
MCP clients.
|
|
29
30
|
|
|
30
31
|
`chrome-devtools-mcp` officially supports Google Chrome and [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) only.
|
|
31
|
-
Other Chromium-based
|
|
32
|
+
Other Chromium-based browsers may work, but this is not guaranteed, and you may encounter unexpected behavior. Use at your own discretion.
|
|
32
33
|
We are committed to providing fixes and support for the latest version of [Extended Stable Chrome](https://chromiumdash.appspot.com/schedule).
|
|
33
34
|
|
|
34
35
|
Performance tools may send trace URLs to the Google CrUX API to fetch real-user
|
|
@@ -51,7 +52,12 @@ Google handles this data in accordance with the [Google Privacy Policy](https://
|
|
|
51
52
|
|
|
52
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.
|
|
53
54
|
|
|
54
|
-
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.
|
|
55
61
|
|
|
56
62
|
## Requirements
|
|
57
63
|
|
|
@@ -74,7 +80,7 @@ Add the following config to your MCP client:
|
|
|
74
80
|
}
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
> [!NOTE]
|
|
83
|
+
> [!NOTE]
|
|
78
84
|
> Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server.
|
|
79
85
|
|
|
80
86
|
If you are interested in doing only basic browser tasks, use the `--slim` mode:
|
|
@@ -143,7 +149,7 @@ claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
|
|
|
143
149
|
|
|
144
150
|
**Install as a Plugin (MCP + Skills)**
|
|
145
151
|
|
|
146
|
-
> [!NOTE]
|
|
152
|
+
> [!NOTE]
|
|
147
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.
|
|
148
154
|
|
|
149
155
|
To install Chrome DevTools MCP with skills, add the marketplace registry in Claude Code:
|
|
@@ -200,7 +206,7 @@ startup_timeout_ms = 20_000
|
|
|
200
206
|
|
|
201
207
|
<details>
|
|
202
208
|
<summary>Command Code</summary>
|
|
203
|
-
|
|
209
|
+
|
|
204
210
|
Use the Command Code CLI to add the Chrome DevTools MCP server (<a href="https://commandcode.ai/docs/mcp">MCP guide</a>):
|
|
205
211
|
|
|
206
212
|
```bash
|
|
@@ -235,6 +241,22 @@ Configure the following fields and press `CTRL+S` to save the configuration:
|
|
|
235
241
|
<details>
|
|
236
242
|
<summary>Copilot / VS Code</summary>
|
|
237
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
|
+
|
|
238
260
|
**Click the button to install:**
|
|
239
261
|
|
|
240
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)
|
|
@@ -243,8 +265,7 @@ Configure the following fields and press `CTRL+S` to save the configuration:
|
|
|
243
265
|
|
|
244
266
|
**Or install manually:**
|
|
245
267
|
|
|
246
|
-
Follow the MCP
|
|
247
|
-
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:
|
|
248
269
|
|
|
249
270
|
For macOS and Linux:
|
|
250
271
|
|
|
@@ -353,6 +374,21 @@ Once connected, the Chrome DevTools MCP tools will be available in StudioAssist.
|
|
|
353
374
|
|
|
354
375
|
</details>
|
|
355
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
|
+
|
|
356
392
|
<details>
|
|
357
393
|
<summary>OpenCode</summary>
|
|
358
394
|
|
|
@@ -402,10 +438,11 @@ qodercli mcp add -s user chrome-devtools -- npx chrome-devtools-mcp@latest
|
|
|
402
438
|
|
|
403
439
|
<details>
|
|
404
440
|
<summary>Visual Studio</summary>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
+
|
|
409
446
|
</details>
|
|
410
447
|
|
|
411
448
|
<details>
|
|
@@ -431,7 +468,7 @@ Check the performance of https://developers.chrome.com
|
|
|
431
468
|
|
|
432
469
|
Your MCP client should open the browser and record a performance trace.
|
|
433
470
|
|
|
434
|
-
> [!NOTE]
|
|
471
|
+
> [!NOTE]
|
|
435
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.
|
|
436
473
|
|
|
437
474
|
## Tools
|
|
@@ -460,11 +497,10 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
|
|
|
460
497
|
- **Emulation** (2 tools)
|
|
461
498
|
- [`emulate`](docs/tool-reference.md#emulate)
|
|
462
499
|
- [`resize_page`](docs/tool-reference.md#resize_page)
|
|
463
|
-
- **Performance** (
|
|
500
|
+
- **Performance** (3 tools)
|
|
464
501
|
- [`performance_analyze_insight`](docs/tool-reference.md#performance_analyze_insight)
|
|
465
502
|
- [`performance_start_trace`](docs/tool-reference.md#performance_start_trace)
|
|
466
503
|
- [`performance_stop_trace`](docs/tool-reference.md#performance_stop_trace)
|
|
467
|
-
- [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)
|
|
468
504
|
- **Network** (2 tools)
|
|
469
505
|
- [`get_network_request`](docs/tool-reference.md#get_network_request)
|
|
470
506
|
- [`list_network_requests`](docs/tool-reference.md#list_network_requests)
|
|
@@ -475,6 +511,14 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
|
|
|
475
511
|
- [`list_console_messages`](docs/tool-reference.md#list_console_messages)
|
|
476
512
|
- [`take_screenshot`](docs/tool-reference.md#take_screenshot)
|
|
477
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)
|
|
478
522
|
|
|
479
523
|
<!-- END AUTO GENERATED TOOLS -->
|
|
480
524
|
|
|
@@ -485,7 +529,7 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
485
529
|
<!-- BEGIN AUTO GENERATED OPTIONS -->
|
|
486
530
|
|
|
487
531
|
- **`--autoConnect`/ `--auto-connect`**
|
|
488
|
-
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.
|
|
489
533
|
- **Type:** boolean
|
|
490
534
|
- **Default:** `false`
|
|
491
535
|
|
|
@@ -521,7 +565,7 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
521
565
|
- **`--channel`**
|
|
522
566
|
Specify a different Chrome channel that should be used. The default is the stable channel version.
|
|
523
567
|
- **Type:** string
|
|
524
|
-
- **Choices:** `
|
|
568
|
+
- **Choices:** `canary`, `dev`, `beta`, `stable`
|
|
525
569
|
|
|
526
570
|
- **`--logFile`/ `--log-file`**
|
|
527
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.
|
|
@@ -539,10 +583,18 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
539
583
|
If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.
|
|
540
584
|
- **Type:** boolean
|
|
541
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
|
+
|
|
542
590
|
- **`--experimentalScreencast`/ `--experimental-screencast`**
|
|
543
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.
|
|
544
592
|
- **Type:** boolean
|
|
545
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
|
+
|
|
546
598
|
- **`--chromeArg`/ `--chrome-arg`**
|
|
547
599
|
Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
|
|
548
600
|
- **Type:** array
|
|
@@ -566,13 +618,18 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
566
618
|
- **Type:** boolean
|
|
567
619
|
- **Default:** `true`
|
|
568
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
|
+
|
|
569
626
|
- **`--performanceCrux`/ `--performance-crux`**
|
|
570
627
|
Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.
|
|
571
628
|
- **Type:** boolean
|
|
572
629
|
- **Default:** `true`
|
|
573
630
|
|
|
574
631
|
- **`--usageStatistics`/ `--usage-statistics`**
|
|
575
|
-
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.
|
|
576
633
|
- **Type:** boolean
|
|
577
634
|
- **Default:** `true`
|
|
578
635
|
|
|
@@ -580,6 +637,11 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
580
637
|
Exposes a "slim" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.
|
|
581
638
|
- **Type:** boolean
|
|
582
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
|
+
|
|
583
645
|
<!-- END AUTO GENERATED OPTIONS -->
|
|
584
646
|
|
|
585
647
|
Pass them via the `args` property in the JSON configuration. For example:
|
|
@@ -686,7 +748,7 @@ Make sure your browser is running. Open gemini-cli and run the following prompt:
|
|
|
686
748
|
Check the performance of https://developers.chrome.com
|
|
687
749
|
```
|
|
688
750
|
|
|
689
|
-
> [!NOTE]
|
|
751
|
+
> [!NOTE]
|
|
690
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.
|
|
691
753
|
|
|
692
754
|
The Chrome DevTools MCP server will try to connect to your running Chrome
|
|
@@ -722,7 +784,7 @@ Add the `--browser-url` option to your MCP client configuration. The value of th
|
|
|
722
784
|
|
|
723
785
|
**Step 2: Start the Chrome browser**
|
|
724
786
|
|
|
725
|
-
> [!WARNING]
|
|
787
|
+
> [!WARNING]
|
|
726
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.
|
|
727
789
|
|
|
728
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,10 +31,8 @@ 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
|
-
#inPageTools;
|
|
52
36
|
#nextPageId = 1;
|
|
53
37
|
#extensionPages = new WeakMap();
|
|
54
38
|
#extensionServiceWorkerMap = new WeakMap();
|
|
@@ -57,6 +41,7 @@ export class McpContext {
|
|
|
57
41
|
#traceResults = [];
|
|
58
42
|
#locatorClass;
|
|
59
43
|
#options;
|
|
44
|
+
#heapSnapshotManager = new HeapSnapshotManager();
|
|
60
45
|
constructor(browser, logger, options, locatorClass) {
|
|
61
46
|
this.browser = browser;
|
|
62
47
|
this.logger = logger;
|
|
@@ -71,7 +56,7 @@ export class McpContext {
|
|
|
71
56
|
uncaughtError: event => {
|
|
72
57
|
collect(event);
|
|
73
58
|
},
|
|
74
|
-
|
|
59
|
+
devtoolsAggregatedIssue: event => {
|
|
75
60
|
collect(event);
|
|
76
61
|
},
|
|
77
62
|
};
|
|
@@ -329,12 +314,6 @@ export class McpContext {
|
|
|
329
314
|
this.#selectedPage = newPage;
|
|
330
315
|
this.#updateSelectedPageTimeouts();
|
|
331
316
|
}
|
|
332
|
-
setInPageTools(toolGroup) {
|
|
333
|
-
this.#inPageTools = toolGroup;
|
|
334
|
-
}
|
|
335
|
-
getInPageTools() {
|
|
336
|
-
return this.#inPageTools;
|
|
337
|
-
}
|
|
338
317
|
#updateSelectedPageTimeouts() {
|
|
339
318
|
const page = this.#getSelectedMcpPage();
|
|
340
319
|
// For waiters 5sec timeout should be sufficient.
|
|
@@ -611,9 +590,9 @@ export class McpContext {
|
|
|
611
590
|
async saveTemporaryFile(data, filename) {
|
|
612
591
|
return await saveTemporaryFile(data, filename);
|
|
613
592
|
}
|
|
614
|
-
async saveFile(data,
|
|
593
|
+
async saveFile(data, clientProvidedFilePath, extension) {
|
|
615
594
|
try {
|
|
616
|
-
const filePath = path.resolve(
|
|
595
|
+
const filePath = ensureExtension(path.resolve(clientProvidedFilePath), extension);
|
|
617
596
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
618
597
|
await fs.writeFile(filePath, data);
|
|
619
598
|
return { filename: filePath };
|
|
@@ -631,16 +610,6 @@ export class McpContext {
|
|
|
631
610
|
recordedTraces() {
|
|
632
611
|
return this.#traceResults;
|
|
633
612
|
}
|
|
634
|
-
getWaitForHelper(page, cpuMultiplier, networkMultiplier) {
|
|
635
|
-
return new WaitForHelper(page, cpuMultiplier, networkMultiplier);
|
|
636
|
-
}
|
|
637
|
-
waitForEventsAfterAction(action, options) {
|
|
638
|
-
const page = this.#getSelectedMcpPage();
|
|
639
|
-
const cpuMultiplier = page.cpuThrottlingRate;
|
|
640
|
-
const networkMultiplier = getNetworkMultiplierFromString(page.networkConditions);
|
|
641
|
-
const waitForHelper = this.getWaitForHelper(page.pptrPage, cpuMultiplier, networkMultiplier);
|
|
642
|
-
return waitForHelper.waitForEventsAfterAction(action, options);
|
|
643
|
-
}
|
|
644
613
|
getNetworkRequestStableId(request) {
|
|
645
614
|
return this.#networkCollector.getIdForResource(request);
|
|
646
615
|
}
|
|
@@ -675,33 +644,34 @@ export class McpContext {
|
|
|
675
644
|
}
|
|
676
645
|
async installExtension(extensionPath) {
|
|
677
646
|
const id = await this.browser.installExtension(extensionPath);
|
|
678
|
-
await this.#extensionRegistry.registerExtension(id, extensionPath);
|
|
679
647
|
return id;
|
|
680
648
|
}
|
|
681
649
|
async uninstallExtension(id) {
|
|
682
650
|
await this.browser.uninstallExtension(id);
|
|
683
|
-
this.#extensionRegistry.remove(id);
|
|
684
651
|
}
|
|
685
652
|
async triggerExtensionAction(id) {
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const session = await this.browser.target().createCDPSession();
|
|
691
|
-
try {
|
|
692
|
-
await session.send('Extensions.triggerAction', {
|
|
693
|
-
id,
|
|
694
|
-
targetId: theTarget,
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
finally {
|
|
698
|
-
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.`);
|
|
699
657
|
}
|
|
658
|
+
const page = this.getSelectedPptrPage();
|
|
659
|
+
await extension.triggerAction(page);
|
|
700
660
|
}
|
|
701
661
|
listExtensions() {
|
|
702
|
-
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);
|
|
703
673
|
}
|
|
704
|
-
|
|
705
|
-
return this.#
|
|
674
|
+
async getHeapSnapshotStaticData(filePath) {
|
|
675
|
+
return await this.#heapSnapshotManager.getStaticData(filePath);
|
|
706
676
|
}
|
|
707
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
|
}
|