Skip to content

Commit 3d0c06a

Browse files
authored
Merge branch 'main' into feature/extension-debugging
2 parents 4c5b959 + 8e252dd commit 3d0c06a

22 files changed

Lines changed: 456 additions & 306 deletions

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,25 @@ Or, from the IDE **Activity Bar** > `Kiro` > `MCP Servers` > `Click Open MCP Con
241241

242242
</details>
243243

244+
<details>
245+
<summary>OpenCode</summary>
246+
247+
Add the following configuration to your `opencode.json` file. If you don't have one, create it at `~/.config/opencode/opencode.json` (<a href="https://opencode.ai/docs/mcp-servers">guide</a>):
248+
249+
```json
250+
{
251+
"$schema": "https://opencode.ai/config.json",
252+
"mcp": {
253+
"chrome-devtools": {
254+
"type": "local",
255+
"command": ["npx", "-y", "chrome-devtools-mcp@latest"]
256+
}
257+
}
258+
}
259+
```
260+
261+
</details>
262+
244263
<details>
245264
<summary>Qoder</summary>
246265

docs/tool-reference.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131

132132
**Parameters:**
133133

134-
- **pageIdx** (number) **(required)**: The index of the page to close. Call [`list_pages`](#list_pages) to list pages.
134+
- **pageId** (number) **(required)**: The ID of the page to close. Call [`list_pages`](#list_pages) to list pages.
135135

136136
---
137137

@@ -173,7 +173,7 @@
173173

174174
**Parameters:**
175175

176-
- **pageIdx** (number) **(required)**: The index of the page to select. Call [`list_pages`](#list_pages) to get available pages.
176+
- **pageId** (number) **(required)**: The ID of the page to select. Call [`list_pages`](#list_pages) to get available pages.
177177
- **bringToFront** (boolean) _(optional)_: Whether to focus the page and bring it to the top.
178178

179179
---

package-lock.json

Lines changed: 283 additions & 215 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"mcpName": "io.github.ChromeDevTools/chrome-devtools-mcp",
4242
"devDependencies": {
4343
"@eslint/js": "^9.35.0",
44-
"@modelcontextprotocol/sdk": "1.24.3",
44+
"@modelcontextprotocol/sdk": "1.25.2",
4545
"@rollup/plugin-commonjs": "^29.0.0",
4646
"@rollup/plugin-json": "^6.1.0",
4747
"@rollup/plugin-node-resolve": "^16.0.3",
@@ -53,16 +53,16 @@
5353
"@types/yargs": "^17.0.33",
5454
"@typescript-eslint/eslint-plugin": "^8.43.0",
5555
"@typescript-eslint/parser": "^8.43.0",
56-
"chrome-devtools-frontend": "1.0.1555430",
56+
"chrome-devtools-frontend": "1.0.1565595",
5757
"core-js": "3.47.0",
5858
"debug": "4.4.3",
5959
"eslint": "^9.35.0",
6060
"eslint-import-resolver-typescript": "^4.4.4",
6161
"eslint-plugin-import": "^2.32.0",
6262
"globals": "^17.0.0",
6363
"prettier": "^3.6.2",
64-
"puppeteer": "24.33.0",
65-
"rollup": "4.54.0",
64+
"puppeteer": "24.34.0",
65+
"rollup": "4.55.1",
6666
"rollup-plugin-cleanup": "^3.2.1",
6767
"rollup-plugin-license": "^3.6.0",
6868
"sinon": "^21.0.0",

scripts/post-build.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import * as fs from 'node:fs';
88
import * as path from 'node:path';
99

10-
import {sed} from './sed.ts';
11-
1210
const BUILD_DIR = path.join(process.cwd(), 'build');
1311

1412
/**
@@ -73,21 +71,6 @@ export const experiments = {
7371
`;
7472
writeFile(runtimeFile, runtimeContent);
7573

76-
// Update protocol_client to remove:
77-
// 1. self.Protocol assignment
78-
// 2. Call to register backend commands.
79-
const protocolClientDir = path.join(
80-
BUILD_DIR,
81-
devtoolsFrontEndCorePath,
82-
'protocol_client',
83-
);
84-
const clientFile = path.join(protocolClientDir, 'protocol_client.js');
85-
const globalAssignment = /self\.Protocol = self\.Protocol \|\| \{\};/;
86-
const registerCommands =
87-
/InspectorBackendCommands\.registerCommands\(InspectorBackend\.inspectorBackend\);/;
88-
sed(clientFile, globalAssignment, '');
89-
sed(clientFile, registerCommands, '');
90-
9174
copyDevToolsDescriptionFiles();
9275
}
9376

