chrome-devtools-mcp 0.2.1 → 0.2.2

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.
@@ -99,16 +99,20 @@ export class WaitForHelper {
99
99
  });
100
100
  }
101
101
  async waitForEventsAfterAction(action) {
102
- const navigationStartedPromise = this.waitForNavigationStarted();
103
- await action();
104
- try {
105
- const navigationStated = await navigationStartedPromise;
102
+ const navigationFinished = this.waitForNavigationStarted()
103
+ .then(navigationStated => {
106
104
  if (navigationStated) {
107
- await this.#page.waitForNavigation({
105
+ return this.#page.waitForNavigation({
108
106
  timeout: this.#navigationTimeout,
109
107
  signal: this.#abortController.signal,
110
108
  });
111
109
  }
110
+ return;
111
+ })
112
+ .catch(error => logger(error));
113
+ await action();
114
+ try {
115
+ await navigationFinished;
112
116
  // Wait for stable dom after navigation so we execute in
113
117
  // the correct context
114
118
  await this.waitForStableDom();
@@ -71,6 +71,22 @@ export const cliOptions = {
71
71
  hidden: true,
72
72
  },
73
73
  };
74
+ function readPackageJson() {
75
+ const currentDir = import.meta.dirname;
76
+ const packageJsonPath = path.join(currentDir, '..', '..', 'package.json');
77
+ if (!fs.existsSync(packageJsonPath)) {
78
+ return {};
79
+ }
80
+ try {
81
+ const json = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
82
+ assert.strict(json['name'], 'chrome-devtools-mcp');
83
+ return json;
84
+ }
85
+ catch {
86
+ return {};
87
+ }
88
+ }
89
+ const version = readPackageJson().version ?? 'unknown';
74
90
  const yargsInstance = yargs(hideBin(process.argv))
75
91
  .scriptName('npx chrome-devtools-mcp@latest')
76
92
  .options(cliOptions)
@@ -97,24 +113,9 @@ const yargsInstance = yargs(hideBin(process.argv))
97
113
  export const args = yargsInstance
98
114
  .wrap(Math.min(120, yargsInstance.terminalWidth()))
99
115
  .help()
116
+ .version(version)
100
117
  .parseSync();
101
118
  const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;
102
- function readPackageJson() {
103
- const currentDir = import.meta.dirname;
104
- const packageJsonPath = path.join(currentDir, '..', '..', 'package.json');
105
- if (!fs.existsSync(packageJsonPath)) {
106
- return {};
107
- }
108
- try {
109
- const json = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
110
- assert.strict(json['name'], 'chrome-devtools-mcp');
111
- return json;
112
- }
113
- catch {
114
- return {};
115
- }
116
- }
117
- const version = readPackageJson().version ?? 'unknown';
118
119
  logger(`Starting Chrome DevTools MCP Server v${version}`);
