Skip to content

Commit ab01738

Browse files
committed
feat: get state from the open DevTools window
1 parent 43897af commit ab01738

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

src/McpContext.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,13 @@ export class McpContext implements Context {
337337
);
338338
});
339339

340-
await this.#detectOpenDevToolsWindows(allPages);
340+
await this.detectOpenDevToolsWindows();
341341

342342
return this.#pages;
343343
}
344344

345-
async #detectOpenDevToolsWindows(pages: Page[]) {
345+
async detectOpenDevToolsWindows() {
346+
const pages = await this.browser.pages();
346347
this.#pageToDevToolsPage = new Map<Page, Page>();
347348
for (const devToolsPage of pages) {
348349
if (devToolsPage.url().startsWith('devtools://')) {
@@ -377,6 +378,45 @@ export class McpContext implements Context {
377378
return this.#pageToDevToolsPage.get(page);
378379
}
379380

381+
async getDevToolsContextData(): Promise<undefined | {requestId?: number}> {
382+
try {
383+
const selectedPage = this.getSelectedPage();
384+
const devtoolsPage = this.getDevToolsPage(selectedPage);
385+
if (devtoolsPage) {
386+
const cdpRequestId = await devtoolsPage.evaluate(async () => {
387+
// @ts-expect-error no types
388+
const UI = await import('/bundled/ui/legacy/legacy.js');
389+
// @ts-expect-error no types
390+
const SDK = await import('/bundled/core/sdk/sdk.js');
391+
const request = UI.Context.Context.instance().flavor(
392+
SDK.NetworkRequest.NetworkRequest,
393+
);
394+
return request?.requestId();
395+
});
396+
if (!cdpRequestId) {
397+
this.logger('no context request');
398+
return;
399+
}
400+
const request = this.#networkCollector.find(selectedPage, request => {
401+
// @ts-expect-error id is internal.
402+
return request.id === cdpRequestId;
403+
});
404+
if (!request) {
405+
this.logger('no collected request for ' + cdpRequestId);
406+
return;
407+
}
408+
return {
409+
requestId: this.#networkCollector.getIdForResource(request),
410+
};
411+
} else {
412+
this.logger('no devtools page deteched');
413+
}
414+
} catch (err) {
415+
this.logger('error getting devtools data', err);
416+
}
417+
return;
418+
}
419+
380420
/**
381421
* Creates a text snapshot of a page.
382422
*/

src/McpResponse.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,14 @@ export class McpResponse implements Response {
291291
);
292292
}
293293

294+
const devToolsData = await context.getDevToolsContextData();
295+
294296
return this.format(toolName, context, {
295297
bodies,
296298
consoleData,
297299
consoleListData,
298300
formattedSnapshot,
301+
devToolsData,
299302
});
300303
}
301304

@@ -310,13 +313,23 @@ export class McpResponse implements Response {
310313
consoleData: ConsoleMessageData | undefined;
311314
consoleListData: ConsoleMessageData[] | undefined;
312315
formattedSnapshot: string | undefined;
316+
devToolsData?: {requestId?: number};
313317
},
314318
): Array<TextContent | ImageContent> {
315319
const response = [`# ${toolName} response`];
316320
for (const line of this.#textResponseLines) {
317321
response.push(line);
318322
}
319323

324+
response.push('## Network requests inspected in DevTools');
325+
if (data.devToolsData?.requestId) {
326+
response.push(`Network request: reqid=${data.devToolsData?.requestId}`);
327+
} else {
328+
response.push(
329+
`Nothing inspected right now. Call list_pages if you need to check DevTools`,
330+
);
331+
}
332+
320333
const networkConditions = context.getNetworkConditions();
321334
if (networkConditions) {
322335
response.push(`## Network emulation`);

src/PageCollector.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ export class PageCollector<T> {
173173

174174
throw new Error('Request not found for selected page');
175175
}
176+
177+
find(page: Page, filter: (item: T) => boolean): T | undefined {
178+
const navigations = this.storage.get(page);
179+
if (!navigations) {
180+
return;
181+
}
182+
183+
for (const navigation of navigations) {
184+
for (const collected of navigation) {
185+
if (filter(collected)) {
186+
return collected;
187+
}
188+
}
189+
}
190+
return;
191+
}
176192
}
177193

178194
export class NetworkCollector extends PageCollector<HTTPRequest> {

src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ function registerTool(tool: ToolDefinition): void {
129129
try {
130130
logger(`${tool.name} request: ${JSON.stringify(params, null, ' ')}`);
131131
const context = await getContext();
132+
await context.detectOpenDevToolsWindows();
132133
const response = new McpResponse();
133134
await tool.handler(
134135
{

0 commit comments

Comments
 (0)