chrome-devtools-mcp 0.18.0 → 0.18.1
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/McpContext.js +34 -1
- package/build/src/McpResponse.js +27 -0
- package/build/src/main.js +3 -1
- package/build/src/tools/memory.js +1 -2
- package/build/src/tools/pages.js +15 -13
- package/build/src/tools/tools.js +0 -1
- package/build/src/version.js +1 -1
- package/package.json +1 -1
package/build/src/McpContext.js
CHANGED
|
@@ -53,6 +53,7 @@ export class McpContext {
|
|
|
53
53
|
// Auto-generated name counter for when no name is provided.
|
|
54
54
|
#nextIsolatedContextId = 1;
|
|
55
55
|
#pages = [];
|
|
56
|
+
#extensionServiceWorkers = [];
|
|
56
57
|
#pageToDevToolsPage = new Map();
|
|
57
58
|
#selectedPage;
|
|
58
59
|
#textSnapshot = null;
|
|
@@ -66,6 +67,8 @@ export class McpContext {
|
|
|
66
67
|
#dialog;
|
|
67
68
|
#pageIdMap = new WeakMap();
|
|
68
69
|
#nextPageId = 1;
|
|
70
|
+
#extensionServiceWorkerMap = new WeakMap();
|
|
71
|
+
#nextExtensionServiceWorkerId = 1;
|
|
69
72
|
#nextSnapshotId = 1;
|
|
70
73
|
#traceResults = [];
|
|
71
74
|
#locatorClass;
|
|
@@ -94,6 +97,7 @@ export class McpContext {
|
|
|
94
97
|
}
|
|
95
98
|
async #init() {
|
|
96
99
|
const pages = await this.createPagesSnapshot();
|
|
100
|
+
await this.createExtensionServiceWorkersSnapshot();
|
|
97
101
|
await this.#networkCollector.init(pages);
|
|
98
102
|
await this.#consoleCollector.init(pages);
|
|
99
103
|
await this.#devtoolsUniverseManager.init(pages);
|
|
@@ -350,7 +354,7 @@ export class McpContext {
|
|
|
350
354
|
throw new Error('No page selected');
|
|
351
355
|
}
|
|
352
356
|
if (page.isClosed()) {
|
|
353
|
-
throw new Error(`The selected page has been closed. Call ${listPages.name} to see open pages.`);
|
|
357
|
+
throw new Error(`The selected page has been closed. Call ${listPages().name} to see open pages.`);
|
|
354
358
|
}
|
|
355
359
|
return page;
|
|
356
360
|
}
|
|
@@ -426,6 +430,29 @@ export class McpContext {
|
|
|
426
430
|
});
|
|
427
431
|
}
|
|
428
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Creates a snapshot of the extension service workers.
|
|
435
|
+
*/
|
|
436
|
+
async createExtensionServiceWorkersSnapshot() {
|
|
437
|
+
const allTargets = await this.browser.targets();
|
|
438
|
+
const serviceWorkers = allTargets.filter(target => {
|
|
439
|
+
return (target.type() === 'service_worker' &&
|
|
440
|
+
target.url().includes('chrome-extension://'));
|
|
441
|
+
});
|
|
442
|
+
for (const serviceWorker of serviceWorkers) {
|
|
443
|
+
if (!this.#extensionServiceWorkerMap.has(serviceWorker)) {
|
|
444
|
+
this.#extensionServiceWorkerMap.set(serviceWorker, 'sw-' + this.#nextExtensionServiceWorkerId++);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
this.#extensionServiceWorkers = serviceWorkers.map(serviceWorker => {
|
|
448
|
+
return {
|
|
449
|
+
target: serviceWorker,
|
|
450
|
+
id: this.#extensionServiceWorkerMap.get(serviceWorker),
|
|
451
|
+
url: serviceWorker.url(),
|
|
452
|
+
};
|
|
453
|
+
});
|
|
454
|
+
return this.#extensionServiceWorkers;
|
|
455
|
+
}
|
|
429
456
|
async createPagesSnapshot() {
|
|
430
457
|
const allPages = await this.#getAllPages();
|
|
431
458
|
for (const page of allPages) {
|
|
@@ -502,6 +529,12 @@ export class McpContext {
|
|
|
502
529
|
}
|
|
503
530
|
}
|
|
504
531
|
}
|
|
532
|
+
getExtensionServiceWorkers() {
|
|
533
|
+
return this.#extensionServiceWorkers;
|
|
534
|
+
}
|
|
535
|
+
getExtensionServiceWorkerId(extensionServiceWorker) {
|
|
536
|
+
return this.#extensionServiceWorkerMap.get(extensionServiceWorker.target);
|
|
537
|
+
}
|
|
505
538
|
getPages() {
|
|
506
539
|
return this.#pages;
|
|
507
540
|
}
|
package/build/src/McpResponse.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getInsightOutput, getTraceSummary } from './trace-processing/parse.js';
|
|
|
14
14
|
import { paginate } from './utils/pagination.js';
|
|
15
15
|
export class McpResponse {
|
|
16
16
|
#includePages = false;
|
|
17
|
+
#includeExtensionServiceWorkers = false;
|
|
17
18
|
#snapshotParams;
|
|
18
19
|
#attachedNetworkRequestId;
|
|
19
20
|
#attachedNetworkRequestOptions;
|
|
@@ -27,6 +28,10 @@ export class McpResponse {
|
|
|
27
28
|
#listExtensions;
|
|
28
29
|
#devToolsData;
|
|
29
30
|
#tabId;
|
|
31
|
+
#args;
|
|
32
|
+
constructor(args) {
|
|
33
|
+
this.#args = args;
|
|
34
|
+
}
|
|
30
35
|
attachDevToolsData(data) {
|
|
31
36
|
this.#devToolsData = data;
|
|
32
37
|
}
|
|
@@ -35,6 +40,9 @@ export class McpResponse {
|
|
|
35
40
|
}
|
|
36
41
|
setIncludePages(value) {
|
|
37
42
|
this.#includePages = value;
|
|
43
|
+
if (this.#args.categoryExtensions) {
|
|
44
|
+
this.#includeExtensionServiceWorkers = value;
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
includeSnapshot(params) {
|
|
40
48
|
this.#snapshotParams = params ?? {
|
|
@@ -142,6 +150,9 @@ export class McpResponse {
|
|
|
142
150
|
if (this.#includePages) {
|
|
143
151
|
await context.createPagesSnapshot();
|
|
144
152
|
}
|
|
153
|
+
if (this.#includeExtensionServiceWorkers) {
|
|
154
|
+
await context.createExtensionServiceWorkersSnapshot();
|
|
155
|
+
}
|
|
145
156
|
let snapshot;
|
|
146
157
|
if (this.#snapshotParams) {
|
|
147
158
|
await context.createTextSnapshot(this.#snapshotParams.verbose, this.#devToolsData);
|
|
@@ -345,6 +356,22 @@ Call ${handleDialog.name} to handle it before continuing.`);
|
|
|
345
356
|
return entry;
|
|
346
357
|
});
|
|
347
358
|
}
|
|
359
|
+
if (this.#includeExtensionServiceWorkers) {
|
|
360
|
+
if (!context.getExtensionServiceWorkers().length) {
|
|
361
|
+
response.push(`## Extension Service Workers`);
|
|
362
|
+
}
|
|
363
|
+
for (const extensionServiceWorker of context.getExtensionServiceWorkers()) {
|
|
364
|
+
response.push(`${extensionServiceWorker.id}: ${extensionServiceWorker.url}`);
|
|
365
|
+
}
|
|
366
|
+
structuredContent.extensionServiceWorkers = context
|
|
367
|
+
.getExtensionServiceWorkers()
|
|
368
|
+
.map(extensionServiceWorker => {
|
|
369
|
+
return {
|
|
370
|
+
id: extensionServiceWorker.id,
|
|
371
|
+
url: extensionServiceWorker.url,
|
|
372
|
+
};
|
|
373
|
+
});
|
|
374
|
+
}
|
|
348
375
|
if (this.#tabId) {
|
|
349
376
|
structuredContent.tabId = this.#tabId;
|
|
350
377
|
}
|
package/build/src/main.js
CHANGED
|
@@ -148,7 +148,9 @@ function registerTool(tool) {
|
|
|
148
148
|
const context = await getContext();
|
|
149
149
|
logger(`${tool.name} context: resolved`);
|
|
150
150
|
await context.detectOpenDevToolsWindows();
|
|
151
|
-
const response = args.slim
|
|
151
|
+
const response = args.slim
|
|
152
|
+
? new SlimMcpResponse(args)
|
|
153
|
+
: new McpResponse(args);
|
|
152
154
|
await tool.handler({
|
|
153
155
|
params,
|
|
154
156
|
}, response, context);
|
|
@@ -16,8 +16,7 @@ export const takeMemorySnapshot = defineTool({
|
|
|
16
16
|
schema: {
|
|
17
17
|
filePath: zod
|
|
18
18
|
.string()
|
|
19
|
-
.describe('A path to a .heapsnapshot file to save the heapsnapshot to.')
|
|
20
|
-
.endsWith('.heapsnapshot'),
|
|
19
|
+
.describe('A path to a .heapsnapshot file to save the heapsnapshot to.'),
|
|
21
20
|
},
|
|
22
21
|
handler: async (request, response, context) => {
|
|
23
22
|
const page = context.getSelectedPage();
|
package/build/src/tools/pages.js
CHANGED
|
@@ -7,17 +7,19 @@ import { logger } from '../logger.js';
|
|
|
7
7
|
import { zod } from '../third_party/index.js';
|
|
8
8
|
import { ToolCategory } from './categories.js';
|
|
9
9
|
import { CLOSE_PAGE_ERROR, defineTool, timeoutSchema } from './ToolDefinition.js';
|
|
10
|
-
export const listPages = defineTool({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
response
|
|
20
|
-
|
|
10
|
+
export const listPages = defineTool(args => {
|
|
11
|
+
return {
|
|
12
|
+
name: 'list_pages',
|
|
13
|
+
description: `Get a list of pages ${args?.categoryExtensions ? 'including extension service workers' : ''} open in the browser.`,
|
|
14
|
+
annotations: {
|
|
15
|
+
category: ToolCategory.NAVIGATION,
|
|
16
|
+
readOnlyHint: true,
|
|
17
|
+
},
|
|
18
|
+
schema: {},
|
|
19
|
+
handler: async (_request, response) => {
|
|
20
|
+
response.setIncludePages(true);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
21
23
|
});
|
|
22
24
|
export const selectPage = defineTool({
|
|
23
25
|
name: 'select_page',
|
|
@@ -29,7 +31,7 @@ export const selectPage = defineTool({
|
|
|
29
31
|
schema: {
|
|
30
32
|
pageId: zod
|
|
31
33
|
.number()
|
|
32
|
-
.describe(`The ID of the page to select. Call ${listPages.name} to get available pages.`),
|
|
34
|
+
.describe(`The ID of the page to select. Call ${listPages().name} to get available pages.`),
|
|
33
35
|
bringToFront: zod
|
|
34
36
|
.boolean()
|
|
35
37
|
.optional()
|
|
@@ -318,7 +320,7 @@ export const getTabId = defineTool({
|
|
|
318
320
|
schema: {
|
|
319
321
|
pageId: zod
|
|
320
322
|
.number()
|
|
321
|
-
.describe(`The ID of the page to get the tab ID for. Call ${listPages.name} to get available pages.`),
|
|
323
|
+
.describe(`The ID of the page to get the tab ID for. Call ${listPages().name} to get available pages.`),
|
|
322
324
|
},
|
|
323
325
|
handler: async (request, response, context) => {
|
|
324
326
|
const page = context.getPageById(request.params.pageId);
|
package/build/src/tools/tools.js
CHANGED
|
@@ -36,7 +36,6 @@ export const createTools = (args) => {
|
|
|
36
36
|
const tools = [];
|
|
37
37
|
for (const tool of rawTools) {
|
|
38
38
|
if (typeof tool === 'function') {
|
|
39
|
-
// @ts-expect-error none of the tools for now implement the function type tool has type "never"
|
|
40
39
|
tools.push(tool(args));
|
|
41
40
|
}
|
|
42
41
|
else {
|
package/build/src/version.js
CHANGED