chrome-devtools-mcp 0.23.0 → 0.24.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.
Files changed (77) hide show
  1. package/build/src/DevToolsConnectionAdapter.js +1 -0
  2. package/build/src/DevtoolsUtils.js +1 -0
  3. package/build/src/HeapSnapshotManager.js +16 -0
  4. package/build/src/McpContext.js +57 -4
  5. package/build/src/McpPage.js +6 -0
  6. package/build/src/McpResponse.js +38 -4
  7. package/build/src/Mutex.js +1 -0
  8. package/build/src/PageCollector.js +1 -0
  9. package/build/src/SlimMcpResponse.js +1 -0
  10. package/build/src/TextSnapshot.js +11 -5
  11. package/build/src/WaitForHelper.js +6 -0
  12. package/build/src/bin/check-latest-version.js +1 -0
  13. package/build/src/bin/chrome-devtools-cli-options.js +206 -46
  14. package/build/src/bin/chrome-devtools-mcp-cli-options.js +3 -1
  15. package/build/src/bin/chrome-devtools-mcp-main.js +1 -0
  16. package/build/src/bin/chrome-devtools-mcp.js +1 -0
  17. package/build/src/bin/chrome-devtools.js +5 -13
  18. package/build/src/browser.js +1 -0
  19. package/build/src/daemon/client.js +4 -2
  20. package/build/src/daemon/daemon.js +1 -0
  21. package/build/src/daemon/types.js +1 -0
  22. package/build/src/daemon/utils.js +1 -0
  23. package/build/src/formatters/ConsoleFormatter.js +48 -1
  24. package/build/src/formatters/HeapSnapshotFormatter.js +18 -2
  25. package/build/src/formatters/IssueFormatter.js +1 -0
  26. package/build/src/formatters/NetworkFormatter.js +1 -0
  27. package/build/src/formatters/SnapshotFormatter.js +2 -1
  28. package/build/src/index.js +114 -51
  29. package/build/src/issue-descriptions.js +1 -0
  30. package/build/src/logger.js +1 -0
  31. package/build/src/polyfill.js +1 -0
  32. package/build/src/telemetry/ClearcutLogger.js +13 -1
  33. package/build/src/telemetry/WatchdogClient.js +1 -0
  34. package/build/src/telemetry/flagUtils.js +1 -0
  35. package/build/src/telemetry/metricUtils.js +1 -0
  36. package/build/src/telemetry/persistence.js +1 -0
  37. package/build/src/telemetry/toolMetricsUtils.js +2 -1
  38. package/build/src/telemetry/types.js +1 -0
  39. package/build/src/telemetry/watchdog/ClearcutSender.js +1 -0
  40. package/build/src/telemetry/watchdog/main.js +1 -0
  41. package/build/src/third_party/THIRD_PARTY_NOTICES +5 -5
  42. package/build/src/third_party/bundled-packages.json +2 -2
  43. package/build/src/third_party/devtools-formatter-worker.js +2451 -2933
  44. package/build/src/third_party/devtools-heap-snapshot-worker.js +32 -26
  45. package/build/src/third_party/index.js +535 -135
  46. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +21717 -20261
  47. package/build/src/tools/ToolDefinition.js +1 -0
  48. package/build/src/tools/categories.js +6 -2
  49. package/build/src/tools/console.js +3 -0
  50. package/build/src/tools/emulation.js +2 -0
  51. package/build/src/tools/extensions.js +6 -0
  52. package/build/src/tools/inPage.js +3 -2
  53. package/build/src/tools/input.js +13 -2
  54. package/build/src/tools/lighthouse.js +17 -9
  55. package/build/src/tools/memory.js +34 -1
  56. package/build/src/tools/network.js +5 -0
  57. package/build/src/tools/pages.js +9 -0
  58. package/build/src/tools/performance.js +6 -0
  59. package/build/src/tools/screencast.js +6 -2
  60. package/build/src/tools/screenshot.js +3 -0
  61. package/build/src/tools/script.js +2 -0
  62. package/build/src/tools/slim/tools.js +4 -0
  63. package/build/src/tools/snapshot.js +5 -1
  64. package/build/src/tools/tools.js +1 -0
  65. package/build/src/tools/webmcp.js +3 -0
  66. package/build/src/trace-processing/parse.js +1 -0
  67. package/build/src/types.js +1 -0
  68. package/build/src/utils/check-for-updates.js +1 -0
  69. package/build/src/utils/files.js +5 -10
  70. package/build/src/utils/id.js +1 -0
  71. package/build/src/utils/keyboard.js +1 -0
  72. package/build/src/utils/pagination.js +1 -0
  73. package/build/src/utils/string.js +1 -0
  74. package/build/src/utils/types.js +1 -0
  75. package/build/src/version.js +2 -1
  76. package/package.json +9 -9
  77. package/build/src/bin/cliDefinitions.js +0 -621
