chrome-devtools-mcp 1.1.0 → 1.2.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 +12 -3
- package/build/src/DevtoolsUtils.js +57 -0
- package/build/src/HeapSnapshotManager.js +5 -0
- package/build/src/McpContext.js +28 -8
- package/build/src/McpPage.js +9 -9
- package/build/src/McpResponse.js +101 -53
- package/build/src/PageCollector.js +7 -7
- package/build/src/ServiceWorkerCollector.js +171 -0
- package/build/src/TextSnapshot.js +1 -1
- package/build/src/ToolHandler.js +11 -5
- package/build/src/WaitForHelper.js +2 -2
- package/build/src/bin/chrome-devtools-cli-options.js +22 -4
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +19 -4
- 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/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 +30 -0
- package/build/src/third_party/bundled-packages.json +2 -1
- package/build/src/third_party/devtools-formatter-worker.js +1 -0
- package/build/src/third_party/devtools-heap-snapshot-worker.js +107 -0
- package/build/src/third_party/index.js +5906 -4913
- 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 +33 -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 +2 -1
- package/build/src/tools/screenshot.js +1 -1
- package/build/src/tools/script.js +2 -2
- 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 +14 -13
package/build/src/tools/pages.js
CHANGED
|
@@ -22,7 +22,7 @@ async function navigateWithInterception(page, action, allowListString, timeout)
|
|
|
22
22
|
void interceptedRequest.continue();
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
|
-
logger(`Blocking request to: ${requestUrl}`);
|
|
25
|
+
logger?.(`Blocking request to: ${requestUrl}`);
|
|
26
26
|
void interceptedRequest.abort('blockedbyclient');
|
|
27
27
|
}
|
|
28
28
|
};
|
|
@@ -30,7 +30,7 @@ async function navigateWithInterception(page, action, allowListString, timeout)
|
|
|
30
30
|
if (allowList) {
|
|
31
31
|
page.pptrPage.off('request', requestHandler);
|
|
32
32
|
await page.pptrPage.setRequestInterception(false).catch(error => {
|
|
33
|
-
logger(`Failed to disable request interception`, error);
|
|
33
|
+
logger?.(`Failed to disable request interception`, error);
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
};
|
|
@@ -62,6 +62,7 @@ export const listPages = defineTool(args => {
|
|
|
62
62
|
},
|
|
63
63
|
schema: {},
|
|
64
64
|
blockedByDialog: false,
|
|
65
|
+
verifyFilesSchema: [],
|
|
65
66
|
handler: async (_request, response) => {
|
|
66
67
|
response.setIncludePages(true);
|
|
67
68
|
response.setListThirdPartyDeveloperTools();
|
|
@@ -86,6 +87,7 @@ export const selectPage = defineTool({
|
|
|
86
87
|
.describe('Whether to focus the page and bring it to the top.'),
|
|
87
88
|
},
|
|
88
89
|
blockedByDialog: false,
|
|
90
|
+
verifyFilesSchema: [],
|
|
89
91
|
handler: async (request, response, context) => {
|
|
90
92
|
const page = context.getPageById(request.params.pageId);
|
|
91
93
|
context.selectPage(page);
|
|
@@ -110,6 +112,7 @@ export const closePage = defineTool({
|
|
|
110
112
|
.describe('The ID of the page to close. Call list_pages to list pages.'),
|
|
111
113
|
},
|
|
112
114
|
blockedByDialog: false,
|
|
115
|
+
verifyFilesSchema: [],
|
|
113
116
|
handler: async (request, response, context) => {
|
|
114
117
|
try {
|
|
115
118
|
await context.closePage(request.params.pageId);
|
|
@@ -157,6 +160,7 @@ export const newPage = defineTool(args => {
|
|
|
157
160
|
...timeoutSchema,
|
|
158
161
|
},
|
|
159
162
|
blockedByDialog: false,
|
|
163
|
+
verifyFilesSchema: [],
|
|
160
164
|
handler: async (request, response, context) => {
|
|
161
165
|
const page = await context.newPage(request.params.background, request.params.isolatedContext);
|
|
162
166
|
await navigateWithInterception(page, () => page.pptrPage.goto(request.params.url, {
|
|
@@ -204,6 +208,7 @@ export const navigatePage = definePageTool(args => {
|
|
|
204
208
|
...timeoutSchema,
|
|
205
209
|
},
|
|
206
210
|
blockedByDialog: false,
|
|
211
|
+
verifyFilesSchema: [],
|
|
207
212
|
handler: async (request, response) => {
|
|
208
213
|
const page = request.page;
|
|
209
214
|
const options = {
|
|
@@ -290,7 +295,7 @@ export const navigatePage = definePageTool(args => {
|
|
|
290
295
|
await page.pptrPage
|
|
291
296
|
.removeScriptToEvaluateOnNewDocument(initScriptId)
|
|
292
297
|
.catch(error => {
|
|
293
|
-
logger(`Failed to remove init script`, error);
|
|
298
|
+
logger?.(`Failed to remove init script`, error);
|
|
294
299
|
});
|
|
295
300
|
}
|
|
296
301
|
}
|
|
@@ -312,6 +317,7 @@ export const resizePage = definePageTool({
|
|
|
312
317
|
height: zod.number().describe('Page height'),
|
|
313
318
|
},
|
|
314
319
|
blockedByDialog: false,
|
|
320
|
+
verifyFilesSchema: [],
|
|
315
321
|
handler: async (request, response, _context) => {
|
|
316
322
|
const page = request.page;
|
|
317
323
|
try {
|
|
@@ -354,6 +360,7 @@ export const handleDialog = definePageTool({
|
|
|
354
360
|
.describe('Optional prompt text to enter into the dialog.'),
|
|
355
361
|
},
|
|
356
362
|
blockedByDialog: false,
|
|
363
|
+
verifyFilesSchema: [],
|
|
357
364
|
handler: async (request, response, _context) => {
|
|
358
365
|
const page = request.page;
|
|
359
366
|
const dialog = page.getDialog();
|
|
@@ -367,7 +374,7 @@ export const handleDialog = definePageTool({
|
|
|
367
374
|
}
|
|
368
375
|
catch (err) {
|
|
369
376
|
// Likely already handled by the user outside of MCP.
|
|
370
|
-
logger(err);
|
|
377
|
+
logger?.(err);
|
|
371
378
|
}
|
|
372
379
|
response.appendResponseLine('Successfully accepted the dialog');
|
|
373
380
|
break;
|
|
@@ -378,7 +385,7 @@ export const handleDialog = definePageTool({
|
|
|
378
385
|
}
|
|
379
386
|
catch (err) {
|
|
380
387
|
// Likely already handled.
|
|
381
|
-
logger(err);
|
|
388
|
+
logger?.(err);
|
|
382
389
|
}
|
|
383
390
|
response.appendResponseLine('Successfully dismissed the dialog');
|
|
384
391
|
break;
|
|
@@ -402,6 +409,7 @@ export const getTabId = definePageTool({
|
|
|
402
409
|
.describe(`The ID of the page to get the tab ID for. Call ${listPages().name} to get available pages.`),
|
|
403
410
|
},
|
|
404
411
|
blockedByDialog: false,
|
|
412
|
+
verifyFilesSchema: [],
|
|
405
413
|
handler: async (request, response, context) => {
|
|
406
414
|
const page = context.getPageById(request.params.pageId);
|
|
407
415
|
const tabId = page.pptrPage._tabId;
|
|
@@ -32,8 +32,8 @@ export const startTrace = definePageTool({
|
|
|
32
32
|
filePath: filePathSchema,
|
|
33
33
|
},
|
|
34
34
|
blockedByDialog: true,
|
|
35
|
+
verifyFilesSchema: ['filePath'],
|
|
35
36
|
handler: async (request, response, context) => {
|
|
36
|
-
await context.validatePath(request.params.filePath);
|
|
37
37
|
if (context.isRunningPerformanceTrace()) {
|
|
38
38
|
response.appendResponseLine('Error: a performance trace is already running. Use performance_stop_trace to stop it. Only one trace can be running at any given time.');
|
|
39
39
|
return;
|
|
@@ -96,8 +96,8 @@ export const stopTrace = definePageTool({
|
|
|
96
96
|
filePath: filePathSchema,
|
|
97
97
|
},
|
|
98
98
|
blockedByDialog: true,
|
|
99
|
+
verifyFilesSchema: ['filePath'],
|
|
99
100
|
handler: async (request, response, context) => {
|
|
100
|
-
await context.validatePath(request.params.filePath);
|
|
101
101
|
if (!context.isRunningPerformanceTrace()) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
@@ -121,6 +121,7 @@ export const analyzeInsight = definePageTool({
|
|
|
121
121
|
.describe('The name of the Insight you want more information on. For example: "DocumentLatency" or "LCPBreakdown"'),
|
|
122
122
|
},
|
|
123
123
|
blockedByDialog: false,
|
|
124
|
+
verifyFilesSchema: [],
|
|
124
125
|
handler: async (request, response, context) => {
|
|
125
126
|
const lastRecording = context.recordedTraces().at(-1);
|
|
126
127
|
if (!lastRecording) {
|
|
@@ -172,8 +173,8 @@ async function stopTracingAndAppendOutput(page, response, context, filePath) {
|
|
|
172
173
|
}
|
|
173
174
|
/** We tell CrUXManager to fetch data so it's available when DevTools.PerformanceTraceFormatter is invoked */
|
|
174
175
|
async function populateCruxData(result) {
|
|
175
|
-
logger('populateCruxData called');
|
|
176
|
-
const cruxManager = DevTools.CrUXManager.instance();
|
|
176
|
+
logger?.('populateCruxData called');
|
|
177
|
+
const cruxManager = DevTools.CrUXManager.CrUXManager.instance();
|
|
177
178
|
// go/jtfbx. Yes, we're aware this API key is public. ;)
|
|
178
179
|
cruxManager.setEndpointForTesting('https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=AIzaSyBn5gimNjhiEyA_euicSKko6IlD3HdgUfk');
|
|
179
180
|
const cruxSetting = DevTools.Common.Settings.Settings.instance().createSetting('field-data', {
|
|
@@ -185,13 +186,13 @@ async function populateCruxData(result) {
|
|
|
185
186
|
urls.push(result.parsedTrace.data.Meta.mainFrameURL);
|
|
186
187
|
const urlSet = new Set(urls);
|
|
187
188
|
if (urlSet.size === 0) {
|
|
188
|
-
logger('No URLs found for CrUX data');
|
|
189
|
+
logger?.('No URLs found for CrUX data');
|
|
189
190
|
return;
|
|
190
191
|
}
|
|
191
|
-
logger(`Fetching CrUX data for ${urlSet.size} URLs: ${Array.from(urlSet).join(', ')}`);
|
|
192
|
+
logger?.(`Fetching CrUX data for ${urlSet.size} URLs: ${Array.from(urlSet).join(', ')}`);
|
|
192
193
|
const cruxData = await Promise.all(Array.from(urlSet).map(async (url) => {
|
|
193
194
|
const data = await cruxManager.getFieldDataForPage(url);
|
|
194
|
-
logger(`CrUX data for ${url}: ${data ? 'found' : 'not found'}`);
|
|
195
|
+
logger?.(`CrUX data for ${url}: ${data ? 'found' : 'not found'}`);
|
|
195
196
|
return data;
|
|
196
197
|
}));
|
|
197
198
|
result.parsedTrace.metadata.cruxFieldData = cruxData;
|
|
@@ -30,8 +30,8 @@ export const startScreencast = definePageTool(args => ({
|
|
|
30
30
|
.describe(`Output file path (${supportedExtensions.join(',')} are supported). Uses mkdtemp to generate a unique path if not provided.`),
|
|
31
31
|
},
|
|
32
32
|
blockedByDialog: false,
|
|
33
|
+
verifyFilesSchema: ['filePath'],
|
|
33
34
|
handler: async (request, response, context) => {
|
|
34
|
-
await context.validatePath(request.params.filePath);
|
|
35
35
|
if (context.getScreenRecorder() !== null) {
|
|
36
36
|
response.appendResponseLine('Error: a screencast recording is already in progress. Use screencast_stop to stop it before starting a new one.');
|
|
37
37
|
return;
|
|
@@ -78,6 +78,7 @@ export const stopScreencast = definePageTool({
|
|
|
78
78
|
},
|
|
79
79
|
schema: {},
|
|
80
80
|
blockedByDialog: false,
|
|
81
|
+
verifyFilesSchema: [],
|
|
81
82
|
handler: async (_request, response, context) => {
|
|
82
83
|
const data = context.getScreenRecorder();
|
|
83
84
|
if (!data) {
|
|
@@ -39,8 +39,8 @@ export const screenshot = definePageTool({
|
|
|
39
39
|
.describe('The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.'),
|
|
40
40
|
},
|
|
41
41
|
blockedByDialog: true,
|
|
42
|
+
verifyFilesSchema: ['filePath'],
|
|
42
43
|
handler: async (request, response, context) => {
|
|
43
|
-
await context.validatePath(request.params.filePath);
|
|
44
44
|
if (request.params.uid && request.params.fullPage) {
|
|
45
45
|
throw new Error('Providing both "uid" and "fullPage" is not allowed.');
|
|
46
46
|
}
|
|
@@ -16,6 +16,7 @@ so returned values have to be JSON-serializable.`,
|
|
|
16
16
|
readOnlyHint: false,
|
|
17
17
|
},
|
|
18
18
|
schema: {
|
|
19
|
+
...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}),
|
|
19
20
|
function: zod.string().describe(`A JavaScript function declaration to be executed by the tool in the currently selected page.
|
|
20
21
|
Example without arguments: \`() => {
|
|
21
22
|
return document.title
|
|
@@ -40,7 +41,6 @@ Example with arguments: \`(el) => {
|
|
|
40
41
|
.string()
|
|
41
42
|
.optional()
|
|
42
43
|
.describe('Handle dialogs while execution. "accept", "dismiss", or string for response of window.prompt. Defaults to accept.'),
|
|
43
|
-
...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}),
|
|
44
44
|
...(cliArgs?.categoryExtensions
|
|
45
45
|
? {
|
|
46
46
|
serviceWorkerId: zod
|
|
@@ -51,9 +51,9 @@ Example with arguments: \`(el) => {
|
|
|
51
51
|
: {}),
|
|
52
52
|
},
|
|
53
53
|
blockedByDialog: true,
|
|
54
|
+
verifyFilesSchema: ['filePath'],
|
|
54
55
|
handler: async (request, response, context) => {
|
|
55
56
|
const { serviceWorkerId, args: uidArgs, function: fnString, pageId, dialogAction, filePath, } = request.params;
|
|
56
|
-
await context.validatePath(filePath);
|
|
57
57
|
if (cliArgs?.categoryExtensions && serviceWorkerId) {
|
|
58
58
|
if (uidArgs && uidArgs.length > 0) {
|
|
59
59
|
throw new Error('args (element uids) cannot be used when evaluating in a service worker.');
|
|
@@ -16,6 +16,7 @@ export const screenshot = definePageTool({
|
|
|
16
16
|
},
|
|
17
17
|
schema: {},
|
|
18
18
|
blockedByDialog: true,
|
|
19
|
+
verifyFilesSchema: [],
|
|
19
20
|
handler: async (request, response, context) => {
|
|
20
21
|
const page = request.page;
|
|
21
22
|
const screenshot = await page.pptrPage.screenshot({
|
|
@@ -37,6 +38,7 @@ export const navigate = definePageTool({
|
|
|
37
38
|
url: zod.string().describe('URL to navigate to'),
|
|
38
39
|
},
|
|
39
40
|
blockedByDialog: false,
|
|
41
|
+
verifyFilesSchema: [],
|
|
40
42
|
handler: async (request, response) => {
|
|
41
43
|
const page = request.page;
|
|
42
44
|
const options = {
|
|
@@ -71,6 +73,7 @@ export const evaluate = definePageTool({
|
|
|
71
73
|
script: zod.string().describe(`JS script to run on the page`),
|
|
72
74
|
},
|
|
73
75
|
blockedByDialog: true,
|
|
76
|
+
verifyFilesSchema: [],
|
|
74
77
|
handler: async (request, response) => {
|
|
75
78
|
const page = request.page;
|
|
76
79
|
try {
|
|
@@ -27,8 +27,8 @@ in the DevTools Elements panel (if any).`,
|
|
|
27
27
|
.describe('The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.'),
|
|
28
28
|
},
|
|
29
29
|
blockedByDialog: true,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
verifyFilesSchema: ['filePath'],
|
|
31
|
+
handler: async (request, response) => {
|
|
32
32
|
response.includeSnapshot({
|
|
33
33
|
verbose: request.params.verbose ?? false,
|
|
34
34
|
filePath: request.params.filePath,
|
|
@@ -50,6 +50,7 @@ export const waitFor = definePageTool({
|
|
|
50
50
|
...timeoutSchema,
|
|
51
51
|
},
|
|
52
52
|
blockedByDialog: true,
|
|
53
|
+
verifyFilesSchema: [],
|
|
53
54
|
handler: async (request, response, context) => {
|
|
54
55
|
const page = request.page;
|
|
55
56
|
await context.waitForTextOnPage(request.params.text, request.params.timeout, page.pptrPage);
|
|
@@ -21,6 +21,7 @@ export const listThirdPartyDeveloperTools = definePageTool({
|
|
|
21
21
|
},
|
|
22
22
|
schema: {},
|
|
23
23
|
blockedByDialog: false,
|
|
24
|
+
verifyFilesSchema: [],
|
|
24
25
|
handler: async (_request, response, _context) => {
|
|
25
26
|
response.setListThirdPartyDeveloperTools();
|
|
26
27
|
},
|
|
@@ -40,6 +41,7 @@ export const executeThirdPartyDeveloperTool = definePageTool({
|
|
|
40
41
|
.describe('The JSON-stringified parameters to pass to the tool'),
|
|
41
42
|
},
|
|
42
43
|
blockedByDialog: false,
|
|
44
|
+
verifyFilesSchema: [],
|
|
43
45
|
handler: async (request, response) => {
|
|
44
46
|
const toolName = request.params.toolName;
|
|
45
47
|
let params = {};
|
|
@@ -58,8 +60,16 @@ export const executeThirdPartyDeveloperTool = definePageTool({
|
|
|
58
60
|
throw new Error(`Failed to parse params as JSON: ${errorMessage}`);
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
+
const toolGroups = request.page.getThirdPartyDeveloperTools();
|
|
64
|
+
let tool;
|
|
65
|
+
if (toolGroups) {
|
|
66
|
+
for (const group of toolGroups) {
|
|
67
|
+
tool = group.tools?.find(t => t.name === toolName);
|
|
68
|
+
if (tool) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
63
73
|
if (!tool) {
|
|
64
74
|
throw new Error(`Tool ${toolName} not found`);
|
|
65
75
|
}
|
|
@@ -15,6 +15,7 @@ export const listWebMcpTools = definePageTool({
|
|
|
15
15
|
},
|
|
16
16
|
schema: {},
|
|
17
17
|
blockedByDialog: false,
|
|
18
|
+
verifyFilesSchema: [],
|
|
18
19
|
handler: async (_request, response, _context) => {
|
|
19
20
|
response.setListWebMcpTools();
|
|
20
21
|
},
|
|
@@ -34,6 +35,7 @@ export const executeWebMcpTool = definePageTool({
|
|
|
34
35
|
.describe('The JSON-stringified parameters to pass to the WebMCP tool'),
|
|
35
36
|
},
|
|
36
37
|
blockedByDialog: false,
|
|
38
|
+
verifyFilesSchema: [],
|
|
37
39
|
handler: async (request, response) => {
|
|
38
40
|
const toolName = request.params.toolName;
|
|
39
41
|
let input = {};
|
|
@@ -40,7 +40,7 @@ export async function parseRawTraceBuffer(buffer, metadata) {
|
|
|
40
40
|
}
|
|
41
41
|
catch (e) {
|
|
42
42
|
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
|
|
43
|
-
logger(`Unexpected error parsing trace: ${errorText}`);
|
|
43
|
+
logger?.(`Unexpected error parsing trace: ${errorText}`);
|
|
44
44
|
return {
|
|
45
45
|
error: errorText,
|
|
46
46
|
};
|
|
@@ -51,9 +51,9 @@ const extraFormatDescriptions = `Information on performance traces may contain m
|
|
|
51
51
|
${DevTools.PerformanceTraceFormatter.callFrameDataFormatDescription}
|
|
52
52
|
|
|
53
53
|
${DevTools.PerformanceTraceFormatter.networkDataFormatDescription}`;
|
|
54
|
-
export function getTraceSummary(result) {
|
|
54
|
+
export function getTraceSummary(result, deviceScope) {
|
|
55
55
|
const focus = DevTools.AgentFocus.fromParsedTrace(result.parsedTrace);
|
|
56
|
-
const formatter = new DevTools.PerformanceTraceFormatter(focus);
|
|
56
|
+
const formatter = new DevTools.PerformanceTraceFormatter(focus, deviceScope);
|
|
57
57
|
const summaryText = formatter.formatTraceSummary();
|
|
58
58
|
return `## Summary of Performance trace findings:
|
|
59
59
|
${summaryText}
|
|
@@ -61,7 +61,7 @@ ${summaryText}
|
|
|
61
61
|
## Details on call tree & network request formats:
|
|
62
62
|
${extraFormatDescriptions}`;
|
|
63
63
|
}
|
|
64
|
-
export function getInsightOutput(result, insightSetId, insightName) {
|
|
64
|
+
export function getInsightOutput(result, insightSetId, insightName, deviceScope) {
|
|
65
65
|
if (!result.insights) {
|
|
66
66
|
return {
|
|
67
67
|
error: 'No Performance insights are available for this trace.',
|
|
@@ -79,7 +79,7 @@ export function getInsightOutput(result, insightSetId, insightName) {
|
|
|
79
79
|
error: `No Insight with the name ${insightName} found. Double check the name you provided is accurate and try again.`,
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
|
-
const formatter = new DevTools.PerformanceInsightFormatter(DevTools.AgentFocus.fromParsedTrace(result.parsedTrace), matchingInsight);
|
|
82
|
+
const formatter = new DevTools.PerformanceInsightFormatter(DevTools.AgentFocus.fromParsedTrace(result.parsedTrace), matchingInsight, deviceScope);
|
|
83
83
|
return { output: formatter.formatInsight() };
|
|
84
84
|
}
|
|
85
85
|
//# sourceMappingURL=parse.js.map
|
package/build/src/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP server for Chrome DevTools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,28 +9,28 @@
|
|
|
9
9
|
},
|
|
10
10
|
"main": "./build/src/index.js",
|
|
11
11
|
"scripts": {
|
|
12
|
-
"cli:generate": "node
|
|
12
|
+
"cli:generate": "node scripts/generate-cli.ts",
|
|
13
13
|
"clean": "node -e \"require('fs').rmSync('build', {recursive: true, force: true})\"",
|
|
14
|
-
"bundle": "npm run clean && npm run build && rollup -c rollup.config.mjs && node -e \"require('fs').rmSync('build/node_modules', {recursive: true, force: true})\" && node
|
|
15
|
-
"build": "tsc && node
|
|
14
|
+
"bundle": "npm run clean && npm run build && rollup -c rollup.config.mjs && node -e \"require('fs').rmSync('build/node_modules', {recursive: true, force: true})\" && node scripts/append-lighthouse-notices.ts",
|
|
15
|
+
"build": "tsc && node scripts/post-build.ts",
|
|
16
16
|
"typecheck": "tsc --noEmit",
|
|
17
17
|
"format": "eslint --cache --fix . && prettier --write --cache .",
|
|
18
18
|
"check-format": "eslint --cache . && prettier --check --cache .;",
|
|
19
19
|
"gen": "npm run build && npm run docs:generate && npm run cli:generate && npm run update-metrics && npm run format",
|
|
20
|
-
"docs:generate": "node
|
|
20
|
+
"docs:generate": "node scripts/generate-docs.ts",
|
|
21
21
|
"start": "npm run build && node build/src/bin/chrome-devtools-mcp.js",
|
|
22
22
|
"start-debug": "DEBUG=mcp:* DEBUG_COLORS=false npm run build && node build/src/bin/chrome-devtools-mcp.js",
|
|
23
23
|
"test": "npm run build && node scripts/test.mjs",
|
|
24
24
|
"test:no-build": "node scripts/test.mjs",
|
|
25
25
|
"test:only": "npm run build && node scripts/test.mjs --test-only",
|
|
26
26
|
"test:update-snapshots": "npm run build && node scripts/test.mjs --test-update-snapshots",
|
|
27
|
-
"prepare": "node
|
|
28
|
-
"verify-server-json-version": "node
|
|
29
|
-
"update-lighthouse": "node
|
|
30
|
-
"update-metrics": "node
|
|
27
|
+
"prepare": "node scripts/prepare.ts",
|
|
28
|
+
"verify-server-json-version": "node scripts/verify-server-json-version.ts",
|
|
29
|
+
"update-lighthouse": "node scripts/update-lighthouse.ts",
|
|
30
|
+
"update-metrics": "node scripts/update_metrics.ts",
|
|
31
31
|
"verify-npm-package": "node scripts/verify-npm-package.mjs",
|
|
32
|
-
"eval": "npm run build && node
|
|
33
|
-
"count-tokens": "node
|
|
32
|
+
"eval": "npm run build && node scripts/eval_gemini.ts",
|
|
33
|
+
"count-tokens": "node scripts/count_tokens.ts"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"build/src",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"@rollup/plugin-json": "^6.1.0",
|
|
55
55
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
56
56
|
"@stylistic/eslint-plugin": "^5.4.0",
|
|
57
|
+
"@toon-format/toon": "^2.2.0",
|
|
57
58
|
"@types/debug": "^4.1.12",
|
|
58
59
|
"@types/filesystem": "^0.0.36",
|
|
59
60
|
"@types/node": "^25.0.0",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"@types/yargs": "^17.0.33",
|
|
63
64
|
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
|
64
65
|
"@typescript-eslint/parser": "^8.43.0",
|
|
65
|
-
"chrome-devtools-frontend": "1.0.
|
|
66
|
+
"chrome-devtools-frontend": "1.0.1641723",
|
|
66
67
|
"core-js": "3.49.0",
|
|
67
68
|
"debug": "4.4.3",
|
|
68
69
|
"eslint": "^9.35.0",
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
"lighthouse": "13.3.0",
|
|
73
74
|
"prettier": "^3.6.2",
|
|
74
75
|
"puppeteer": "25.1.0",
|
|
75
|
-
"rollup": "4.
|
|
76
|
+
"rollup": "4.61.0",
|
|
76
77
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
77
78
|
"rollup-plugin-license": "^3.6.0",
|
|
78
79
|
"semver": "^7.7.4",
|