119
120
  const server = new McpServer({
120
121
  name: 'chrome_devtools',
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import z from 'zod';
7
7
  import { defineTool } from './ToolDefinition.js';
8
- import { getInsightOutput, getTraceSummary, parseRawTraceBuffer, } from '../trace-processing/parse.js';
8
+ import { getInsightOutput, getTraceSummary, parseRawTraceBuffer, traceResultIsSuccess, } from '../trace-processing/parse.js';
9
9
  import { logger } from '../logger.js';
10
10
  import { ToolCategories } from './categories.js';
11
11
  export const startTrace = defineTool({
@@ -122,20 +122,22 @@ async function stopTracingAndAppendOutput(page, response, context) {
122
122
  const traceEventsBuffer = await page.tracing.stop();
123
123
  const result = await parseRawTraceBuffer(traceEventsBuffer);
124
124
  response.appendResponseLine('The performance trace has been stopped.');
125
- if (result) {
125
+ if (traceResultIsSuccess(result)) {
126
126
  context.storeTraceRecording(result);
127
- const insightText = getTraceSummary(result);
128
- if (insightText) {
129
- response.appendResponseLine('Insights with performance opportunities:');
130
- response.appendResponseLine(insightText);
131
- }
132
- else {
133
- response.appendResponseLine('No insights have been found. The performance looks good!');
134
- }
127
+ response.appendResponseLine('Here is a high level summary of the trace and the Insights that were found:');
128
+ const traceSummaryText = getTraceSummary(result);
129
+ response.appendResponseLine(traceSummaryText);
130
+ }
131
+ else {
132
+ response.appendResponseLine('There was an unexpected error parsing the trace:');
133
+ response.appendResponseLine(result.error);
135
134
  }
136
135
  }
137
136
  catch (e) {
138
- logger(`Error stopping performance trace: ${e instanceof Error ? e.message : JSON.stringify(e)}`);
137
+ const errorText = e instanceof Error ? e.message : JSON.stringify(e);
138
+ logger(`Error stopping performance trace: ${errorText}`);
139
+ response.appendResponseLine('An error occured generating the response for this trace:');
140
+ response.appendResponseLine(errorText);
139
141
  }
140
142
  finally {
141
143
  context.setIsRunningPerformanceTrace(false);
@@ -9,14 +9,21 @@ import * as TraceEngine from '../../node_modules/chrome-devtools-frontend/front_
9
9
  import { logger } from '../logger.js';
10
10
  import { AgentFocus } from '../../node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIContext.js';
11
11
  const engine = TraceEngine.TraceModel.Model.createWithAllHandlers();
12
+ export function traceResultIsSuccess(x) {
13
+ return 'parsedTrace' in x;
14
+ }
12
15
  export async function parseRawTraceBuffer(buffer) {
13
16
  engine.resetProcessor();
14
17
  if (!buffer) {
15
- return null;
18
+ return {
19
+ error: 'No buffer was provided.',
20
+ };
16
21
  }
17
22
  const asString = new TextDecoder().decode(buffer);
18
23
  if (!asString) {
19
- return null;
24
+ return {
25
+ error: 'Decoding the trace buffer returned an empty string.',
26
+ };
20
27
  }
21
28
  try {
22
29
  const data = JSON.parse(asString);
@@ -24,25 +31,22 @@ export async function parseRawTraceBuffer(buffer) {
24
31
  await engine.parse(events);
25
32
  const parsedTrace = engine.parsedTrace();
26
33
  if (!parsedTrace) {
27
- return null;
28
- }
29
- const insights = parsedTrace?.insights;
30
- if (!insights) {
31
- return null;
34
+ return {
35
+ error: 'No parsed trace was returned from the trace engine.',
36
+ };
32
37
  }
38
+ const insights = parsedTrace?.insights ?? null;
33
39
  return {
34
40
  parsedTrace,
35
41
  insights,
36
42
  };
37
43
  }
38
44
  catch (e) {
39
- if (e instanceof Error) {
40
- logger(`Error parsing trace: ${e.message}`);
41
- }
42
- else {
43
- logger(`Error parsing trace: ${JSON.stringify(e)}`);
44
- }
45
- return null;
45
+ const errorText = e instanceof Error ? e.message : JSON.stringify(e);
46
+ logger(`Unexpeced error parsing trace: ${errorText}`);
47
+ return {
48
+ error: errorText,
49
+ };
46
50
  }
47
51
  }
48
52
  export function getTraceSummary(result) {
@@ -53,6 +57,11 @@ export function getTraceSummary(result) {
53
57
  return output;
54
58
  }
55
59
  export function getInsightOutput(result, insightName) {
60
+ if (!result.insights) {
61
+ return {
62
+ error: 'No Performance insights are available for this trace.',
63
+ };
64
+ }
56
65
  // Currently, we do not support inspecting traces with multiple navigations. We either:
57
66
  // 1. Find Insights from the first navigation (common case: user records a trace with a page reload to test load performance)
58
67
  // 2. Fall back to finding Insights not associated with a navigation (common case: user tests an interaction without a page load).
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "MCP server for Chrome DevTools",
5
5
  "type": "module",
6
- "bin": {
7
- "chrome-devtools-mcp": "./build/src/index.js"
8
- },
6
+ "bin": "./build/src/index.js",
9
7
  "main": "index.js",
10
8
  "scripts": {
11
9
  "build": "tsc && node --experimental-strip-types --no-warnings=ExperimentalWarning scripts/post-build.ts",
@@ -38,7 +36,7 @@
38
36
  "dependencies": {
39
37
  "@modelcontextprotocol/sdk": "1.18.1",
40
38
  "debug": "4.4.3",
41
- "puppeteer-core": "24.22.0",
39
+ "puppeteer-core": "24.22.2",
42
40
  "yargs": "18.0.0"
43
41
  },
44
42
  "devDependencies": {
@@ -54,7 +52,7 @@
54
52
  "eslint": "^9.35.0",
55
53
  "globals": "^16.4.0",
56
54
  "prettier": "^3.6.2",
57
- "puppeteer": "24.22.0",
55
+ "puppeteer": "24.22.2",
58
56
  "sinon": "^21.0.0",
59
57
  "typescript": "^5.9.2",
60
58
  "typescript-eslint": "^8.43.0"