chrome-devtools-mcp 1.1.1 → 1.3.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 (109) hide show
  1. package/README.md +33 -4
  2. package/build/src/HeapSnapshotManager.js +30 -16
  3. package/build/src/McpContext.js +63 -9
  4. package/build/src/McpPage.js +9 -9
  5. package/build/src/McpResponse.js +176 -58
  6. package/build/src/PageCollector.js +8 -8
  7. package/build/src/ServiceWorkerCollector.js +171 -0
  8. package/build/src/TextSnapshot.js +1 -1
  9. package/build/src/ToolHandler.js +10 -4
  10. package/build/src/WaitForHelper.js +2 -2
  11. package/build/src/bin/chrome-devtools-cli-options.js +106 -4
  12. package/build/src/bin/chrome-devtools-mcp-cli-options.js +64 -5
  13. package/build/src/bin/chrome-devtools-mcp-main.js +5 -5
  14. package/build/src/browser.js +8 -4
  15. package/build/src/daemon/client.js +7 -7
  16. package/build/src/daemon/daemon.js +12 -12
  17. package/build/src/daemon/utils.js +2 -2
  18. package/build/src/{DevToolsConnectionAdapter.js → devtools/DevToolsConnectionAdapter.js} +1 -1
  19. package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +79 -18
  20. package/build/src/devtools/McpHostBindingAdapter.js +165 -0
  21. package/build/src/formatters/ConsoleFormatter.js +1 -1
  22. package/build/src/formatters/HeapSnapshotFormatter.js +22 -0
  23. package/build/src/formatters/IssueFormatter.js +4 -4
  24. package/build/src/index.js +13 -1
  25. package/build/src/telemetry/ClearcutLogger.js +1 -1
  26. package/build/src/telemetry/WatchdogClient.js +4 -4
  27. package/build/src/telemetry/persistence.js +2 -2
  28. package/build/src/telemetry/watchdog/ClearcutSender.js +10 -10
  29. package/build/src/telemetry/watchdog/main.js +5 -5
  30. package/build/src/third_party/THIRD_PARTY_NOTICES +31 -1
  31. package/build/src/third_party/bundled-packages.json +2 -1
  32. package/build/src/third_party/devtools-formatter-worker.js +1 -1
  33. package/build/src/third_party/devtools-heap-snapshot-worker.js +161 -3
  34. package/build/src/third_party/index.js +7020 -5774
  35. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
  36. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
  37. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
  38. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
  39. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
  40. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  41. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  42. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
  43. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
  44. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
  45. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
  46. package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  47. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
  48. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
  49. package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  50. package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  51. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  52. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  53. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  54. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  55. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  56. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  57. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
  58. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
  59. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
  60. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
  61. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
  62. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
  63. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
  64. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
  65. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
  66. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
  67. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
  68. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
  69. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
  70. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
  71. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
  72. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
  73. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
  74. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
  75. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
  76. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
  77. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
  78. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
  79. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
  80. package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  81. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  82. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  83. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  84. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  85. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  86. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  87. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  88. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  89. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  90. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  91. package/build/src/tools/console.js +7 -0
  92. package/build/src/tools/emulation.js +1 -0
  93. package/build/src/tools/extensions.js +5 -2
  94. package/build/src/tools/input.js +11 -3
  95. package/build/src/tools/lighthouse.js +11 -6
  96. package/build/src/tools/memory.js +109 -10
  97. package/build/src/tools/network.js +2 -2
  98. package/build/src/tools/pages.js +13 -5
  99. package/build/src/tools/performance.js +8 -7
  100. package/build/src/tools/screencast.js +32 -10
  101. package/build/src/tools/screenshot.js +158 -76
  102. package/build/src/tools/script.js +1 -1
  103. package/build/src/tools/slim/tools.js +3 -0
  104. package/build/src/tools/snapshot.js +3 -2
  105. package/build/src/tools/thirdPartyDeveloper.js +12 -2
  106. package/build/src/tools/webmcp.js +2 -0
  107. package/build/src/trace-processing/parse.js +5 -5
  108. package/build/src/version.js +1 -1
  109. package/package.json +4 -3
@@ -3,9 +3,10 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import { Mutex } from '../Mutex.js';
7
+ import { DevTools } from '../third_party/index.js';
6
8
  import { PuppeteerDevToolsConnection } from './DevToolsConnectionAdapter.js';
