@mcp-b/chrome-devtools-mcp 2.3.1 → 3.0.0-beta.20260529000441

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 (67) hide show
  1. package/package.json +1 -1
  2. package/build/src/DevToolsConnectionAdapter.js +0 -70
  3. package/build/src/DevtoolsUtils.js +0 -290
  4. package/build/src/McpContext.js +0 -687
  5. package/build/src/McpPage.js +0 -95
  6. package/build/src/McpResponse.js +0 -588
  7. package/build/src/Mutex.js +0 -37
  8. package/build/src/PageCollector.js +0 -308
  9. package/build/src/SlimMcpResponse.js +0 -18
  10. package/build/src/WaitForHelper.js +0 -135
  11. package/build/src/bin/chrome-devtools-cli-options.js +0 -651
  12. package/build/src/bin/chrome-devtools-mcp-cli-options.js +0 -317
  13. package/build/src/bin/chrome-devtools-mcp-main.js +0 -35
  14. package/build/src/bin/chrome-devtools-mcp.js +0 -21
  15. package/build/src/bin/chrome-devtools.js +0 -185
  16. package/build/src/bin/cliDefinitions.js +0 -615
  17. package/build/src/browser.js +0 -198
  18. package/build/src/daemon/client.js +0 -152
  19. package/build/src/daemon/daemon.js +0 -206
  20. package/build/src/daemon/types.js +0 -6
  21. package/build/src/daemon/utils.js +0 -108
  22. package/build/src/formatters/ConsoleFormatter.js +0 -234
  23. package/build/src/formatters/IssueFormatter.js +0 -192
  24. package/build/src/formatters/NetworkFormatter.js +0 -215
  25. package/build/src/formatters/SnapshotFormatter.js +0 -131
  26. package/build/src/index.js +0 -202
  27. package/build/src/issue-descriptions.js +0 -39
  28. package/build/src/logger.js +0 -36
  29. package/build/src/polyfill.js +0 -7
  30. package/build/src/telemetry/ClearcutLogger.js +0 -102
  31. package/build/src/telemetry/WatchdogClient.js +0 -60
  32. package/build/src/telemetry/flagUtils.js +0 -45
  33. package/build/src/telemetry/metricUtils.js +0 -14
  34. package/build/src/telemetry/persistence.js +0 -53
  35. package/build/src/telemetry/types.js +0 -33
  36. package/build/src/telemetry/watchdog/ClearcutSender.js +0 -203
  37. package/build/src/telemetry/watchdog/main.js +0 -127
  38. package/build/src/third_party/devtools-formatter-worker.js +0 -7
  39. package/build/src/third_party/index.js +0 -26
  40. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +0 -54183
  41. package/build/src/tools/ToolDefinition.js +0 -72
  42. package/build/src/tools/categories.js +0 -24
  43. package/build/src/tools/console.js +0 -85
  44. package/build/src/tools/emulation.js +0 -55
  45. package/build/src/tools/extensions.js +0 -96
  46. package/build/src/tools/input.js +0 -368
  47. package/build/src/tools/lighthouse.js +0 -123
  48. package/build/src/tools/memory.js +0 -28
  49. package/build/src/tools/network.js +0 -120
  50. package/build/src/tools/pages.js +0 -319
  51. package/build/src/tools/performance.js +0 -190
  52. package/build/src/tools/screencast.js +0 -79
  53. package/build/src/tools/screenshot.js +0 -84
  54. package/build/src/tools/script.js +0 -119
  55. package/build/src/tools/slim/tools.js +0 -81
  56. package/build/src/tools/snapshot.js +0 -56
  57. package/build/src/tools/tools.js +0 -52
  58. package/build/src/tools/webmcp.js +0 -416
  59. package/build/src/trace-processing/parse.js +0 -84
  60. package/build/src/types.js +0 -6
  61. package/build/src/utils/ExtensionRegistry.js +0 -35
  62. package/build/src/utils/files.js +0 -19
  63. package/build/src/utils/keyboard.js +0 -296
  64. package/build/src/utils/pagination.js +0 -49
  65. package/build/src/utils/string.js +0 -36
  66. package/build/src/utils/types.js +0 -6
  67. package/build/src/version.js +0 -9
