chrome-devtools-mcp 0.6.0 → 0.7.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 +13 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Color.js +13 -9
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ColorConverter.js +9 -7
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/MapWithDefault.js +5 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ResourceType.js +0 -11
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ReturnToPanel.js +6 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/AidaClient.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/GdpClient.js +116 -59
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/Platform.js +5 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +6 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/StringUtilities.js +33 -31
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMetadata.js +4 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSPropertyParser.js +11 -9
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSPropertyParserMatchers.js +19 -13
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js +30 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/EventBreakpointsModel.js +4 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/HttpReasonPhraseStrings.js +4 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +9 -41
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +0 -14
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PageResourceLoader.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PreloadingModel.js +7 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RemoteObject.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ScreenCaptureModel.js +20 -18
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Target.js +7 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +4 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js +30 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIContext.js +18 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/crux-manager/CrUXManager.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/network_time_calculator/RequestTimeRanges.js +6 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +7 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/LanternComputationData.js +1 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/FramesHandler.js +7 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +8 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +17 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/helpers.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Timing.js +4 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Trace.js +8 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +10 -10
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +12 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +11 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +5 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/SourceMapsResolver.js +1 -1
- package/build/src/McpContext.js +24 -7
- package/build/src/McpResponse.js +49 -20
- package/build/src/Mutex.js +3 -6
- package/build/src/browser.js +6 -5
- package/build/src/cli.js +10 -2
- package/build/src/formatters/consoleFormatter.js +1 -1
- package/build/src/formatters/networkFormatter.js +44 -0
- package/build/src/tools/emulation.js +13 -2
- package/build/src/tools/performance.js +3 -4
- package/build/src/tools/screenshot.js +2 -3
- package/build/src/trace-processing/parse.js +7 -6
- package/package.json +7 -6
package/build/src/browser.js
CHANGED
|
@@ -27,8 +27,6 @@ function targetFilter(target) {
|
|
|
27
27
|
}
|
|
28
28
|
const connectOptions = {
|
|
29
29
|
targetFilter,
|
|
30
|
-
// We do not expect any single CDP command to take more than 10sec.
|
|
31
|
-
protocolTimeout: 10_000,
|
|
32
30
|
};
|
|
33
31
|
export async function ensureBrowserConnected(browserURL) {
|
|
34
32
|
if (browser?.connected) {
|
|
@@ -60,9 +58,12 @@ export async function launch(options) {
|
|
|
60
58
|
if (customDevTools) {
|
|
61
59
|
args.push(`--custom-devtools-frontend=file://${customDevTools}`);
|
|
62
60
|
}
|
|
63
|
-
|
|
61
|
+
if (headless) {
|
|
62
|
+
args.push('--screen-info={3840x2160}');
|
|
63
|
+
}
|
|
64
|
+
let puppeteerChannel;
|
|
64
65
|
if (!executablePath) {
|
|
65
|
-
|
|
66
|
+
puppeteerChannel =
|
|
66
67
|
channel && channel !== 'stable'
|
|
67
68
|
? `chrome-${channel}`
|
|
68
69
|
: 'chrome';
|
|
@@ -70,7 +71,7 @@ export async function launch(options) {
|
|
|
70
71
|
try {
|
|
71
72
|
const browser = await puppeteer.launch({
|
|
72
73
|
...connectOptions,
|
|
73
|
-
channel:
|
|
74
|
+
channel: puppeteerChannel,
|
|
74
75
|
executablePath,
|
|
75
76
|
defaultViewport: null,
|
|
76
77
|
userDataDir,
|
package/build/src/cli.js
CHANGED
|
@@ -11,7 +11,15 @@ export const cliOptions = {
|
|
|
11
11
|
description: 'Connect to a running Chrome instance using port forwarding. For more details see: https://developer.chrome.com/docs/devtools/remote-debugging/local-server.',
|
|
12
12
|
alias: 'u',
|
|
13
13
|
coerce: (url) => {
|
|
14
|
-
|
|
14
|
+
if (!url) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
new URL(url);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error(`Provided browserUrl ${url} is not valid URL.`);
|
|
22
|
+
}
|
|
15
23
|
return url;
|
|
16
24
|
},
|
|
17
25
|
},
|
|
@@ -50,7 +58,7 @@ export const cliOptions = {
|
|
|
50
58
|
},
|
|
51
59
|
viewport: {
|
|
52
60
|
type: 'string',
|
|
53
|
-
describe: 'Initial viewport size for the
|
|
61
|
+
describe: 'Initial viewport size for the Chrome instances started by the server. For example, `1280x720`. In headless mode, max size is 3840x2160px.',
|
|
54
62
|
coerce: (arg) => {
|
|
55
63
|
if (arg === undefined) {
|
|
56
64
|
return;
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
+
import { isUtf8 } from 'node:buffer';
|
|
7
|
+
const BODY_CONTEXT_SIZE_LIMIT = 10000;
|
|
6
8
|
export function getShortDescriptionForRequest(request) {
|
|
7
9
|
return `${request.url()} ${request.method()} ${getStatusFromRequest(request)}`;
|
|
8
10
|
}
|
|
@@ -32,3 +34,45 @@ export function getFormattedHeaderValue(headers) {
|
|
|
32
34
|
}
|
|
33
35
|
return response;
|
|
34
36
|
}
|
|
37
|
+
export async function getFormattedResponseBody(httpResponse, sizeLimit = BODY_CONTEXT_SIZE_LIMIT) {
|
|
38
|
+
try {
|
|
39
|
+
const responseBuffer = await httpResponse.buffer();
|
|
40
|
+
if (isUtf8(responseBuffer)) {
|
|
41
|
+
const responseAsTest = responseBuffer.toString('utf-8');
|
|
42
|
+
if (responseAsTest.length === 0) {
|
|
43
|
+
return `<empty response>`;
|
|
44
|
+
}
|
|
45
|
+
return `${getSizeLimitedString(responseAsTest, sizeLimit)}`;
|
|
46
|
+
}
|
|
47
|
+
return `<binary data>`;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// buffer() call might fail with CDP exception, in this case we don't print anything in the context
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function getFormattedRequestBody(httpRequest, sizeLimit = BODY_CONTEXT_SIZE_LIMIT) {
|
|
55
|
+
if (httpRequest.hasPostData()) {
|
|
56
|
+
const data = httpRequest.postData();
|
|
57
|
+
if (data) {
|
|
58
|
+
return `${getSizeLimitedString(data, sizeLimit)}`;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const fetchData = await httpRequest.fetchPostData();
|
|
62
|
+
if (fetchData) {
|
|
63
|
+
return `${getSizeLimitedString(fetchData, sizeLimit)}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// fetchPostData() call might fail with CDP exception, in this case we don't print anything in the context
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
function getSizeLimitedString(text, sizeLimit) {
|
|
74
|
+
if (text.length > sizeLimit) {
|
|
75
|
+
return `${text.substring(0, sizeLimit) + '... <truncated>'}`;
|
|
76
|
+
}
|
|
77
|
+
return `${text}`;
|
|
78
|
+
}
|
|
@@ -9,11 +9,12 @@ import { ToolCategories } from './categories.js';
|
|
|
9
9
|
import { defineTool } from './ToolDefinition.js';
|
|
10
10
|
const throttlingOptions = [
|
|
11
11
|
'No emulation',
|
|
12
|
+
'Offline',
|
|
12
13
|
...Object.keys(PredefinedNetworkConditions),
|
|
13
14
|
];
|
|
14
15
|
export const emulateNetwork = defineTool({
|
|
15
16
|
name: 'emulate_network',
|
|
16
|
-
description: `Emulates network conditions such as throttling on the selected page.`,
|
|
17
|
+
description: `Emulates network conditions such as throttling or offline mode on the selected page.`,
|
|
17
18
|
annotations: {
|
|
18
19
|
category: ToolCategories.EMULATION,
|
|
19
20
|
readOnlyHint: false,
|
|
@@ -21,7 +22,7 @@ export const emulateNetwork = defineTool({
|
|
|
21
22
|
schema: {
|
|
22
23
|
throttlingOption: z
|
|
23
24
|
.enum(throttlingOptions)
|
|
24
|
-
.describe(`The network throttling option to emulate. Available throttling options are: ${throttlingOptions.join(', ')}. Set to "No emulation" to disable.`),
|
|
25
|
+
.describe(`The network throttling option to emulate. Available throttling options are: ${throttlingOptions.join(', ')}. Set to "No emulation" to disable. Set to "Offline" to simulate offline network conditions.`),
|
|
25
26
|
},
|
|
26
27
|
handler: async (request, _response, context) => {
|
|
27
28
|
const page = context.getSelectedPage();
|
|
@@ -31,6 +32,16 @@ export const emulateNetwork = defineTool({
|
|
|
31
32
|
context.setNetworkConditions(null);
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
35
|
+
if (conditions === 'Offline') {
|
|
36
|
+
await page.emulateNetworkConditions({
|
|
37
|
+
offline: true,
|
|
38
|
+
download: 0,
|
|
39
|
+
upload: 0,
|
|
40
|
+
latency: 0,
|
|
41
|
+
});
|
|
42
|
+
context.setNetworkConditions('Offline');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
34
45
|
if (conditions in PredefinedNetworkConditions) {
|
|
35
46
|
const networkCondition = PredefinedNetworkConditions[conditions];
|
|
36
47
|
await page.emulateNetworkConditions(networkCondition);
|
|
@@ -84,7 +84,7 @@ export const stopTrace = defineTool({
|
|
|
84
84
|
},
|
|
85
85
|
schema: {},
|
|
86
86
|
handler: async (_request, response, context) => {
|
|
87
|
-
if (!context.isRunningPerformanceTrace) {
|
|
87
|
+
if (!context.isRunningPerformanceTrace()) {
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
90
|
const page = context.getSelectedPage();
|
|
@@ -93,7 +93,7 @@ export const stopTrace = defineTool({
|
|
|
93
93
|
});
|
|
94
94
|
export const analyzeInsight = defineTool({
|
|
95
95
|
name: 'performance_analyze_insight',
|
|
96
|
-
description: 'Provides more detailed information on a specific Performance Insight that was
|
|
96
|
+
description: 'Provides more detailed information on a specific Performance Insight that was highlighted in the results of a trace recording.',
|
|
97
97
|
annotations: {
|
|
98
98
|
category: ToolCategories.PERFORMANCE,
|
|
99
99
|
readOnlyHint: true,
|
|
@@ -124,7 +124,6 @@ async function stopTracingAndAppendOutput(page, response, context) {
|
|
|
124
124
|
response.appendResponseLine('The performance trace has been stopped.');
|
|
125
125
|
if (traceResultIsSuccess(result)) {
|
|
126
126
|
context.storeTraceRecording(result);
|
|
127
|
-
response.appendResponseLine('Here is a high level summary of the trace and the Insights that were found:');
|
|
128
127
|
const traceSummaryText = getTraceSummary(result);
|
|
129
128
|
response.appendResponseLine(traceSummaryText);
|
|
130
129
|
}
|
|
@@ -136,7 +135,7 @@ async function stopTracingAndAppendOutput(page, response, context) {
|
|
|
136
135
|
catch (e) {
|
|
137
136
|
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
|
|
138
137
|
logger(`Error stopping performance trace: ${errorText}`);
|
|
139
|
-
response.appendResponseLine('An error
|
|
138
|
+
response.appendResponseLine('An error occurred generating the response for this trace:');
|
|
140
139
|
response.appendResponseLine(errorText);
|
|
141
140
|
}
|
|
142
141
|
finally {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { writeFile } from 'node:fs/promises';
|
|
7
6
|
import z from 'zod';
|
|
8
7
|
import { ToolCategories } from './categories.js';
|
|
9
8
|
import { defineTool } from './ToolDefinition.js';
|
|
@@ -65,8 +64,8 @@ export const screenshot = defineTool({
|
|
|
65
64
|
response.appendResponseLine("Took a screenshot of the current page's viewport.");
|
|
66
65
|
}
|
|
67
66
|
if (request.params.filePath) {
|
|
68
|
-
await
|
|
69
|
-
response.appendResponseLine(`Saved screenshot to ${
|
|
67
|
+
const file = await context.saveFile(screenshot, request.params.filePath);
|
|
68
|
+
response.appendResponseLine(`Saved screenshot to ${file.filename}.`);
|
|
70
69
|
}
|
|
71
70
|
else if (screenshot.length >= 2_000_000) {
|
|
72
71
|
const { filename } = await context.saveTemporaryFile(screenshot, `image/${request.params.format}`);
|
|
@@ -43,7 +43,7 @@ export async function parseRawTraceBuffer(buffer) {
|
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
45
|
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
|
|
46
|
-
logger(`
|
|
46
|
+
logger(`Unexpected error parsing trace: ${errorText}`);
|
|
47
47
|
return {
|
|
48
48
|
error: errorText,
|
|
49
49
|
};
|
|
@@ -53,15 +53,16 @@ const extraFormatDescriptions = `Information on performance traces may contain m
|
|
|
53
53
|
|
|
54
54
|
${PerformanceTraceFormatter.callFrameDataFormatDescription}
|
|
55
55
|
|
|
56
|
-
${PerformanceTraceFormatter.networkDataFormatDescription}
|
|
57
|
-
`;
|
|
56
|
+
${PerformanceTraceFormatter.networkDataFormatDescription}`;
|
|
58
57
|
export function getTraceSummary(result) {
|
|
59
58
|
const focus = AgentFocus.fromParsedTrace(result.parsedTrace);
|
|
60
59
|
const formatter = new PerformanceTraceFormatter(focus);
|
|
61
|
-
const
|
|
62
|
-
return
|
|
60
|
+
const summaryText = formatter.formatTraceSummary();
|
|
61
|
+
return `## Summary of Performance trace findings:
|
|
62
|
+
${summaryText}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
## Details on call tree & network request formats:
|
|
65
|
+
${extraFormatDescriptions}`;
|
|
65
66
|
}
|
|
66
67
|
export function getInsightOutput(result, insightName) {
|
|
67
68
|
if (!result.insights) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "MCP server for Chrome DevTools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./build/src/index.js",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp#readme",
|
|
38
38
|
"mcpName": "io.github.ChromeDevTools/chrome-devtools-mcp",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "1.
|
|
40
|
+
"@modelcontextprotocol/sdk": "1.19.1",
|
|
41
41
|
"core-js": "3.45.1",
|
|
42
42
|
"debug": "4.4.3",
|
|
43
|
-
"puppeteer-core": "24.
|
|
44
|
-
"yargs": "18.0.0"
|
|
43
|
+
"puppeteer-core": "^24.23.1",
|
|
44
|
+
"yargs": "18.0.0",
|
|
45
|
+
"zod": "^3.25.76"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@eslint/js": "^9.35.0",
|
|
@@ -53,13 +54,13 @@
|
|
|
53
54
|
"@types/yargs": "^17.0.33",
|
|
54
55
|
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
|
55
56
|
"@typescript-eslint/parser": "^8.43.0",
|
|
56
|
-
"chrome-devtools-frontend": "1.0.
|
|
57
|
+
"chrome-devtools-frontend": "1.0.1524741",
|
|
57
58
|
"eslint": "^9.35.0",
|
|
58
59
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
59
60
|
"eslint-plugin-import": "^2.32.0",
|
|
60
61
|
"globals": "^16.4.0",
|
|
61
62
|
"prettier": "^3.6.2",
|
|
62
|
-
"puppeteer": "24.
|
|
63
|
+
"puppeteer": "24.23.1",
|
|
63
64
|
"sinon": "^21.0.0",
|
|
64
65
|
"typescript": "^5.9.2",
|
|
65
66
|
"typescript-eslint": "^8.43.0"
|