7
- import { Mutex } from './Mutex.js';
8
- import { DevTools } from './third_party/index.js';
9
+ import { McpHostBindingAdapter } from './McpHostBindingAdapter.js';
9
10
  /**
10
11
  * A mock implementation of an issues manager that only implements the methods
11
12
  * that are actually used by the IssuesAggregator
@@ -16,22 +17,82 @@ export class FakeIssuesManager extends DevTools.Common.ObjectWrapper
16
17
  return [];
17
18
  }
18
19
  }
19
- // DevTools CDP errors can get noisy.
20
- DevTools.ProtocolClient.InspectorBackend.test.suppressRequestErrors = true;
21
- DevTools.I18n.DevToolsLocale.DevToolsLocale.instance({
22
- create: true,
23
- data: {
24
- navigatorLanguage: 'en-US',
25
- settingLanguage: 'en-US',
26
- lookupClosestDevToolsLocale: l => l,
27
- },
28
- });
29
- DevTools.I18n.i18n.registerLocaleDataForTest('en-US', {});
30
- DevTools.Formatter.FormatterWorkerPool.FormatterWorkerPool.instance({
31
- forceNew: true,
32
- entrypointURL: import.meta
33
- .resolve('./third_party/devtools-formatter-worker.js'),
34
- });
20
+ export function overrideDevToolsGlobals({ loadResource, }) {
21
+ DevTools.Host.InspectorFrontendHost.installInspectorFrontendHost(new McpHostBindingAdapter(loadResource));
22
+ // DevTools CDP errors can get noisy.
23
+ DevTools.ProtocolClient.InspectorBackend.test.suppressRequestErrors = true;
24
+ // Stub out Network emulation commands on the DevTools Agent prototype globally.
25
+ // This prevents the DevTools Frontend from ever resetting/clearing Puppeteer's
26
+ // active network blocking/throttling rules during target setup or session lifetime.
27
+ const networkAgentPrototype = DevTools.ProtocolClient.InspectorBackend.inspectorBackend.agentPrototypes.get('Network');
28
+ if (networkAgentPrototype) {
29
+ Object.defineProperty(networkAgentPrototype, 'invoke_emulateNetworkConditionsByRule', {
30
+ value: () => {
31
+ return Promise.resolve({
32
+ ruleIds: [],
33
+ getError: () => undefined,
34
+ });
35
+ },
36
+ writable: true,
37
+ configurable: true,
38
+ enumerable: true,
39
+ });
40
+ Object.defineProperty(networkAgentPrototype, 'invoke_overrideNetworkState', {
41
+ value: () => {
42
+ return Promise.resolve({
43
+ getError: () => undefined,
44
+ });
45
+ },
46
+ writable: true,
47
+ configurable: true,
48
+ enumerable: true,
49
+ });
50
+ Object.defineProperty(networkAgentPrototype, 'invoke_enable', {
51
+ value: () => {
52
+ return Promise.resolve({
53
+ getError: () => undefined,
54
+ });
55
+ },
56
+ writable: true,
57
+ configurable: true,
58
+ enumerable: true,
59
+ });
60
+ Object.defineProperty(networkAgentPrototype, 'invoke_disable', {
61
+ value: () => {
62
+ return Promise.resolve({
63
+ getError: () => undefined,
64
+ });
65
+ },
66
+ writable: true,
67
+ configurable: true,
68
+ enumerable: true,
69
+ });
70
+ Object.defineProperty(networkAgentPrototype, 'invoke_setBlockedURLs', {
71
+ value: () => {
72
+ return Promise.resolve({
73
+ getError: () => undefined,
74
+ });
75
+ },
76
+ writable: true,
77
+ configurable: true,
78
+ enumerable: true,
79
+ });
80
+ }
81
+ DevTools.I18n.DevToolsLocale.DevToolsLocale.instance({
82
+ create: true,
83
+ data: {
84
+ navigatorLanguage: 'en-US',
85
+ settingLanguage: 'en-US',
86
+ lookupClosestDevToolsLocale: l => l,
87
+ },
88
+ });
89
+ DevTools.I18n.i18n.registerLocaleDataForTest('en-US', {});
90
+ DevTools.Formatter.FormatterWorkerPool.FormatterWorkerPool.instance({
91
+ forceNew: true,
92
+ entrypointURL: import.meta
93
+ .resolve('../third_party/devtools-formatter-worker.js'),
94
+ });
95
+ }
35
96
  export class UniverseManager {
36
97
  #browser;
37
98
  #createUniverseFor;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /* eslint-disable @typescript-eslint/no-empty-function */