@@ -1,53 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import fs from 'node:fs/promises';
7
- import os from 'node:os';
8
- import path from 'node:path';
9
- import process from 'node:process';
10
- import { logger } from '../logger.js';
11
- const STATE_FILE_NAME = 'telemetry_state.json';
12
- function getDataFolder() {
13
- const homedir = os.homedir();
14
- const { env } = process;
15
- const name = 'chrome-devtools-mcp';
16
- if (process.platform === 'darwin') {
17
- return path.join(homedir, 'Library', 'Application Support', name);
18
- }
19
- if (process.platform === 'win32') {
20
- const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
21
- return path.join(localAppData, name, 'Data');
22
- }
23
- return path.join(env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'), name);
24
- }
25
- export class FilePersistence {
26
- #dataFolder;
27
- constructor(dataFolderOverride) {
28
- this.#dataFolder = dataFolderOverride ?? getDataFolder();
29
- }
30
- async loadState() {
31
- try {
32
- const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);
33
- const content = await fs.readFile(filePath, 'utf-8');
34
- return JSON.parse(content);
35
- }
36
- catch {
37
- return {
38
- lastActive: '',
39
- };
40
- }
41
- }
42
- async saveState(state) {
43
- const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);
44
- try {
45
- await fs.mkdir(this.#dataFolder, { recursive: true });
46
- await fs.writeFile(filePath, JSON.stringify(state, null, 2), 'utf-8');
47
- }
48
- catch (error) {
49
- // Ignore errors during state saving to avoid crashing the server
50
- logger(`Failed to save telemetry state to ${filePath}:`, error);
51
- }
52
- }
53
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- // Enums
7
- export var OsType;
8
- (function (OsType) {
9
- OsType[OsType["OS_TYPE_UNSPECIFIED"] = 0] = "OS_TYPE_UNSPECIFIED";
10
- OsType[OsType["OS_TYPE_WINDOWS"] = 1] = "OS_TYPE_WINDOWS";
11
- OsType[OsType["OS_TYPE_MACOS"] = 2] = "OS_TYPE_MACOS";
12
- OsType[OsType["OS_TYPE_LINUX"] = 3] = "OS_TYPE_LINUX";
13
- })(OsType || (OsType = {}));
14
- export var ChromeChannel;
15
- (function (ChromeChannel) {
16
- ChromeChannel[ChromeChannel["CHROME_CHANNEL_UNSPECIFIED"] = 0] = "CHROME_CHANNEL_UNSPECIFIED";
17
- ChromeChannel[ChromeChannel["CHROME_CHANNEL_CANARY"] = 1] = "CHROME_CHANNEL_CANARY";
18
- ChromeChannel[ChromeChannel["CHROME_CHANNEL_DEV"] = 2] = "CHROME_CHANNEL_DEV";
19
- ChromeChannel[ChromeChannel["CHROME_CHANNEL_BETA"] = 3] = "CHROME_CHANNEL_BETA";
20
- ChromeChannel[ChromeChannel["CHROME_CHANNEL_STABLE"] = 4] = "CHROME_CHANNEL_STABLE";
21
- })(ChromeChannel || (ChromeChannel = {}));
22
- export var McpClient;
23
- (function (McpClient) {
24
- McpClient[McpClient["MCP_CLIENT_UNSPECIFIED"] = 0] = "MCP_CLIENT_UNSPECIFIED";
25
- McpClient[McpClient["MCP_CLIENT_CLAUDE_CODE"] = 1] = "MCP_CLIENT_CLAUDE_CODE";
26
- McpClient[McpClient["MCP_CLIENT_GEMINI_CLI"] = 2] = "MCP_CLIENT_GEMINI_CLI";
27
- })(McpClient || (McpClient = {}));
28
- // IPC types for messages between the main process and the
29
- // telemetry watchdog process.
30
- export var WatchdogMessageType;
31
- (function (WatchdogMessageType) {
32
- WatchdogMessageType["LOG_EVENT"] = "log-event";
33
- })(WatchdogMessageType || (WatchdogMessageType = {}));
@@ -1,203 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import crypto from 'node:crypto';
7
- import { logger } from '../../logger.js';
8
- const MAX_BUFFER_SIZE = 1000;
9
- const DEFAULT_CLEARCUT_ENDPOINT = 'https://play.googleapis.com/log?format=json_proto';
10
- const DEFAULT_FLUSH_INTERVAL_MS = 15 * 60 * 1000;
11
- const LOG_SOURCE = 2839;
12
- const CLIENT_TYPE = 47;
13
- const MIN_RATE_LIMIT_WAIT_MS = 30_000;
14
- const REQUEST_TIMEOUT_MS = 30_000;
15
- const SHUTDOWN_TIMEOUT_MS = 5_000;
16
- const SESSION_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
17
- export class ClearcutSender {
18
- #appVersion;
19
- #osType;
20
- #clearcutEndpoint;
21
- #flushIntervalMs;
22
- #includePidHeader;
23
- #sessionId;
24
- #sessionCreated;
25
- #buffer = [];
26
- #flushTimer = null;
27
- #isFlushing = false;
28
- #timerStarted = false;
29
- constructor(config) {
30
- this.#appVersion = config.appVersion;
31
- this.#osType = config.osType;
32
- this.#clearcutEndpoint =
33
- config.clearcutEndpoint ?? DEFAULT_CLEARCUT_ENDPOINT;
34
- this.#flushIntervalMs =
35
- config.forceFlushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
36
- this.#includePidHeader = config.includePidHeader ?? false;
37
- this.#sessionId = crypto.randomUUID();
38
- this.#sessionCreated = Date.now();
39
- }
40
- enqueueEvent(event) {
41
- if (Date.now() - this.#sessionCreated > SESSION_ROTATION_INTERVAL_MS) {
42
- this.#sessionId = crypto.randomUUID();
43
- this.#sessionCreated = Date.now();
44
- }
45
- logger('Enqueing telemetry event', JSON.stringify(event, null, 2));
46
- this.#addToBuffer({
47
- ...event,
48
- session_id: this.#sessionId,
49
- app_version: this.#appVersion,
50
- os_type: this.#osType,
51
- });
52
- if (!this.#timerStarted) {
53
- this.#timerStarted = true;
54
- this.#scheduleFlush(this.#flushIntervalMs);
55
- }
56
- }
57
- async sendShutdownEvent() {
58
- if (this.#flushTimer) {
59
- clearTimeout(this.#flushTimer);
60
- this.#flushTimer = null;
61
- }
62
- const shutdownEvent = {
63
- server_shutdown: {},
64
- };
65
- this.enqueueEvent(shutdownEvent);
66
- try {
67
- await Promise.race([
68
- this.#finalFlush(),
69
- new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),
70
- ]);
71
- logger('Final flush completed');
72
- }
73
- catch (error) {
74
- logger('Final flush failed:', error);
75
- }
76
- }
77
- async #flush() {
78
- if (this.#isFlushing) {
79
- return;
80
- }
81
- if (this.#buffer.length === 0) {
82
- this.#scheduleFlush(this.#flushIntervalMs);
83
- return;
84
- }
85
- this.#isFlushing = true;
86
- let nextDelayMs = this.#flushIntervalMs;
87
- // Optimistically remove events from buffer before sending.
88
- // This prevents race conditions where a simultaneous #finalFlush would include these same events.
89
- const eventsToSend = [...this.#buffer];
90
- this.#buffer = [];
91
- try {
92
- const result = await this.#sendBatch(eventsToSend);
93
- if (result.success) {
94
- if (result.nextRequestWaitMs !== undefined) {
95
- nextDelayMs = Math.max(result.nextRequestWaitMs, MIN_RATE_LIMIT_WAIT_MS);
96
- }
97
- }
98
- else if (result.isPermanentError) {
99
- logger('Permanent error, dropped batch of', eventsToSend.length, 'events');
100
- }
101
- else {
102
- // Transient error: Requeue events at the front of the buffer
103
- // to maintain order and retry them later.
104
- this.#buffer = [...eventsToSend, ...this.#buffer];
105
- }
106
- }
107
- catch (error) {
108
- // Safety catch for unexpected errors, requeue events
109
- this.#buffer = [...eventsToSend, ...this.#buffer];
110
- logger('Flush failed unexpectedly:', error);
111
- }
112
- finally {
113
- this.#isFlushing = false;
114
- this.#scheduleFlush(nextDelayMs);
115
- }
116
- }
117
- #addToBuffer(event) {
118
- if (this.#buffer.length >= MAX_BUFFER_SIZE) {
119
- this.#buffer.shift();
120
- logger('Telemetry buffer overflow: dropped oldest event');
121
- }
122
- this.#buffer.push({
123
- event,
124
- timestamp: Date.now(),
125
- });
126
- }
127
- #scheduleFlush(delayMs) {
128
- logger(`Scheduling flush in ${delayMs}`);
129
- if (this.#flushTimer) {
130
- clearTimeout(this.#flushTimer);
131
- }
132
- this.#flushTimer = setTimeout(() => {
133
- this.#flush().catch(err => {
134
- logger('Flush error:', err);
135
- });
136
- }, delayMs);
137
- }
138
- async #sendBatch(events) {
139
- logger(`Sending batch of ${events.length}`);
140
- const requestBody = {
141
- log_source: LOG_SOURCE,
142
- request_time_ms: Date.now().toString(),
143
- client_info: {
144
- client_type: CLIENT_TYPE,
145
- },
146
- log_event: events.map(({ event, timestamp }) => ({
147
- event_time_ms: timestamp.toString(),
148
- source_extension_json: JSON.stringify(event),
149
- })),
150
- };
151
- const controller = new AbortController();
152
- const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
153
- try {
154
- const response = await fetch(this.#clearcutEndpoint, {
155
- method: 'POST',
156
- headers: {
157
- 'Content-Type': 'application/json',
158
- // Used in E2E tests to confirm that the watchdog process is killed
159
- ...(this.#includePidHeader
160
- ? { 'X-Watchdog-Pid': process.pid.toString() }
161
- : {}),
162
- },
163
- body: JSON.stringify(requestBody),
164
- signal: controller.signal,
165
- });
166
- clearTimeout(timeoutId);
167
- if (response.ok) {
168
- const data = (await response.json());
169
- return {
170
- success: true,
171
- nextRequestWaitMs: data.next_request_wait_millis,
172
- };
173
- }
174
- const status = response.status;
175
- if (status >= 500 || status === 429) {
176
- return { success: false };
177
- }
178
- logger('Telemetry permanent error:', status);
179
- return { success: false, isPermanentError: true };
180
- }
181
- catch {
182
- clearTimeout(timeoutId);
183
- return { success: false };
184
- }
185
- }
186
- async #finalFlush() {
187
- if (this.#buffer.length === 0) {
188
- return;
189
- }
190
- const eventsToSend = [...this.#buffer];
191
- await this.#sendBatch(eventsToSend);
192
- }
193
- stopForTesting() {
194
- if (this.#flushTimer) {
195
- clearTimeout(this.#flushTimer);
196
- this.#flushTimer = null;
197
- }
198
- this.#timerStarted = false;
199
- }
200
- get bufferSizeForTesting() {
201
- return this.#buffer.length;
202
- }
203
- }
@@ -1,127 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import process from 'node:process';
7
- import readline from 'node:readline';
8
- import { parseArgs } from 'node:util';
9
- import { logger, flushLogs, saveLogsToFile } from '../../logger.js';
10
- import { WatchdogMessageType } from '../types.js';
11
- import { ClearcutSender } from './ClearcutSender.js';
12
- function parseWatchdogArgs() {
13
- const { values } = parseArgs({
14
- options: {
15
- 'parent-pid': { type: 'string' },
16
- 'app-version': { type: 'string' },
17
- 'os-type': { type: 'string' },
18
- 'log-file': { type: 'string' },
19
- 'clearcut-endpoint': { type: 'string' },
20
- 'clearcut-force-flush-interval-ms': { type: 'string' },
21
- 'clearcut-include-pid-header': { type: 'boolean' },
22
- },
23
- strict: true,
24
- });
25
- // Verify required arguments
26
- const parentPid = parseInt(values['parent-pid'] ?? '', 10);
27
- const appVersion = values['app-version'];
28
- const osType = parseInt(values['os-type'] ?? '', 10);
29
- if (isNaN(parentPid) || !appVersion || isNaN(osType)) {
30
- console.error('Invalid arguments provided for watchdog process: ', JSON.stringify({ parentPid, appVersion, osType }));
31
- process.exit(1);
32
- }
33
- // Parse Optional Arguments
34
- const logFile = values['log-file'];
35
- const clearcutEndpoint = values['clearcut-endpoint'];
36
- const clearcutIncludePidHeader = values['clearcut-include-pid-header'];
37
- let clearcutForceFlushIntervalMs;
38
- if (values['clearcut-force-flush-interval-ms']) {
39
- const parsed = parseInt(values['clearcut-force-flush-interval-ms'], 10);
40
- if (!isNaN(parsed)) {
41
- clearcutForceFlushIntervalMs = parsed;
42
- }
43
- }
44
- return {
45
- parentPid,
46
- appVersion,
47
- osType,
48
- logFile,
49
- clearcutEndpoint,
50
- clearcutForceFlushIntervalMs,
51
- clearcutIncludePidHeader,
52
- };
53
- }
54
- function main() {
55
- const { parentPid, appVersion, osType, logFile, clearcutEndpoint, clearcutForceFlushIntervalMs, clearcutIncludePidHeader, } = parseWatchdogArgs();
56
- let logStream;
57
- if (logFile) {
58
- logStream = saveLogsToFile(logFile);
59
- }
60
- const exit = (code) => {
61
- if (!logStream) {
62
- process.exit(code);
63
- }
64
- void flushLogs(logStream).finally(() => {
65
- process.exit(code);
66
- });
67
- };
68
- logger('Watchdog started', JSON.stringify({
69
- pid: process.pid,
70
- parentPid,
71
- version: appVersion,
72
- osType,
73
- }, null, 2));
74
- const sender = new ClearcutSender({
75
- appVersion,
76
- osType: osType,
77
- clearcutEndpoint,
78
- forceFlushIntervalMs: clearcutForceFlushIntervalMs,
79
- includePidHeader: clearcutIncludePidHeader,
80
- });
81
- let isShuttingDown = false;
82
- function onParentDeath(reason) {
83
- if (isShuttingDown) {
84
- return;
85
- }
86
- isShuttingDown = true;
87
- logger(`Parent death detected (${reason}). Sending shutdown event...`);
88
- sender
89
- .sendShutdownEvent()
90
- .then(() => {
91
- logger('Shutdown event sent. Exiting.');
92
- exit(0);
93
- })
94
- .catch(err => {
95
- logger('Failed to send shutdown event', err);
96
- exit(1);
97
- });
98
- }
99
- process.stdin.on('end', () => onParentDeath('stdin end'));
100
- process.stdin.on('close', () => onParentDeath('stdin close'));
101
- process.on('disconnect', () => onParentDeath('ipc disconnect'));
102
- const rl = readline.createInterface({
103
- input: process.stdin,
104
- terminal: false,
105
- });
106
- rl.on('line', line => {
107
- try {
108
- if (!line.trim()) {
109
- return;
110
- }
111
- const msg = JSON.parse(line);
112
- if (msg.type === WatchdogMessageType.LOG_EVENT && msg.payload) {
113
- sender.enqueueEvent(msg.payload);
114
- }
115
- }
116
- catch (err) {
117
- logger('Failed to parse IPC message', err);
118
- }
119
- });
120
- }
121
- try {
122
- main();
123
- }
124
- catch (err) {
125
- console.error('Watchdog fatal error:', err);
126
- process.exit(1);
127
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- // eslint-disable-next-line no-restricted-imports
7
- import '../../node_modules/chrome-devtools-frontend/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.js';
@@ -1,26 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import 'core-js/modules/es.promise.with-resolvers.js';
7
- import 'core-js/modules/es.set.union.v2.js';
8
- import 'core-js/proposals/iterator-helpers.js';
9
- export { default as yargs } from 'yargs';
10
- export { hideBin } from 'yargs/helpers';
11
- export { default as debug } from 'debug';
12
- export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
13
- export { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
14
- export { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
15
- export { Client } from '@modelcontextprotocol/sdk/client/index.js';
16
- export { SetLevelRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
17
- export { z as zod } from 'zod';
18
- export { Locator, PredefinedNetworkConditions, KnownDevices, CDPSessionEvent, } from 'puppeteer-core';
19
- export { default as puppeteer } from 'puppeteer-core';
20
- export { PipeTransport } from 'puppeteer-core/internal/node/PipeTransport.js';
21
- export { resolveDefaultUserDataDir, detectBrowserPlatform, Browser as BrowserEnum, } from '@puppeteer/browsers';
22
- import { snapshot as snapshotImpl, navigation as navigationImpl, generateReport as generateReportImpl, } from './lighthouse-devtools-mcp-bundle.js';
23
- export const snapshot = snapshotImpl;
24
- export const navigation = navigationImpl;
25
- export const generateReport = generateReportImpl;
26
- export * as DevTools from '../../node_modules/chrome-devtools-frontend/mcp/mcp.js';