Skip to content

Commit d0b59a3

Browse files
committed
feat: get state from the open DevTools window
1 parent 73be1b4 commit d0b59a3

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

src/McpContext.ts

Lines changed: 43 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://')) {
@@ -376,6 +377,46 @@ export class McpContext implements Context {
376377
getDevToolsPage(page: Page): Page | undefined {
377378
return this.#pageToDevToolsPage.get(page);
378379
}
380+
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(SDK.NetworkRequest.NetworkRequest);
392+
return request?.requestId();
393+
});
394+
let requestId: number|undefined;
395+
if (!cdpRequestId) {
396+
console.error('no context request');
397+
return;
398+
}
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+
console.error('no collected request for ' + cdpRequestId);
406+
return;
407+
}
408+
requestId = this.#networkCollector.getIdForResource(request);
409+
return {
410+
requestId,
411+
}
412+
} else {
413+
console.error('no devtools page deteched');
414+
}
415+
} catch (err) {
416+
console.error('error getting devtools data', err);
417+
}
418+
return;
419+
}
379420

380421
/**
381422
* Creates a text snapshot of a page.

src/McpResponse.ts

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

294+
295+
const devToolsData = await context.getDevToolsContextData();
296+
294297
return this.format(toolName, context, {
295298
bodies,
296299
consoleData,
297300
consoleListData,
298301
formattedSnapshot,
302+
devToolsData,
299303
});
300304
}
301305

@@ -310,13 +314,19 @@ export class McpResponse implements Response {
310314
consoleData: ConsoleMessageData | undefined;
311315
consoleListData: ConsoleMessageData[] | undefined;
312316
formattedSnapshot: string | undefined;
317+
devToolsData?: {requestId?: number},
313318
},
314319
): Array<TextContent | ImageContent> {
315320
const response = [`# ${toolName} response`];
316321
for (const line of this.#textResponseLines) {
317322
response.push(line);
318323
}
319324

325+
if (data.devToolsData?.requestId) {
326+
response.push('## DevTools context');
327+
response.push(`Network request reqid=${data.devToolsData?.requestId} is currently being inspected by the user in DevTools.`)
328+
}
329+
320330
const networkConditions = context.getNetworkConditions();
321331
if (networkConditions) {
322332
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)