7
+ import { DevTools } from '../third_party/index.js';
8
+ /**
9
+ * BaseClass that is noop or throws for methods.
10
+ * the McpHostBindingAdapter should only implement methods
11
+ * that it needs to support.
12
+ */
13
+ class BaseMcpHostBindingAdapter {
14
+ connectAutomaticFileSystem() { }
15
+ disconnectAutomaticFileSystem() { }
16
+ addFileSystem() { }
17
+ loadCompleted() { }
18
+ indexPath() { }
19
+ setInspectedPageBounds() { }
20
+ showCertificateViewer() { }
21
+ setWhitelistedShortcuts() { }
22
+ setEyeDropperActive() { }
23
+ inspectElementCompleted() { }
24
+ openInNewTab() { }
25
+ openSearchResultsInNewTab() { }
26
+ showItemInFolder() { }
27
+ removeFileSystem() { }
28
+ requestFileSystems() { }
29
+ save() { }
30
+ append() { }
31
+ close() { }
32
+ searchInPath() { }
33
+ stopIndexing() { }
34
+ bringToFront() { }
35
+ closeWindow() { }
36
+ copyText() { }
37
+ inspectedURLChanged() { }
38
+ isolatedFileSystem() {
39
+ throw new Error('Not implemented');
40
+ }
41
+ registerPreference() { }
42
+ getPreferences() { }
43
+ getPreference() { }
44
+ setPreference() { }
45
+ removePreference() { }
46
+ clearPreferences() { }
47
+ getSyncInformation() { }
48
+ getHostConfig() { }
49
+ upgradeDraggedFileSystemPermissions() { }
50
+ platform() {
51
+ throw new Error('Not implemented');
52
+ }
53
+ recordCountHistogram() { }
54
+ recordEnumeratedHistogram() { }
55
+ recordPerformanceHistogram() { }
56
+ recordPerformanceHistogramMedium() { }
57
+ recordUserMetricsAction() { }
58
+ recordNewBadgeUsage() { }
59
+ sendMessageToBackend() { }
60
+ setDevicesDiscoveryConfig() { }
61
+ setDevicesUpdatesEnabled() { }
62
+ openRemotePage() { }
63
+ openNodeFrontend() { }
64
+ setInjectedScriptForOrigin() { }
65
+ setIsDocked() { }
66
+ showSurvey() { }
67
+ canShowSurvey() { }
68
+ zoomFactor() {
69
+ throw new Error('Not implemented');
70
+ }
71
+ zoomIn() { }
72
+ zoomOut() { }
73
+ resetZoom() { }
74
+ showContextMenuAtPoint() { }
75
+ reattach() { }
76
+ readyForTest() { }
77
+ connectionReady() { }
78
+ setOpenNewWindowForPopups() { }
79
+ isHostedMode() {
80
+ throw new Error('Not implemented');
81
+ }
82
+ setAddExtensionCallback() { }
83
+ initialTargetId() {
84
+ throw new Error('Not implemented');
85
+ }
86
+ doAidaConversation(_request, _streamId, cb) {
87
+ cb({
88
+ error: 'Not implemented',
89
+ });
90
+ }
91
+ registerAidaClientEvent(_request, cb) {
92
+ cb({
93
+ error: 'Not implemented',
94
+ });
95
+ }
96
+ aidaCodeComplete(_request, cb) {
97
+ cb({
98
+ error: 'Not implemented',
99
+ });
100
+ }
101
+ dispatchHttpRequest(_request, cb) {
102
+ cb({
103
+ error: 'Not implemented',
104
+ });
105
+ }
106
+ recordImpression() { }
107
+ recordResize() { }
108
+ recordClick() { }
109
+ recordHover() { }
110
+ recordDrag() { }
111
+ recordChange() { }
112
+ recordKeyDown() { }
113
+ recordSettingAccess() { }
114
+ recordFunctionCall() { }
115
+ setChromeFlag() { }
116
+ requestRestart() { }
117
+ loadNetworkResource(_urlString, _headers, _streamId, _callback) { }
118
+ }
119
+ export class McpHostBindingAdapter extends BaseMcpHostBindingAdapter {
120
+ #loadResource;
121
+ constructor(loadResource) {
122
+ super();
123
+ this.#loadResource = loadResource;
124
+ }
125
+ isolatedFileSystem() {
126
+ return null;
127
+ }
128
+ platform() {
129
+ switch (process.platform) {
130
+ case 'darwin':
131
+ return 'mac';
132
+ case 'win32':
133
+ return 'windows';
134
+ default:
135
+ return 'linux';
136
+ }
137
+ }
138
+ zoomFactor() {
139
+ return 1;
140
+ }
141
+ isHostedMode() {
142
+ return true;
143
+ }
144
+ initialTargetId() {
145
+ return Promise.resolve(null);
146
+ }
147
+ loadNetworkResource(urlString, _headers, streamId, callback) {
148
+ if (!URL.canParse(urlString)) {
149
+ callback({
150
+ statusCode: 404,
151
+ urlValid: false,
152
+ });
153
+ return;
154
+ }
155
+ this.#loadResource(urlString)
156
+ .then(content => {
157
+ DevTools.Host.ResourceLoader.streamWrite(streamId, content);
158
+ callback({ statusCode: 200 });
159
+ })
160
+ .catch(() => {
161
+ callback({ statusCode: 404 });
162
+ });
163
+ }
164
+ }
165
+ //# sourceMappingURL=McpHostBindingAdapter.js.map
@@ -3,7 +3,7 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { createStackTraceForConsoleMessage, SymbolizedError, } from '../DevtoolsUtils.js';
6
+ import { createStackTraceForConsoleMessage, SymbolizedError, } from '../devtools/DevtoolsUtils.js';
7
7
  import { UncaughtError } from '../PageCollector.js';