scripts/sed.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/McpContext.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ export class McpContext implements Context {
126126
#geolocationMap = new WeakMap<Page, GeolocationOptions>();
127127
#dialog?: Dialog;
128128

129+
#pageIdMap = new WeakMap<Page, number>();
130+
#nextPageId = 1;
131+
129132
#nextSnapshotId = 1;
130133
#traceResults: TraceResult[] = [];
131134

@@ -261,11 +264,11 @@ export class McpContext implements Context {
261264
this.#consoleCollector.addPage(page);
262265
return page;
263266
}
264-
async closePage(pageIdx: number): Promise<void> {
267+
async closePage(pageId: number): Promise<void> {
265268
if (this.#pages.length === 1) {
266269
throw new Error(CLOSE_PAGE_ERROR);
267270
}
268-
const page = this.getPageByIdx(pageIdx);
271+
const page = this.getPageById(pageId);
269272
await page.close({runBeforeUnload: false});
270273
}
271274

@@ -342,15 +345,18 @@ export class McpContext implements Context {
342345
return page;
343346
}
344347

345-
getPageByIdx(idx: number): Page {
346-
const pages = this.#pages;
347-
const page = pages[idx];
348+
getPageById(pageId: number): Page {
349+
const page = this.#pages.find(p => this.#pageIdMap.get(p) === pageId);
348350
if (!page) {
349351
throw new Error('No page found');
350352
}
351353
return page;
352354
}
353355

356+
getPageId(page: Page): number | undefined {
357+
return this.#pageIdMap.get(page);
358+
}
359+
354360
#dialogHandler = (dialog: Dialog): void => {
355361
this.#dialog = dialog;
356362
};
@@ -432,6 +438,12 @@ export class McpContext implements Context {
432438
this.#options.experimentalIncludeAllPages,
433439
);
434440

441+
for (const page of allPages) {
442+
if (!this.#pageIdMap.has(page)) {
443+
this.#pageIdMap.set(page, this.#nextPageId++);
444+
}
445+
}
446+
435447
this.#pages = allPages.filter(page => {
436448
// If we allow debugging DevTools windows, return all pages.
437449
// If we are in regular mode, the user should only see non-DevTools page.

src/McpResponse.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,10 @@ Call ${handleDialog.name} to handle it before continuing.`);
385385

386386
if (this.#includePages) {
387387
const parts = [`## Pages`];
388-
let idx = 0;
389388
for (const page of context.getPages()) {
390389
parts.push(
391-
`${idx}: ${page.url()}${context.isPageSelected(page) ? ' [selected]' : ''}`,
390+
`${context.getPageId(page)}: ${page.url()}${context.isPageSelected(page) ? ' [selected]' : ''}`,
392391
);
393-
idx++;
394392
}
395393

396394
// Include service workers when extension debugging is enabled

src/browser.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ export async function launch(options: McpLaunchOptions): Promise<Browser> {
224224
}
225225
if (options.viewport) {
226226
const [page] = await browser.pages();
227-
// @ts-expect-error internal API for now.
228227
await page?.resize({
229228
contentWidth: options.viewport.width,
230229
contentHeight: options.viewport.height,

src/formatters/consoleFormatter.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface ConsoleMessageData {
1515
count?: number;
1616
description?: string;
1717
args?: string[];
18+
stackTrace?: DevTools.StackTrace.StackTrace.StackTrace;
1819
}
1920

2021
// The short format for a console message, based on a previous format.
@@ -46,6 +47,7 @@ export function formatConsoleEventVerbose(
4647
`ID: ${msg.consoleMessageStableId}`,
4748
`Message: ${msg.type}> ${aggregatedIssue ? formatIssue(aggregatedIssue, msg.description, context) : msg.message}`,
4849
aggregatedIssue ? undefined : formatArgs(msg),
50+
formatStackTrace(msg.stackTrace),
4951
].filter(line => !!line);
5052
return result.join('\n');
5153
}
@@ -163,3 +165,42 @@ export function formatIssue(
163165
if (result.length === 0) return 'No affected resources found';
164166
return result.join('\n');
165167
}
168+
169+
function formatStackTrace(
170+
stackTrace: DevTools.StackTrace.StackTrace.StackTrace | undefined,
171+
): string {
172+
if (!stackTrace) {
173+
return '';
174+
}
175+
176+
return [
177+
'### Stack trace',
178+
formatFragment(stackTrace.syncFragment),
179+
...stackTrace.asyncFragments.map(formatAsyncFragment),
180+
].join('\n');
181+
}
182+
183+
function formatFragment(
184+
fragment: DevTools.StackTrace.StackTrace.Fragment,
185+
): string {
186+
return fragment.frames.map(formatFrame).join('\n');
187+
}
188+
189+
function formatAsyncFragment(
190+
fragment: DevTools.StackTrace.StackTrace.AsyncFragment,
191+
): string {
192+
const separatorLineLength = 40;
193+
const prefix = `--- ${fragment.description || 'async'} `;
194+
const separator = prefix + '-'.repeat(separatorLineLength - prefix.length);
195+
return separator + '\n' + formatFragment(fragment);
196+
}
197+
198+
function formatFrame(frame: DevTools.StackTrace.StackTrace.Frame): string {
199+
let result = `at ${frame.name ?? '<anonymous>'}`;
200+
if (frame.uiSourceCode) {
201+
result += ` (${frame.uiSourceCode.displayName()}:${frame.line}:${frame.column})`;
202+
} else if (frame.url) {
203+
result += ` (${frame.url}:${frame.line}:${frame.column})`;
204+
}
205+
return result;
206+
}

0 commit comments

Comments
 (0)