@@ -12,11 +12,68 @@ import { Mutex } from './Mutex.js';
12
12
  import { SlimMcpResponse } from './SlimMcpResponse.js';
13
13
  import { ClearcutLogger } from './telemetry/ClearcutLogger.js';
14
14
  import { bucketizeLatency } from './telemetry/metricUtils.js';
15
- import { McpServer, SetLevelRequestSchema, } from './third_party/index.js';
16
- import { ToolCategory } from './tools/categories.js';
15
+ import { McpServer, SetLevelRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, } from './third_party/index.js';
16
+ import { labels, OFF_BY_DEFAULT_CATEGORIES } from './tools/categories.js';
17
17
  import { pageIdSchema } from './tools/ToolDefinition.js';
18
18
  import { createTools } from './tools/tools.js';
19
19
  import { VERSION } from './version.js';
20
+ export function buildFlag(category) {
21
+ return `category${category.charAt(0).toUpperCase() + category.slice(1)}`;
22
+ }
23
+ function buildDisabledMessage(toolName, flag, categoryLabel) {
24
+ const reason = categoryLabel
25
+ ? `is in category ${categoryLabel} which`
26
+ : `requires experimental feature ${flag} and`;
27
+ return `Tool ${toolName} ${reason} is currently disabled. Enable it by running chrome-devtools start ${flag}=true. For more information check the README.`;
28
+ }
29
+ function getCategoryStatus(category, serverArgs) {
30
+ const categoryFlag = buildFlag(category);
31
+ const flagValue = serverArgs[categoryFlag];
32
+ const isDisabled = OFF_BY_DEFAULT_CATEGORIES.includes(category)
33
+ ? !flagValue
34
+ : flagValue === false;
35
+ if (isDisabled) {
36
+ return {
37
+ categoryFlag,
38
+ disabled: true,
39
+ };
40
+ }
41
+ return {
42
+ disabled: false,
43
+ };
44
+ }
45
+ function getConditionStatus(condition, serverArgs) {
46
+ if (condition && !serverArgs[condition]) {
47
+ return { conditionFlag: condition, disabled: true };
48
+ }
49
+ return { disabled: false };
50
+ }
51
+ function getToolStatusInfo(tool, serverArgs) {
52
+ const category = tool.annotations.category;
53
+ const categoryCheck = getCategoryStatus(category, serverArgs);
54
+ if (category && categoryCheck.disabled) {
55
+ if (!categoryCheck.categoryFlag) {
56
+ throw new Error('when the category is disabled there should always be a flag set');
57
+ }
58
+ return {
59
+ disabled: true,
60
+ reason: buildDisabledMessage(tool.name, `--${categoryCheck.categoryFlag}`, labels[category]),
61
+ };
62
+ }
63
+ for (const condition of tool.annotations.conditions || []) {
64
+ const conditionCheck = getConditionStatus(condition, serverArgs);
65
+ if (conditionCheck.disabled) {
66
+ if (!conditionCheck.conditionFlag) {
67
+ throw new Error('when the condition is disabled there should always be a flag set');
68
+ }
69
+ return {
70
+ disabled: true,
71
+ reason: buildDisabledMessage(tool.name, `--${conditionCheck.conditionFlag}`),
72
+ };
73
+ }
74
+ }
75
+ return { disabled: false };
76
+ }
20
77
  export async function createMcpServer(serverArgs, options) {
21
78
  let clearcutLogger;
22
79
  if (serverArgs.usageStatistics) {
@@ -36,11 +93,29 @@ export async function createMcpServer(serverArgs, options) {
36
93
  server.server.setRequestHandler(SetLevelRequestSchema, () => {
37
94
  return {};
38
95
  });
96
+ const updateRoots = async () => {
97
+ if (!server.server.getClientCapabilities()?.roots) {
98
+ return;
99
+ }
100
+ try {
101
+ const roots = await server.server.request({ method: 'roots/list' }, ListRootsResultSchema);
102
+ context?.setRoots(roots.roots);
103
+ }
104
+ catch (e) {
105
+ logger('Failed to list roots', e);
106
+ }
107
+ };
39
108
  server.server.oninitialized = () => {
40
109
  const clientName = server.server.getClientVersion()?.name;
41
110
  if (clientName) {
42
111
  clearcutLogger?.setClientName(clientName);
43
112
  }
113
+ if (server.server.getClientCapabilities()?.roots) {
114
+ void updateRoots();
115
+ server.server.setNotificationHandler(RootsListChangedNotificationSchema, () => {
116
+ void updateRoots();
117
+ });
118
+ }
44
119
  };
45
120
  let context;
46
121
  async function getContext() {
@@ -83,49 +158,14 @@ export async function createMcpServer(serverArgs, options) {
83
158
  experimentalIncludeAllPages: serverArgs.experimentalIncludeAllPages,
84
159
  performanceCrux: serverArgs.performanceCrux,
85
160
  });
161
+ await updateRoots();
86
162
  }
87
163
  return context;
88
164
  }
89
165
  const toolMutex = new Mutex();
90
166
  function registerTool(tool) {
91
- if (tool.annotations.category === ToolCategory.EMULATION &&
92
- serverArgs.categoryEmulation === false) {
93
- return;
94
- }
95
- if (tool.annotations.category === ToolCategory.PERFORMANCE &&
96
- serverArgs.categoryPerformance === false) {
97
- return;
98
- }
99
- if (tool.annotations.category === ToolCategory.NETWORK &&
100
- serverArgs.categoryNetwork === false) {
101
- return;
102
- }
103
- if (tool.annotations.category === ToolCategory.EXTENSIONS &&
104
- serverArgs.categoryExtensions === false) {
105
- return;
106
- }
107
- if (tool.annotations.category === ToolCategory.IN_PAGE &&
108
- !serverArgs.categoryInPageTools) {
109
- return;
110
- }
111
- if (tool.annotations.conditions?.includes('computerVision') &&
112
- !serverArgs.experimentalVision) {
113
- return;
114
- }
115
- if (tool.annotations.conditions?.includes('experimentalMemory') &&
116
- !serverArgs.experimentalMemory) {
117
- return;
118
- }
119
- if (tool.annotations.conditions?.includes('experimentalInteropTools') &&
120
- !serverArgs.experimentalInteropTools) {
121
- return;
122
- }
123
- if (tool.annotations.conditions?.includes('screencast') &&
124
- !serverArgs.experimentalScreencast) {
125
- return;
126
- }
127
- if (tool.annotations.conditions?.includes('experimentalWebmcp') &&
128
- !serverArgs.experimentalWebmcp) {
167
+ const { disabled, reason: disabledReason } = getToolStatusInfo(tool, serverArgs);
168
+ if (disabled && !serverArgs.viaCli) {
129
169
  return;
130
170
  }
131
171
  const schema = 'pageScoped' in tool &&
@@ -139,6 +179,17 @@ export async function createMcpServer(serverArgs, options) {
139
179
  inputSchema: schema,
140
180
  annotations: tool.annotations,
141
181
  }, async (params) => {
182
+ if (disabledReason) {
183
+ return {
184
+ content: [
185
+ {
186
+ type: 'text',
187
+ text: disabledReason,
188
+ },
189
+ ],
190
+ isError: true,
191
+ };
192
+ }
142
193
  const guard = await toolMutex.acquire();
143
194
  const startTime = Date.now();
144
195
  let success = false;
@@ -151,29 +202,40 @@ export async function createMcpServer(serverArgs, options) {
151
202
  ? new SlimMcpResponse(serverArgs)
152
203
  : new McpResponse(serverArgs);
153
204
  response.setRedactNetworkHeaders(serverArgs.redactNetworkHeaders);
154
- if ('pageScoped' in tool && tool.pageScoped) {
205
+ try {
155
206
  const page = serverArgs.experimentalPageIdRouting &&
156
207
  params.pageId &&
157
208
  !serverArgs.slim
158
209
  ? context.getPageById(params.pageId)
159
210
  : context.getSelectedMcpPage();
160
211
  response.setPage(page);
161
- await tool.handler({
162
- params,
163
- page,
164
- }, response, context);
212
+ if (tool.blockedByDialog) {
213
+ page.throwIfDialogOpen();
214
+ }
215
+ if ('pageScoped' in tool && tool.pageScoped) {
216
+ await tool.handler({
217
+ params,
218
+ page,
219
+ }, response, context);
220
+ }
221
+ else {
222
+ await tool.handler(
223
+ // @ts-expect-error types do not match.
224
+ {
225
+ params,
226
+ }, response, context);
227
+ }
165
228
  }
166
- else {
167
- await tool.handler(
168
- // @ts-expect-error types do not match.
169
- {
170
- params,
171
- }, response, context);
229
+ catch (err) {
230
+ response.setError(err);
172
231
  }
173
232
  const { content, structuredContent } = await response.handle(tool.name, context);
174
233
  const result = {
175
234
  content,
176
235
  };
236
+ if (response.error) {
237
+ result.isError = true;
238
+ }
177
239
  success = true;
178
240
  if (serverArgs.experimentalStructuredContent) {
179
241
  result.structuredContent = structuredContent;
@@ -228,3 +290,4 @@ Google collects usage statistics to improve Chrome DevTools MCP. To opt-out, run
228
290
  For more details, visit: https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics`);
229
291
  }
230
292
  };
293
+ //# sourceMappingURL=index.js.map
@@ -37,3 +37,4 @@ export const ISSUE_UTILS = {
37
37
  loadIssueDescriptions,
38
38
  getIssueDescription,
39
39
  };
40
+ //# sourceMappingURL=issue-descriptions.js.map
@@ -34,3 +34,4 @@ export function flushLogs(logFile, timeoutMs = 2000) {
34
34
  });
35
35
  }
36
36
  export const logger = debug(mcpDebugNamespace);
37
+ //# sourceMappingURL=logger.js.map
@@ -5,3 +5,4 @@
5
5
  */
6
6
  // polyfills are now bundled with all other dependencies
7
7
  import './third_party/index.js';
8
+ //# sourceMappingURL=polyfill.js.map
@@ -64,9 +64,20 @@ export function transformArgType(zodType) {
64
64
  throw new Error(`Unsupported zod type for tool parameter: ${zodType}`);
65
65
  }
66
66
  }
67
+ const BUCKETS = [
68
+ 0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000,
69
+ ];
70
+ function bucketize(value) {
71
+ for (const bucket of BUCKETS) {
72
+ if (bucket >= value) {
73
+ return bucket;
74
+ }
75
+ }
76
+ return BUCKETS[BUCKETS.length - 1];
77
+ }
67
78
  function transformValue(zodType, value) {
68
79
  if (zodType === 'ZodString') {
69
- return value.length;
80
+ return bucketize(value.length);
70
81
  }
71
82
  else if (zodType === 'ZodArray') {
72
83
  return value.length;
@@ -239,3 +250,4 @@ export class ClearcutLogger {
239
250
  return !isSameDay;
240
251
  }
241
252
  }
253
+ //# sourceMappingURL=ClearcutLogger.js.map
@@ -58,3 +58,4 @@ export class WatchdogClient {
58
58
  }
59
59
  }
60
60
  }
61
+ //# sourceMappingURL=WatchdogClient.js.map
@@ -85,3 +85,4 @@ export function getPossibleFlagMetrics(options) {
85
85
  }
86
86
  return metrics;
87
87
  }
88
+ //# sourceMappingURL=flagUtils.js.map
@@ -12,3 +12,4 @@ export function bucketizeLatency(latencyMs) {
12
12
  }
13
13
  return LATENCY_BUCKETS[LATENCY_BUCKETS.length - 1];
14
14
  }
15
+ //# sourceMappingURL=metricUtils.js.map
@@ -51,3 +51,4 @@ export class FilePersistence {
51
51
  }
52
52
  }
53
53
  }
54
+ //# sourceMappingURL=persistence.js.map
@@ -32,7 +32,7 @@ export function applyToExistingMetrics(existing, update) {
32
32
  return tool;
33
33
  });
34
34
  }
35
- function applyToExisting(existing, update) {
35
+ export function applyToExisting(existing, update) {
36
36
  const existingNames = new Set(existing.map(item => item.name));
37
37
  const updatedNames = new Set(update.map(item => item.name));
38
38
  const result = [];
@@ -86,3 +86,4 @@ export function generateToolMetrics(tools) {
86
86
  };
87
87
  });
88
88
  }
89
+ //# sourceMappingURL=toolMetricsUtils.js.map
@@ -36,3 +36,4 @@ export var WatchdogMessageType;
36
36
  (function (WatchdogMessageType) {
37
37
  WatchdogMessageType["LOG_EVENT"] = "log-event";
38
38
  })(WatchdogMessageType || (WatchdogMessageType = {}));
39
+ //# sourceMappingURL=types.js.map
@@ -202,3 +202,4 @@ export class ClearcutSender {
202
202
  return this.#buffer.length;
203
203
  }
204
204
  }
205
+ //# sourceMappingURL=ClearcutSender.js.map
@@ -125,3 +125,4 @@ catch (err) {
125
125
  console.error('Watchdog fatal error:', err);
126
126
  process.exit(1);
127
127
  }
128
+ //# sourceMappingURL=main.js.map
@@ -2552,7 +2552,7 @@ SOFTWARE.
2552
2552
 
2553
2553
  Name: axe-core
2554
2554
  URL: https://www.deque.com/axe/
2555
- Version: 4.11.2
2555
+ Version: 4.11.4
2556
2556
  License: MPL-2.0
2557
2557
 
2558
2558
  Mozilla Public License, version 2.0
@@ -3988,7 +3988,7 @@ SOFTWARE.
3988
3988
 
3989
3989
  Name: puppeteer-core
3990
3990
  URL: https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core
3991
- Version: 24.40.0
3991
+ Version: 24.42.0
3992
3992
  License: Apache-2.0
3993
3993
 
3994
3994
  -------------------- DEPENDENCY DIVIDER --------------------
@@ -4054,7 +4054,7 @@ SOFTWARE.
4054
4054
 
4055
4055
  Name: tldts-core
4056
4056
  URL: https://github.com/remusao/tldts#readme
4057
- Version: 7.0.27
4057
+ Version: 7.0.29
4058
4058
  License: MIT
4059
4059
 
4060
4060
  Copyright (c) 2017 Thomas Parisot, 2018 Rémi Berson
@@ -4076,7 +4076,7 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTH
4076
4076
 
4077
4077
  Name: tldts-icann
4078
4078
  URL: https://github.com/remusao/tldts#readme
4079
- Version: 7.0.27
4079
+ Version: 7.0.29
4080
4080
  License: MIT
4081
4081
 
4082
4082
  Copyright (c) 2017 Thomas Parisot, 2018 Rémi Berson
@@ -4118,7 +4118,7 @@ PERFORMANCE OF THIS SOFTWARE.
4118
4118
 
4119
4119
  Name: web-features
4120
4120
  URL: git+https://github.com/web-platform-dx/web-features.git
4121
- Version: 3.21.0
4121
+ Version: 3.25.0
4122
4122
  License: Apache-2.0
4123
4123
 
4124
4124
  Apache License
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "@modelcontextprotocol/sdk": "1.29.0",
3
- "chrome-devtools-frontend": "1.0.1613625",
3
+ "chrome-devtools-frontend": "1.0.1618066",
4
4
  "core-js": "3.49.0",
5
5
  "debug": "4.4.3",
6
- "lighthouse": "13.1.0",
6
+ "lighthouse": "13.2.0",
7
7
  "semver": "^7.7.4",
8
8
  "urlpattern-polyfill": "^10.1.0",
9
9
  "yargs": "18.0.0",