8
8
  import * as DevTools from '../third_party/index.js';
9
9
  export class ConsoleFormatter {
@@ -45,6 +45,28 @@ export class HeapSnapshotFormatter {
45
45
  }
46
46
  return lines.join('\n');
47
47
  }
48
+ static formatRetainingPaths(retainingPaths) {
49
+ const lines = [];
50
+ function formatEdge(edge, depth) {
51
+ const indent = ' '.repeat(depth);
52
+ lines.push(`${indent}<- @${edge.nodeId} ${edge.nodeName} via ${edge.edgeType} ${edge.edgeName} (distance: ${edge.distance})`);
53
+ for (const child of edge.children) {
54
+ formatEdge(child, depth + 1);
55
+ }
56
+ }
57
+ for (const path of retainingPaths) {
58
+ formatEdge(path, 0);
59
+ }
60
+ return lines.join('\n');
61
+ }
62
+ static formatDominators(dominators) {
63
+ const lines = [];
64
+ lines.push('nodeId,nodeName,selfSize,retainedSize');
65
+ for (const node of dominators) {
66
+ lines.push(`${node.nodeId},${node.nodeName},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.selfSize)},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.retainedSize)}`);
67
+ }
68
+ return lines.join('\n');
69
+ }
48
70
  #getSortedAggregates() {
49
71
  return Object.values(this.#aggregates).sort((a, b) => b.maxRet - a.maxRet);
50
72
  }
