chrome-devtools-mcp 1.1.1 → 1.3.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 +33 -4
- package/build/src/HeapSnapshotManager.js +30 -16
- package/build/src/McpContext.js +63 -9
- package/build/src/McpPage.js +9 -9
- package/build/src/McpResponse.js +176 -58
- package/build/src/PageCollector.js +8 -8
- package/build/src/ServiceWorkerCollector.js +171 -0
- package/build/src/TextSnapshot.js +1 -1
- package/build/src/ToolHandler.js +10 -4
- package/build/src/WaitForHelper.js +2 -2
- package/build/src/bin/chrome-devtools-cli-options.js +106 -4
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +64 -5
- package/build/src/bin/chrome-devtools-mcp-main.js +5 -5
- package/build/src/browser.js +8 -4
- package/build/src/daemon/client.js +7 -7
- package/build/src/daemon/daemon.js +12 -12
- package/build/src/daemon/utils.js +2 -2
- package/build/src/{DevToolsConnectionAdapter.js → devtools/DevToolsConnectionAdapter.js} +1 -1
- package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +79 -18
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/formatters/ConsoleFormatter.js +1 -1
- package/build/src/formatters/HeapSnapshotFormatter.js +22 -0
- package/build/src/formatters/IssueFormatter.js +4 -4
- package/build/src/index.js +13 -1
- package/build/src/telemetry/ClearcutLogger.js +1 -1
- package/build/src/telemetry/WatchdogClient.js +4 -4
- package/build/src/telemetry/persistence.js +2 -2
- package/build/src/telemetry/watchdog/ClearcutSender.js +10 -10
- package/build/src/telemetry/watchdog/main.js +5 -5
- package/build/src/third_party/THIRD_PARTY_NOTICES +31 -1
- package/build/src/third_party/bundled-packages.json +2 -1
- package/build/src/third_party/devtools-formatter-worker.js +1 -1
- package/build/src/third_party/devtools-heap-snapshot-worker.js +161 -3
- package/build/src/third_party/index.js +7020 -5774
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
- package/build/src/tools/console.js +7 -0
- package/build/src/tools/emulation.js +1 -0
- package/build/src/tools/extensions.js +5 -2
- package/build/src/tools/input.js +11 -3
- package/build/src/tools/lighthouse.js +11 -6
- package/build/src/tools/memory.js +109 -10
- package/build/src/tools/network.js +2 -2
- package/build/src/tools/pages.js +13 -5
- package/build/src/tools/performance.js +8 -7
- package/build/src/tools/screencast.js +32 -10
- package/build/src/tools/screenshot.js +158 -76
- package/build/src/tools/script.js +1 -1
- package/build/src/tools/slim/tools.js +3 -0
- package/build/src/tools/snapshot.js +3 -2
- package/build/src/tools/thirdPartyDeveloper.js +12 -2
- package/build/src/tools/webmcp.js +2 -0
- package/build/src/trace-processing/parse.js +5 -5
- package/build/src/version.js +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -514,11 +514,15 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
|
|
|
514
514
|
- [`take_snapshot`](docs/tool-reference.md#take_snapshot)
|
|
515
515
|
- [`screencast_start`](docs/tool-reference.md#screencast_start)
|
|
516
516
|
- [`screencast_stop`](docs/tool-reference.md#screencast_stop)
|
|
517
|
-
- **Memory** (
|
|
517
|
+
- **Memory** (9 tools)
|
|
518
518
|
- [`take_heapsnapshot`](docs/tool-reference.md#take_heapsnapshot)
|
|
519
|
+
- [`close_heapsnapshot`](docs/tool-reference.md#close_heapsnapshot)
|
|
519
520
|
- [`get_heapsnapshot_class_nodes`](docs/tool-reference.md#get_heapsnapshot_class_nodes)
|
|
520
521
|
- [`get_heapsnapshot_details`](docs/tool-reference.md#get_heapsnapshot_details)
|
|
522
|
+
- [`get_heapsnapshot_dominators`](docs/tool-reference.md#get_heapsnapshot_dominators)
|
|
523
|
+
- [`get_heapsnapshot_edges`](docs/tool-reference.md#get_heapsnapshot_edges)
|
|
521
524
|
- [`get_heapsnapshot_retainers`](docs/tool-reference.md#get_heapsnapshot_retainers)
|
|
525
|
+
- [`get_heapsnapshot_retaining_paths`](docs/tool-reference.md#get_heapsnapshot_retaining_paths)
|
|
522
526
|
- [`get_heapsnapshot_summary`](docs/tool-reference.md#get_heapsnapshot_summary)
|
|
523
527
|
- **Extensions** (5 tools)
|
|
524
528
|
- [`install_extension`](docs/tool-reference.md#install_extension)
|
|
@@ -608,8 +612,8 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
608
612
|
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.
|
|
609
613
|
- **Type:** boolean
|
|
610
614
|
|
|
611
|
-
- **`--
|
|
612
|
-
Whether to enable
|
|
615
|
+
- **`--memoryDebugging`/ `--memory-debugging`, `-experimentalMemory`**
|
|
616
|
+
Whether to enable memory debugging tools.
|
|
613
617
|
- **Type:** boolean
|
|
614
618
|
|
|
615
619
|
- **`--experimentalStructuredContent`/ `--experimental-structured-content`**
|
|
@@ -629,13 +633,21 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
629
633
|
- **Type:** string
|
|
630
634
|
|
|
631
635
|
- **`--categoryExperimentalWebmcp`/ `--category-experimental-webmcp`**
|
|
632
|
-
Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=
|
|
636
|
+
Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=WebMCP,DevToolsWebMCPSupport`
|
|
633
637
|
- **Type:** boolean
|
|
634
638
|
|
|
635
639
|
- **`--chromeArg`/ `--chrome-arg`**
|
|
636
640
|
Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
|
|
637
641
|
- **Type:** array
|
|
638
642
|
|
|
643
|
+
- **`--blockedUrlPattern`/ `--blocked-url-pattern`**
|
|
644
|
+
Restricts 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). Accepts an array of patterns.
|
|
645
|
+
- **Type:** array
|
|
646
|
+
|
|
647
|
+
- **`--allowedUrlPattern`/ `--allowed-url-pattern`**
|
|
648
|
+
Restricts 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). Accepts an array of patterns.
|
|
649
|
+
- **Type:** array
|
|
650
|
+
|
|
639
651
|
- **`--ignoreDefaultChromeArg`/ `--ignore-default-chrome-arg`**
|
|
640
652
|
Explicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.
|
|
641
653
|
- **Type:** array
|
|
@@ -675,6 +687,23 @@ The Chrome DevTools MCP server supports the following configuration option:
|
|
|
675
687
|
- **Type:** boolean
|
|
676
688
|
- **Default:** `true`
|
|
677
689
|
|
|
690
|
+
- **`--screenshotFormat`/ `--screenshot-format`**
|
|
691
|
+
Override 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 helps reduce context size in AI conversations. Unset preserves the existing default ("png").
|
|
692
|
+
- **Type:** string
|
|
693
|
+
- **Choices:** `jpeg`, `png`, `webp`
|
|
694
|
+
|
|
695
|
+
- **`--screenshotQuality`/ `--screenshot-quality`**
|
|
696
|
+
Override 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.
|
|
697
|
+
- **Type:** number
|
|
698
|
+
|
|
699
|
+
- **`--screenshotMaxWidth`/ `--screenshot-max-width`**
|
|
700
|
+
Maximum 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.
|
|
701
|
+
- **Type:** number
|
|
702
|
+
|
|
703
|
+
- **`--screenshotMaxHeight`/ `--screenshot-max-height`**
|
|
704
|
+
Maximum 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.
|
|
705
|
+
- **Type:** number
|
|
706
|
+
|
|
678
707
|
- **`--slim`**
|
|
679
708
|
Exposes a "slim" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.
|
|
680
709
|
- **Type:** boolean
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fsSync from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
-
import { isNodeLike } from './formatters/HeapSnapshotFormatter.js';
|
|
9
8
|
import { DevTools } from './third_party/index.js';
|
|
10
9
|
import { createIdGenerator, stableIdSymbol, } from './utils/id.js';
|
|
11
10
|
export class HeapSnapshotManager {
|
|
@@ -67,28 +66,38 @@ export class HeapSnapshotManager {
|
|
|
67
66
|
const provider = snapshot.createNodesProviderForClass(className, filter);
|
|
68
67
|
return await provider.serializeItemsRange(0, Infinity);
|
|
69
68
|
}
|
|
70
|
-
async
|
|
69
|
+
async getRetainers(filePath, nodeId) {
|
|
71
70
|
const snapshot = await this.getSnapshot(filePath);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const provider = snapshot.createNodesProviderForClass(classKey, filter);
|
|
76
|
-
const range = await provider.serializeItemsRange(0, Infinity);
|
|
77
|
-
for (const item of range.items) {
|
|
78
|
-
if (isNodeLike(item) && item.id === nodeId) {
|
|
79
|
-
return item.nodeIndex;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
71
|
+
const nodeIndex = await snapshot.nodeIndexForId(nodeId);
|
|
72
|
+
if (nodeIndex === undefined) {
|
|
73
|
+
throw new Error(`Node with ID ${nodeId} not found`);
|
|
82
74
|
}
|
|
83
|
-
|
|
75
|
+
const provider = snapshot.createRetainingEdgesProvider(nodeIndex);
|
|
76
|
+
return await provider.serializeItemsRange(0, Infinity);
|
|
84
77
|
}
|
|
85
|
-
async
|
|
86
|
-
const
|
|
78
|
+
async getRetainingPaths(filePath, nodeId, maxDepth, maxNodes, maxSiblings) {
|
|
79
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
80
|
+
const nodeIndex = await snapshot.nodeIndexForId(nodeId);
|
|
81
|
+
if (nodeIndex === undefined) {
|
|
82
|
+
throw new Error(`Node with ID ${nodeId} not found`);
|
|
83
|
+
}
|
|
84
|
+
return await snapshot.getRetainingPaths(nodeIndex, maxDepth, maxNodes, maxSiblings);
|
|
85
|
+
}
|
|
86
|
+
async getDominatorsOf(filePath, nodeId) {
|
|
87
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
88
|
+
const nodeIndex = await snapshot.nodeIndexForId(nodeId);
|
|
87
89
|
if (nodeIndex === undefined) {
|
|
88
90
|
throw new Error(`Node with ID ${nodeId} not found`);
|
|
89
91
|
}
|
|
92
|
+
return await snapshot.getDominatorsOf(nodeIndex);
|
|
93
|
+
}
|
|
94
|
+
async getEdges(filePath, nodeId) {
|
|
90
95
|
const snapshot = await this.getSnapshot(filePath);
|
|
91
|
-
const
|
|
96
|
+
const nodeIndex = await snapshot.nodeIndexForId(nodeId);
|
|
97
|
+
if (nodeIndex === undefined) {
|
|
98
|
+
throw new Error(`Node with ID ${nodeId} not found`);
|
|
99
|
+
}
|
|
100
|
+
const provider = snapshot.createEdgesProvider(nodeIndex);
|
|
92
101
|
return await provider.serializeItemsRange(0, Infinity);
|
|
93
102
|
}
|
|
94
103
|
#getCachedSnapshot(filePath) {
|
|
@@ -122,13 +131,18 @@ export class HeapSnapshotManager {
|
|
|
122
131
|
const snapshot = await snapshotPromise;
|
|
123
132
|
return { snapshot, worker: workerProxy };
|
|
124
133
|
}
|
|
134
|
+
hasSnapshots() {
|
|
135
|
+
return this.#snapshots.size > 0;
|
|
136
|
+
}
|
|
125
137
|
dispose(filePath) {
|
|
126
138
|
const absolutePath = path.resolve(filePath);
|
|
127
139
|
const cached = this.#snapshots.get(absolutePath);
|
|
128
140
|
if (cached) {
|
|
129
141
|
cached.worker.dispose();
|
|
130
142
|
this.#snapshots.delete(absolutePath);
|
|
143
|
+
return true;
|
|
131
144
|
}
|
|
145
|
+
return false;
|
|
132
146
|
}
|
|
133
147
|
}
|
|
134
148
|
//# sourceMappingURL=HeapSnapshotManager.js.map
|
package/build/src/McpContext.js
CHANGED
|
@@ -8,10 +8,11 @@ import fsPromises from 'node:fs/promises';
|
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
11
|
-
import { UniverseManager } from './DevtoolsUtils.js';
|
|
11
|
+
import { overrideDevToolsGlobals, UniverseManager, } from './devtools/DevtoolsUtils.js';
|
|
12
12
|
import { HeapSnapshotManager } from './HeapSnapshotManager.js';
|
|
13
13
|
import { McpPage } from './McpPage.js';
|
|
14
14
|
import { NetworkCollector, ConsoleCollector, } from './PageCollector.js';
|
|
15
|
+
import { ServiceWorkerConsoleCollector } from './ServiceWorkerCollector.js';
|
|
15
16
|
import { Locator, PredefinedNetworkConditions, } from './third_party/index.js';
|
|
16
17
|
import { listPages } from './tools/pages.js';
|
|
17
18
|
import { CLOSE_PAGE_ERROR } from './tools/ToolDefinition.js';
|
|
@@ -33,6 +34,7 @@ export class McpContext {
|
|
|
33
34
|
#networkCollector;
|
|
34
35
|
#consoleCollector;
|
|
35
36
|
#devtoolsUniverseManager;
|
|
37
|
+
#serviceWorkerConsoleCollector;
|
|
36
38
|
#isRunningTrace = false;
|
|
37
39
|
#screenRecorderData = null;
|
|
38
40
|
#nextPageId = 1;
|
|
@@ -45,6 +47,11 @@ export class McpContext {
|
|
|
45
47
|
#heapSnapshotManager = new HeapSnapshotManager();
|
|
46
48
|
#roots = undefined;
|
|
47
49
|
constructor(browser, logger, options, locatorClass) {
|
|
50
|
+
overrideDevToolsGlobals({
|
|
51
|
+
loadResource: (url) => {
|
|
52
|
+
return this.loadResource(url);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
48
55
|
this.browser = browser;
|
|
49
56
|
this.logger = logger;
|
|
50
57
|
this.#locatorClass = locatorClass;
|
|
@@ -63,19 +70,22 @@ export class McpContext {
|
|
|
63
70
|
},
|
|
64
71
|
};
|
|
65
72
|
});
|
|
73
|
+
this.#serviceWorkerConsoleCollector = new ServiceWorkerConsoleCollector(this.browser);
|
|
66
74
|
this.#devtoolsUniverseManager = new UniverseManager(this.browser);
|
|
67
75
|
}
|
|
68
76
|
async #init() {
|
|
69
77
|
const pages = await this.createPagesSnapshot();
|
|
70
|
-
await this.createExtensionServiceWorkersSnapshot();
|
|
78
|
+
const workers = await this.createExtensionServiceWorkersSnapshot();
|
|
71
79
|
await this.#networkCollector.init(pages);
|
|
72
80
|
await this.#consoleCollector.init(pages);
|
|
73
81
|
await this.#devtoolsUniverseManager.init(pages);
|
|
82
|
+
await this.#serviceWorkerConsoleCollector.init(workers);
|
|
74
83
|
}
|
|
75
84
|
dispose() {
|
|
76
85
|
this.#networkCollector.dispose();
|
|
77
86
|
this.#consoleCollector.dispose();
|
|
78
87
|
this.#devtoolsUniverseManager.dispose();
|
|
88
|
+
this.#serviceWorkerConsoleCollector.dispose();
|
|
79
89
|
for (const mcpPage of this.#mcpPages.values()) {
|
|
80
90
|
mcpPage.dispose();
|
|
81
91
|
}
|
|
@@ -148,7 +158,7 @@ export class McpContext {
|
|
|
148
158
|
}
|
|
149
159
|
resolveCdpRequestId(page, cdpRequestId) {
|
|
150
160
|
if (!cdpRequestId) {
|
|
151
|
-
this.logger('no network request');
|
|
161
|
+
this.logger?.('no network request');
|
|
152
162
|
return;
|
|
153
163
|
}
|
|
154
164
|
const request = this.#networkCollector.find(page.pptrPage, request => {
|
|
@@ -156,7 +166,7 @@ export class McpContext {
|
|
|
156
166
|
return request.id === cdpRequestId;
|
|
157
167
|
});
|
|
158
168
|
if (!request) {
|
|
159
|
-
this.logger('no network request for ' + cdpRequestId);
|
|
169
|
+
this.logger?.('no network request for ' + cdpRequestId);
|
|
160
170
|
return;
|
|
161
171
|
}
|
|
162
172
|
return this.#networkCollector.getIdForResource(request);
|
|
@@ -217,7 +227,13 @@ export class McpContext {
|
|
|
217
227
|
const page = targetPage ?? this.getSelectedPptrPage();
|
|
218
228
|
const mcpPage = this.#getMcpPage(page);
|
|
219
229
|
const newSettings = { ...mcpPage.emulationSettings };
|
|
220
|
-
if
|
|
230
|
+
// Skip network emulation if blocklist/allowlist is configured, as it conflicts with blocking rules in Puppeteer.
|
|
231
|
+
if (this.#options.hasNetworkBlockOrAllowlist) {
|
|
232
|
+
if (options.networkConditions !== undefined) {
|
|
233
|
+
throw new Error('Network throttling is not supported when network blocking (allowlist/blocklist) is configured.');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (!options.networkConditions) {
|
|
221
237
|
await page.emulateNetworkConditions(null);
|
|
222
238
|
delete newSettings.networkConditions;
|
|
223
239
|
}
|
|
@@ -412,6 +428,9 @@ export class McpContext {
|
|
|
412
428
|
});
|
|
413
429
|
return this.#extensionServiceWorkers;
|
|
414
430
|
}
|
|
431
|
+
getServiceWorkerConsoleData(extensionId) {
|
|
432
|
+
return this.#serviceWorkerConsoleCollector.getData(extensionId);
|
|
433
|
+
}
|
|
415
434
|
async createPagesSnapshot() {
|
|
416
435
|
const { pages: allPages, isolatedContextNames } = await this.#getAllPages();
|
|
417
436
|
for (const page of allPages) {
|
|
@@ -421,7 +440,7 @@ export class McpContext {
|
|
|
421
440
|
this.#mcpPages.set(page, mcpPage);
|
|
422
441
|
// We emulate a focused page for all pages to support multi-agent workflows.
|
|
423
442
|
void page.emulateFocusedPage(true).catch(error => {
|
|
424
|
-
this.logger('Error turning on focused page emulation', error);
|
|
443
|
+
this.logger?.('Error turning on focused page emulation', error);
|
|
425
444
|
});
|
|
426
445
|
}
|
|
427
446
|
mcpPage.isolatedContextName = isolatedContextNames.get(page);
|
|
@@ -467,7 +486,7 @@ export class McpContext {
|
|
|
467
486
|
this.#extensionPages.set(target, page);
|
|
468
487
|
}
|
|
469
488
|
catch (e) {
|
|
470
|
-
this.logger('Failed to get page for extension target', e);
|
|
489
|
+
this.logger?.('Failed to get page for extension target', e);
|
|
471
490
|
}
|
|
472
491
|
}
|
|
473
492
|
}
|
|
@@ -502,7 +521,7 @@ export class McpContext {
|
|
|
502
521
|
return { pages: allPages, isolatedContextNames };
|
|
503
522
|
}
|
|
504
523
|
async detectOpenDevToolsWindows() {
|
|
505
|
-
this.logger('Detecting open DevTools windows');
|
|
524
|
+
this.logger?.('Detecting open DevTools windows');
|
|
506
525
|
const { pages } = await this.#getAllPages();
|
|
507
526
|
await Promise.all(pages.map(async (page) => {
|
|
508
527
|
const mcpPage = this.#mcpPages.get(page);
|
|
@@ -557,7 +576,7 @@ export class McpContext {
|
|
|
557
576
|
return { filename: filePath };
|
|
558
577
|
}
|
|
559
578
|
catch (err) {
|
|
560
|
-
this.logger(err);
|
|
579
|
+
this.logger?.(err);
|
|
561
580
|
throw new Error('Could not save a file', { cause: err });
|
|
562
581
|
}
|
|
563
582
|
}
|
|
@@ -639,5 +658,40 @@ export class McpContext {
|
|
|
639
658
|
async getHeapSnapshotRetainers(filePath, nodeId) {
|
|
640
659
|
return await this.#heapSnapshotManager.getRetainers(filePath, nodeId);
|
|
641
660
|
}
|
|
661
|
+
async closeHeapSnapshot(filePath) {
|
|
662
|
+
return this.#heapSnapshotManager.dispose(filePath);
|
|
663
|
+
}
|
|
664
|
+
hasHeapSnapshots() {
|
|
665
|
+
return this.#heapSnapshotManager.hasSnapshots();
|
|
666
|
+
}
|
|
667
|
+
async getHeapSnapshotRetainingPaths(filePath, nodeId, maxDepth, maxNodes, maxSiblings) {
|
|
668
|
+
return await this.#heapSnapshotManager.getRetainingPaths(filePath, nodeId, maxDepth, maxNodes, maxSiblings);
|
|
669
|
+
}
|
|
670
|
+
async getHeapSnapshotDominators(filePath, nodeId) {
|
|
671
|
+
return await this.#heapSnapshotManager.getDominatorsOf(filePath, nodeId);
|
|
672
|
+
}
|
|
673
|
+
async loadResource(path) {
|
|
674
|
+
const url = new URL(path);
|
|
675
|
+
switch (url.protocol) {
|
|
676
|
+
case 'https:':
|
|
677
|
+
case 'http:': {
|
|
678
|
+
// TODO: Verify allow/block list
|
|
679
|
+
const response = await fetch(url);
|
|
680
|
+
if (!response.ok) {
|
|
681
|
+
throw new Error(`Failed to load resource: ${url}`);
|
|
682
|
+
}
|
|
683
|
+
return response.text();
|
|
684
|
+
}
|
|
685
|
+
case 'file:': {
|
|
686
|
+
await this.validatePath(fileURLToPath(url));
|
|
687
|
+
return await fsPromises.readFile(url, 'utf-8');
|
|
688
|
+
}
|
|
689
|
+
default:
|
|
690
|
+
throw new Error(`Unsupported protocol for: ${url}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
async getHeapSnapshotEdges(filePath, nodeId) {
|
|
694
|
+
return await this.#heapSnapshotManager.getEdges(filePath, nodeId);
|
|
695
|
+
}
|
|
642
696
|
}
|
|
643
697
|
//# sourceMappingURL=McpContext.js.map
|
package/build/src/McpPage.js
CHANGED
|
@@ -30,7 +30,7 @@ export class McpPage {
|
|
|
30
30
|
// Dialog
|
|
31
31
|
#dialog;
|
|
32
32
|
#dialogHandler;
|
|
33
|
-
thirdPartyDeveloperTools;
|
|
33
|
+
thirdPartyDeveloperTools = [];
|
|
34
34
|
constructor(page, id) {
|
|
35
35
|
this.pptrPage = page;
|
|
36
36
|
this.id = id;
|
|
@@ -194,18 +194,18 @@ export class McpPage {
|
|
|
194
194
|
for (const handle of oldHandles) {
|
|
195
195
|
await handle
|
|
196
196
|
.dispose()
|
|
197
|
-
.catch(e => logger('Failed to dispose old handle', e));
|
|
197
|
+
.catch(e => logger?.('Failed to dispose old handle', e));
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
const cdpElementIds = await Promise.all(elementHandles.map(async (elementHandle, index) => {
|
|
201
201
|
const backendNodeId = await elementHandle.backendNodeId();
|
|
202
202
|
if (!backendNodeId) {
|
|
203
|
-
logger(`No backendNodeId for stashed DOM element with index ${index}`);
|
|
203
|
+
logger?.(`No backendNodeId for stashed DOM element with index ${index}`);
|
|
204
204
|
return `stashed-${index}`;
|
|
205
205
|
}
|
|
206
206
|
const cdpElementId = this.resolveCdpElementId(backendNodeId);
|
|
207
207
|
if (!cdpElementId) {
|
|
208
|
-
logger(`Could not get cdpElementId for backend node ${backendNodeId}`);
|
|
208
|
+
logger?.(`Could not get cdpElementId for backend node ${backendNodeId}`);
|
|
209
209
|
return `stashed-${index}`;
|
|
210
210
|
}
|
|
211
211
|
return cdpElementId;
|
|
@@ -263,12 +263,12 @@ export class McpPage {
|
|
|
263
263
|
}
|
|
264
264
|
resolveCdpElementId(cdpBackendNodeId) {
|
|
265
265
|
if (!cdpBackendNodeId) {
|
|
266
|
-
logger('no cdpBackendNodeId');
|
|
266
|
+
logger?.('no cdpBackendNodeId');
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
269
|
const snapshot = this.textSnapshot;
|
|
270
270
|
if (!snapshot) {
|
|
271
|
-
logger('no text snapshot');
|
|
271
|
+
logger?.('no text snapshot');
|
|
272
272
|
return;
|
|
273
273
|
}
|
|
274
274
|
// TODO: index by backendNodeId instead.
|
|
@@ -286,10 +286,10 @@ export class McpPage {
|
|
|
286
286
|
}
|
|
287
287
|
async getDevToolsData() {
|
|
288
288
|
try {
|
|
289
|
-
logger('Getting DevTools UI data');
|
|
289
|
+
logger?.('Getting DevTools UI data');
|
|
290
290
|
const devtoolsPage = this.devToolsPage;
|
|
291
291
|
if (!devtoolsPage) {
|
|
292
|
-
logger('No DevTools page detected');
|
|
292
|
+
logger?.('No DevTools page detected');
|
|
293
293
|
return {};
|
|
294
294
|
}
|
|
295
295
|
const { cdpRequestId, cdpBackendNodeId } = await devtoolsPage.evaluate(async () => {
|
|
@@ -307,7 +307,7 @@ export class McpPage {
|
|
|
307
307
|
return { cdpBackendNodeId, cdpRequestId };
|
|
308
308
|
}
|
|
309
309
|
catch (err) {
|
|
310
|
-
logger('error getting devtools data', err);
|
|
310
|
+
logger?.('error getting devtools data', err);
|
|
311
311
|
}
|
|
312
312
|
return {};
|
|
313
313
|
}
|