chrome-devtools-mcp 0.20.2 → 0.20.3
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/build/src/DevtoolsUtils.js +0 -46
- package/build/src/McpContext.js +19 -31
- package/build/src/PageCollector.js +4 -3
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +5 -5
- package/build/src/index.js +1 -1
- package/build/src/third_party/bundled-packages.json +1 -1
- package/build/src/third_party/devtools-formatter-worker.js +0 -1
- package/build/src/third_party/index.js +929 -561
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorNoCorpCrossOriginNoCorsRequest.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoCorpCossOriginNoCorsRequest.md +3 -0
- package/build/src/version.js +1 -1
- package/package.json +2 -2
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +0 -1
|
@@ -6,52 +6,6 @@
|
|
|
6
6
|
import { PuppeteerDevToolsConnection } from './DevToolsConnectionAdapter.js';
|
|
7
7
|
import { Mutex } from './Mutex.js';
|
|
8
8
|
import { DevTools } from './third_party/index.js';
|
|
9
|
-
export function extractUrlLikeFromDevToolsTitle(title) {
|
|
10
|
-
const match = title.match(new RegExp(`DevTools - (.*)`));
|
|
11
|
-
return match?.[1] ?? undefined;
|
|
12
|
-
}
|
|
13
|
-
export function urlsEqual(url1, url2) {
|
|
14
|
-
const normalizedUrl1 = normalizeUrl(url1);
|
|
15
|
-
const normalizedUrl2 = normalizeUrl(url2);
|
|
16
|
-
return normalizedUrl1 === normalizedUrl2;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* For the sake of the MCP server, when we determine if two URLs are equal we
|
|
20
|
-
* remove some parts:
|
|
21
|
-
*
|
|
22
|
-
* 1. We do not care about the protocol.
|
|
23
|
-
* 2. We do not care about trailing slashes.
|
|
24
|
-
* 3. We do not care about "www".
|
|
25
|
-
* 4. We ignore the hash parts.
|
|
26
|
-
*
|
|
27
|
-
* For example, if the user types "record a trace on foo.com", we would want to
|
|
28
|
-
* match a tab in the connected Chrome instance that is showing "www.foo.com/"
|
|
29
|
-
*/
|
|
30
|
-
function normalizeUrl(url) {
|
|
31
|
-
let result = url.trim();
|
|
32
|
-
// Remove protocols
|
|
33
|
-
if (result.startsWith('https://')) {
|
|
34
|
-
result = result.slice(8);
|
|
35
|
-
}
|
|
36
|
-
else if (result.startsWith('http://')) {
|
|
37
|
-
result = result.slice(7);
|
|
38
|
-
}
|
|
39
|
-
// Remove 'www.'. This ensures that we find the right URL regardless of if the user adds `www` or not.
|
|
40
|
-
if (result.startsWith('www.')) {
|
|
41
|
-
result = result.slice(4);
|
|
42
|
-
}
|
|
43
|
-
// We use target URLs to locate DevTools but those often do
|
|
44
|
-
// no include hash.
|
|
45
|
-
const hashIdx = result.lastIndexOf('#');
|
|
46
|
-
if (hashIdx !== -1) {
|
|
47
|
-
result = result.slice(0, hashIdx);
|
|
48
|
-
}
|
|
49
|
-
// Remove trailing slash
|
|
50
|
-
if (result.endsWith('/')) {
|
|
51
|
-
result = result.slice(0, -1);
|
|
52
|
-
}
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
9
|
/**
|
|
56
10
|
* A mock implementation of an issues manager that only implements the methods
|
|
57
11
|
* that are actually used by the IssuesAggregator
|
package/build/src/McpContext.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from 'node:fs/promises';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
-
import {
|
|
8
|
+
import { UniverseManager } from './DevtoolsUtils.js';
|
|
9
9
|
import { McpPage } from './McpPage.js';
|
|
10
|
-
import { NetworkCollector, ConsoleCollector } from './PageCollector.js';
|
|
10
|
+
import { NetworkCollector, ConsoleCollector, } from './PageCollector.js';
|
|
11
11
|
import { Locator } from './third_party/index.js';
|
|
12
12
|
import { PredefinedNetworkConditions } from './third_party/index.js';
|
|
13
13
|
import { listPages } from './tools/pages.js';
|
|
@@ -467,38 +467,26 @@ export class McpContext {
|
|
|
467
467
|
async detectOpenDevToolsWindows() {
|
|
468
468
|
this.logger('Detecting open DevTools windows');
|
|
469
469
|
const { pages } = await this.#getAllPages();
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
mcpPage
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
.send('Target.getTargetInfo');
|
|
482
|
-
const devtoolsPageTitle = data.targetInfo.title;
|
|
483
|
-
const urlLike = extractUrlLikeFromDevToolsTitle(devtoolsPageTitle);
|
|
484
|
-
if (!urlLike) {
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
// TODO: lookup without a loop.
|
|
488
|
-
for (const page of this.#pages) {
|
|
489
|
-
if (urlsEqual(page.url(), urlLike)) {
|
|
490
|
-
const mcpPage = this.#mcpPages.get(page);
|
|
491
|
-
if (mcpPage) {
|
|
492
|
-
mcpPage.devToolsPage = devToolsPage;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
470
|
+
await Promise.all(pages.map(async (page) => {
|
|
471
|
+
const mcpPage = this.#mcpPages.get(page);
|
|
472
|
+
if (!mcpPage) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
// Prior to Chrome 144.0.7559.59, the command fails,
|
|
476
|
+
// Some Electron apps still use older version
|
|
477
|
+
// Fall back to not exposing DevTools at all.
|
|
478
|
+
try {
|
|
479
|
+
if (await page.hasDevTools()) {
|
|
480
|
+
mcpPage.devToolsPage = await page.openDevTools();
|
|
496
481
|
}
|
|
497
|
-
|
|
498
|
-
|
|
482
|
+
else {
|
|
483
|
+
mcpPage.devToolsPage = undefined;
|
|
499
484
|
}
|
|
500
485
|
}
|
|
501
|
-
|
|
486
|
+
catch {
|
|
487
|
+
mcpPage.devToolsPage = undefined;
|
|
488
|
+
}
|
|
489
|
+
}));
|
|
502
490
|
}
|
|
503
491
|
getExtensionServiceWorkers() {
|
|
504
492
|
return this.#extensionServiceWorkers;
|
|
@@ -28,7 +28,7 @@ export class PageCollector {
|
|
|
28
28
|
#browser;
|
|
29
29
|
#listenersInitializer;
|
|
30
30
|
#listeners = new WeakMap();
|
|
31
|
-
|
|
31
|
+
maxNavigationSaved = 3;
|
|
32
32
|
/**
|
|
33
33
|
* This maps a Page to a list of navigations with a sub-list
|
|
34
34
|
* of all collected resources.
|
|
@@ -109,7 +109,7 @@ export class PageCollector {
|
|
|
109
109
|
}
|
|
110
110
|
// Add the latest navigation first
|
|
111
111
|
navigations.unshift([]);
|
|
112
|
-
navigations.splice(this
|
|
112
|
+
navigations.splice(this.maxNavigationSaved);
|
|
113
113
|
}
|
|
114
114
|
cleanupPageDestroyed(page) {
|
|
115
115
|
const listeners = this.#listeners.get(page);
|
|
@@ -129,7 +129,7 @@ export class PageCollector {
|
|
|
129
129
|
return navigations[0];
|
|
130
130
|
}
|
|
131
131
|
const data = [];
|
|
132
|
-
for (let index = this
|
|
132
|
+
for (let index = this.maxNavigationSaved; index >= 0; index--) {
|
|
133
133
|
if (navigations[index]) {
|
|
134
134
|
data.push(...navigations[index]);
|
|
135
135
|
}
|
|
@@ -305,5 +305,6 @@ export class NetworkCollector extends PageCollector {
|
|
|
305
305
|
else {
|
|
306
306
|
navigations.unshift([]);
|
|
307
307
|
}
|
|
308
|
+
navigations.splice(this.maxNavigationSaved);
|
|
308
309
|
}
|
|
309
310
|
}
|
|
@@ -8,7 +8,7 @@ export const cliOptions = {
|
|
|
8
8
|
autoConnect: {
|
|
9
9
|
type: 'boolean',
|
|
10
10
|
description: '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 remoted debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.',
|
|
11
|
-
conflicts: ['isolated', 'executablePath'],
|
|
11
|
+
conflicts: ['isolated', 'executablePath', 'categoryExtensions'],
|
|
12
12
|
default: false,
|
|
13
13
|
coerce: (value) => {
|
|
14
14
|
if (!value) {
|
|
@@ -21,7 +21,7 @@ export const cliOptions = {
|
|
|
21
21
|
type: 'string',
|
|
22
22
|
description: 'Connect to a running, debuggable Chrome instance (e.g. `http://127.0.0.1:9222`). For more details see: https://github.com/ChromeDevTools/chrome-devtools-mcp#connecting-to-a-running-chrome-instance.',
|
|
23
23
|
alias: 'u',
|
|
24
|
-
conflicts: 'wsEndpoint',
|
|
24
|
+
conflicts: ['wsEndpoint', 'categoryExtensions'],
|
|
25
25
|
coerce: (url) => {
|
|
26
26
|
if (!url) {
|
|
27
27
|
return;
|
|
@@ -39,7 +39,7 @@ export const cliOptions = {
|
|
|
39
39
|
type: 'string',
|
|
40
40
|
description: 'WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/<id>). Alternative to --browserUrl.',
|
|
41
41
|
alias: 'w',
|
|
42
|
-
conflicts: 'browserUrl',
|
|
42
|
+
conflicts: ['browserUrl', 'categoryExtensions'],
|
|
43
43
|
coerce: (url) => {
|
|
44
44
|
if (!url) {
|
|
45
45
|
return;
|
|
@@ -193,9 +193,9 @@ export const cliOptions = {
|
|
|
193
193
|
},
|
|
194
194
|
categoryExtensions: {
|
|
195
195
|
type: 'boolean',
|
|
196
|
-
default: false,
|
|
197
196
|
hidden: true,
|
|
198
|
-
|
|
197
|
+
conflicts: ['browserUrl', 'autoConnect', 'wsEndpoint'],
|
|
198
|
+
describe: 'Set to true to include tools related to extensions. Note: This feature is only supported with a pipe connection. autoConnect is not supported.',
|
|
199
199
|
},
|
|
200
200
|
performanceCrux: {
|
|
201
201
|
type: 'boolean',
|
package/build/src/index.js
CHANGED
|
@@ -95,7 +95,7 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
if (tool.annotations.category === ToolCategory.EXTENSIONS &&
|
|
98
|
-
serverArgs.categoryExtensions
|
|
98
|
+
!serverArgs.categoryExtensions) {
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
101
|
if (tool.annotations.conditions?.includes('computerVision') &&
|
|
@@ -3117,7 +3117,6 @@ var ExperimentName;
|
|
|
3117
3117
|
ExperimentName["SHOW_OPTION_TO_EXPOSE_INTERNALS_IN_HEAP_SNAPSHOT"] = "show-option-to-expose-internals-in-heap-snapshot";
|
|
3118
3118
|
ExperimentName["TIMELINE_INVALIDATION_TRACKING"] = "timeline-invalidation-tracking";
|
|
3119
3119
|
ExperimentName["TIMELINE_SHOW_ALL_EVENTS"] = "timeline-show-all-events";
|
|
3120
|
-
ExperimentName["TIMELINE_V8_RUNTIME_CALL_STATS"] = "timeline-v8-runtime-call-stats";
|
|
3121
3120
|
ExperimentName["APCA"] = "apca";
|
|
3122
3121
|
ExperimentName["FONT_EDITOR"] = "font-editor";
|
|
3123
3122
|
ExperimentName["FULL_ACCESSIBILITY_TREE"] = "full-accessibility-tree";
|