@@ -99,7 +99,7 @@ export class IssueFormatter {
99
99
  const markdownDescription = this.#issue.getDescription();
100
100
  const filename = markdownDescription?.file;
101
101
  if (!filename) {
102
- logger(`no description found for issue:` + this.#issue.code());
102
+ logger?.(`no description found for issue:` + this.#issue.code());
103
103
  return undefined;
104
104
  }
105
105
  // We already have the description logic in #getDescription, but title extraction is separate
@@ -107,7 +107,7 @@ export class IssueFormatter {
107
107
  // Ideally we should process markdown once.
108
108
  const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
109
109
  if (!rawMarkdown) {
110
- logger(`no markdown ${filename} found for issue:` + this.#issue.code());
110
+ logger?.(`no markdown ${filename} found for issue:` + this.#issue.code());
111
111
  return undefined;
112
112
  }
113
113
  try {
@@ -115,13 +115,13 @@ export class IssueFormatter {
115
115
  const markdownAst = DevTools.Marked.Marked.lexer(processedMarkdown);
116
116
  const title = DevTools.MarkdownIssueDescription.findTitleFromMarkdownAst(markdownAst);
117
117
  if (!title) {
118
- logger('cannot read issue title from ' + filename);
118
+ logger?.('cannot read issue title from ' + filename);
119
119
  return undefined;
120
120
  }
121
121
  return title;
122
122
  }
123
123
  catch {
124
- logger('error parsing markdown for issue ' + this.#issue.code());
124
+ logger?.('error parsing markdown for issue ' + this.#issue.code());
125
125
  return undefined;
126
126
  }
127
127
  }
@@ -43,7 +43,7 @@ export async function createMcpServer(serverArgs, options) {
43
43
  context?.setRoots(roots.roots);
44
44
  }
45
45
  catch (e) {
46
- logger('Failed to list roots', e);
46
+ logger?.('Failed to list roots', e);
47
47
  }
48
48
  };
49
49
  server.server.oninitialized = () => {
@@ -66,6 +66,12 @@ export async function createMcpServer(serverArgs, options) {
66
66
  chromeArgs.push(`--proxy-server=${serverArgs.proxyServer}`);
67
67
  }
68
68
  const devtools = serverArgs.experimentalDevtools ?? false;
69
+ const blocklist = serverArgs.blockedUrlPattern
70
+ ? serverArgs.blockedUrlPattern.map(String)
71
+ : undefined;
72
+ const allowlist = serverArgs.allowedUrlPattern
73
+ ? serverArgs.allowedUrlPattern.map(String)
74
+ : undefined;
69
75
  const browser = serverArgs.browserUrl || serverArgs.wsEndpoint || serverArgs.autoConnect
70
76
  ? await ensureBrowserConnected({
71
77
  browserURL: serverArgs.browserUrl,
@@ -77,6 +83,8 @@ export async function createMcpServer(serverArgs, options) {
77
83
  : undefined,
78
84
  userDataDir: serverArgs.userDataDir,
79
85
  devtools,
86
+ blocklist,
87
+ allowlist,
80
88
  })
81
89
  : await ensureBrowserLaunched({
82
90
  headless: serverArgs.headless,
@@ -92,12 +100,16 @@ export async function createMcpServer(serverArgs, options) {
92
100
  devtools,
93
101
  enableExtensions: serverArgs.categoryExtensions,
94
102
  viaCli: serverArgs.viaCli,
103
+ blocklist,
104
+ allowlist,
95
105
  });
96
106
  if (context?.browser !== browser) {
97
107
  context = await McpContext.from(browser, logger, {
98
108
  experimentalDevToolsDebugging: devtools,
99
109
  experimentalIncludeAllPages: serverArgs.experimentalIncludeAllPages,
100
110
  performanceCrux: serverArgs.performanceCrux,
111
+ hasNetworkBlockOrAllowlist: Boolean((blocklist && blocklist.length > 0) ||
112
+ (allowlist && allowlist.length > 0)),
101
113
  });
102
114
  await updateRoots();
103
115
  }
@@ -136,7 +136,7 @@ export class ClearcutLogger {
136
136
  }
137
137
  }
138
138
  catch (err) {
139
- logger('Error in logDailyActiveIfNeeded:', err);
139
+ logger?.('Error in logDailyActiveIfNeeded:', err);
140
140
  }
141
141
  }
142
142
  async logServerError(args) {
@@ -35,10 +35,10 @@ export class WatchdogClient {
35
35
  });
36
36
  this.#childProcess.unref();
37
37
  this.#childProcess.on('error', err => {
38
- logger('Watchdog process error:', err);
38
+ logger?.('Watchdog process error:', err);
39
39
  });
40
40
  this.#childProcess.on('exit', (code, signal) => {
41
- logger(`Watchdog exited with code ${code} and signal ${signal}`);
41
+ logger?.(`Watchdog exited with code ${code} and signal ${signal}`);
42
42
  });
43
43
  }
44
44
  send(message) {
@@ -50,11 +50,11 @@ export class WatchdogClient {
50
50
  this.#childProcess.stdin.write(line);
51
51
  }
52
52
  catch (err) {
53
- logger('Failed to write to watchdog stdin', err);
53
+ logger?.('Failed to write to watchdog stdin', err);
54
54
  }
55
55
  }
56
56
  else {
57
- logger('Watchdog stdin not available, dropping message');
57
+ logger?.('Watchdog stdin not available, dropping message');
58
58
  }
59
59
  }
60
60
  }
@@ -45,7 +45,7 @@ export class FilePersistence {
45
45
  return JSON.parse(content);
46
46
  }
47
47
  catch (error) {
48
- logger(`Failed to read telemetry state from ${filePath}:`, error);
48
+ logger?.(`Failed to read telemetry state from ${filePath}:`, error);
49
49
  void ClearcutLogger.get()?.logServerError({
50
50
  errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_READ_FAILED,
51
51
  });
@@ -62,7 +62,7 @@ export class FilePersistence {
62
62
  }
63
63
  catch (error) {
64
64
  // Ignore errors during state saving to avoid crashing the server
65
- logger(`Failed to save telemetry state to ${filePath}:`, error);
65
+ logger?.(`Failed to save telemetry state to ${filePath}:`, error);
66
66
  void ClearcutLogger.get()?.logServerError({
67
67
  errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED,
68
68
  });
@@ -48,7 +48,7 @@ export class ClearcutSender {
48
48
  app_version: this.#appVersion,
49
49
  os_type: this.#osType,
50
50
  };
51
- logger('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
51
+ logger?.('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
52
52
  this.#addToBuffer(eventToSend);
53
53
  if (!this.#timerStarted) {
54
54
  this.#timerStarted = true;
@@ -69,10 +69,10 @@ export class ClearcutSender {
69
69
  this.#finalFlush(),
70
70
  new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),
71
71
  ]);
72
- logger('Final flush completed');
72
+ logger?.('Final flush completed');
73
73
  }
74
74
  catch (error) {
75
- logger('Final flush failed:', error);
75
+ logger?.('Final flush failed:', error);
76
76
  }
77
77
  }
78
78
  async #flush() {
@@ -97,7 +97,7 @@ export class ClearcutSender {
97
97
  }
98
98
  }
99
99
  else if (result.isPermanentError) {
100
- logger('Permanent error, dropped batch of', eventsToSend.length, 'events');
100
+ logger?.('Permanent error, dropped batch of', eventsToSend.length, 'events');
101
101
  }
102
102
  else {
103
103
  // Transient error: Requeue events at the front of the buffer
@@ -108,7 +108,7 @@ export class ClearcutSender {
108
108
  catch (error) {
109
109
  // Safety catch for unexpected errors, requeue events
110
110
  this.#buffer = [...eventsToSend, ...this.#buffer];
111
- logger('Flush failed unexpectedly:', error);
111
+ logger?.('Flush failed unexpectedly:', error);
112
112
  }
113
113
  finally {
114
114
  this.#isFlushing = false;
@@ -118,7 +118,7 @@ export class ClearcutSender {
118
118
  #addToBuffer(event) {
119
119
  if (this.#buffer.length >= MAX_BUFFER_SIZE) {
120
120
  this.#buffer.shift();
121
- logger('Telemetry buffer overflow: dropped oldest event');
121
+ logger?.('Telemetry buffer overflow: dropped oldest event');
122
122
  }
123
123
  this.#buffer.push({
124
124
  event,
@@ -126,18 +126,18 @@ export class ClearcutSender {
126
126
  });
127
127
  }
128
128
  #scheduleFlush(delayMs) {
129
- logger(`Scheduling flush in ${delayMs}`);
129
+ logger?.(`Scheduling flush in ${delayMs}`);
130
130
  if (this.#flushTimer) {
131
131
  clearTimeout(this.#flushTimer);
132
132
  }
133
133
  this.#flushTimer = setTimeout(() => {
134
134
  this.#flush().catch(err => {
135
- logger('Flush error:', err);
135
+ logger?.('Flush error:', err);
136
136
  });
137
137
  }, delayMs);
138
138
  }
139
139
  async #sendBatch(events) {
140
- logger(`Sending batch of ${events.length}`);
140
+ logger?.(`Sending batch of ${events.length}`);
141
141
  const requestBody = {
142
142
  log_source: LOG_SOURCE,
143
143
  request_time_ms: Date.now().toString(),
@@ -176,7 +176,7 @@ export class ClearcutSender {
176
176
  if (status >= 500 || status === 429) {
177
177
  return { success: false };
178
178
  }
179
- logger('Telemetry permanent error:', status);
179
+ logger?.('Telemetry permanent error:', status);
180
180
  return { success: false, isPermanentError: true };
181
181
  }
182
182
  catch {
@@ -65,7 +65,7 @@ function main() {
65
65
  process.exit(code);
66
66
  });
67
67
  };
68
- logger('Watchdog started', JSON.stringify({
68
+ logger?.('Watchdog started', JSON.stringify({
69
69
  pid: process.pid,
70
70
  parentPid,
71
71
  version: appVersion,
@@ -84,15 +84,15 @@ function main() {
84
84
  return;
85
85
  }
86
86
  isShuttingDown = true;
87
- logger(`Parent death detected (${reason}). Sending shutdown event...`);
87
+ logger?.(`Parent death detected (${reason}). Sending shutdown event...`);
88
88
  sender
89
89
  .sendShutdownEvent()
90
90
  .then(() => {
91
- logger('Shutdown event sent. Exiting.');
91
+ logger?.('Shutdown event sent. Exiting.');
92
92
  exit(0);
93
93
  })
94
94
  .catch(err => {
95
- logger('Failed to send shutdown event', err);
95
+ logger?.('Failed to send shutdown event', err);
96
96
  exit(1);
97
97
  });
98
98
  }
@@ -114,7 +114,7 @@ function main() {
114
114
  }
115
115
  }
116
116
  catch (err) {
117
- logger('Failed to parse IPC message', err);
117
+ logger?.('Failed to parse IPC message', err);
118
118
  }
119
119
  });
120
120
  }
@@ -324,7 +324,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
324
324
 
325
325
  Name: semver
326
326
  URL: git+https://github.com/npm/node-semver.git
327
- Version: 7.8.1
327
+ Version: 7.8.3
328
328
  License: ISC
329
329
 
330
330
  The ISC License
@@ -906,6 +906,36 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
906
906
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
907
907
 
908
908
 
909
+ -------------------- DEPENDENCY DIVIDER --------------------
910
+
911
+ Name: @toon-format/toon
912
+ URL: https://toonformat.dev
913
+ Version: 2.3.0
914
+ License: MIT
915
+
916
+ MIT License
917
+
918
+ Copyright (c) 2025-PRESENT Johann Schopplich
919
+
920
+ Permission is hereby granted, free of charge, to any person obtaining a copy
921
+ of this software and associated documentation files (the "Software"), to deal
922
+ in the Software without restriction, including without limitation the rights
923
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
924
+ copies of the Software, and to permit persons to whom the Software is
925
+ furnished to do so, subject to the following conditions:
926
+
927
+ The above copyright notice and this permission notice shall be included in all
928
+ copies or substantial portions of the Software.
929
+
930
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
931
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
932
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
933
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
934
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
935
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
936
+ SOFTWARE.
937
+
938
+
909
939
  -------------------- DEPENDENCY DIVIDER --------------------
910
940
 
911
941
  Name: chrome-devtools-frontend
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "@modelcontextprotocol/sdk": "1.29.0",
3
- "chrome-devtools-frontend": "1.0.1632065",
3
+ "@toon-format/toon": "^2.2.0",
4
+ "chrome-devtools-frontend": "1.0.1646286",
4
5
  "core-js": "3.49.0",
5
6
  "debug": "4.4.3",
6
7
  "lighthouse": "13.3.0",
@@ -2645,9 +2645,9 @@ var ExperimentName;
2645
2645
  ExperimentName["ALL"] = "*";
2646
2646
  ExperimentName["PROTOCOL_MONITOR"] = "protocol-monitor";
2647
2647
  ExperimentName["INSTRUMENTATION_BREAKPOINTS"] = "instrumentation-breakpoints";
2648
- ExperimentName["USE_SOURCE_MAP_SCOPES"] = "use-source-map-scopes";
2649
2648
  ExperimentName["DURABLE_MESSAGES"] = "durable-messages";
2650
2649
  ExperimentName["JPEG_XL"] = "jpeg-xl";
2650
+ ExperimentName["PLUS_BUTTON"] = "plus-button";
2651
2651
  })(ExperimentName || (ExperimentName = {}));
2652
2652
 
2653
2653
  // Copyright 2016 The Chromium Authors