@@ -7,6 +7,7 @@ import fs from 'node:fs/promises';
77import os from 'node:os' ;
88import path from 'node:path' ;
99
10+ import { extractUrlLikeFromDevToolsTitle , urlsEqual } from './DevtoolsUtils.js' ;
1011import type { ListenerMap } from './PageCollector.js' ;
1112import { NetworkCollector , PageCollector } from './PageCollector.js' ;
1213import { Locator } from './third_party/index.js' ;
@@ -40,8 +41,8 @@ export interface TextSnapshot {
4041}
4142
4243interface McpContextOptions {
43- // Whether the DevTools windows are exposed as pages.
44- devtools : boolean ;
44+ // Whether the DevTools windows are exposed as pages for debugging of DevTools .
45+ experimentalDevToolsDebugging : boolean ;
4546}
4647
4748const DEFAULT_TIMEOUT = 5_000 ;
@@ -82,6 +83,7 @@ export class McpContext implements Context {
8283
8384 // The most recent page state.
8485 #pages: Page [ ] = [ ] ;
86+ #pageToDevToolsPage = new Map < Page , Page > ( ) ;
8587 #selectedPageIdx = 0 ;
8688 // The most recent snapshot.
8789 #textSnapshot: TextSnapshot | null = null ;
@@ -324,19 +326,50 @@ export class McpContext implements Context {
324326 * Creates a snapshot of the pages.
325327 */
326328 async createPagesSnapshot ( ) : Promise < Page [ ] > {
327- this . #pages = ( await this . browser . pages ( ) ) . filter ( page => {
328- if ( page . url ( ) . startsWith ( 'devtools://' ) ) {
329- return this . #options. devtools ;
329+ const allPages = await this . browser . pages ( ) ;
330+
331+ this . #pages = allPages . filter ( page => {
332+ // If we allow debugging DevTools windows, return all pages.
333+ if ( this . #options. experimentalDevToolsDebugging ) {
334+ return true ;
330335 }
331- return true ;
336+ // If we are in regular mode, the user should only see non-DevTools page.
337+ return ! page . url ( ) . startsWith ( 'devtools://' ) ;
332338 } ) ;
339+
340+ await this . #detectOpenDevToolsWindows( allPages ) ;
341+
333342 return this . #pages;
334343 }
335344
345+ async #detectOpenDevToolsWindows( pages : Page [ ] ) {
346+ this . #pageToDevToolsPage = new Map < Page , Page > ( ) ;
347+ for ( const devToolsPage of pages ) {
348+ if ( devToolsPage . url ( ) . startsWith ( 'devtools://' ) ) {
349+ const session = await devToolsPage . createCDPSession ( ) ;
350+ const data = await session . send ( 'Target.getTargetInfo' ) ;
351+ const devtoolsPageTitle = data . targetInfo . title ;
352+ const urlLike = extractUrlLikeFromDevToolsTitle ( devtoolsPageTitle ) ;
353+ if ( ! urlLike ) {
354+ continue ;
355+ }
356+ for ( const page of this . #pages) {
357+ if ( urlsEqual ( page . url ( ) , urlLike ) ) {
358+ this . #pageToDevToolsPage. set ( page , devToolsPage ) ;
359+ }
360+ }
361+ }
362+ }
363+ }
364+
336365 getPages ( ) : Page [ ] {
337366 return this . #pages;
338367 }
339368
369+ getDevToolsPage ( page : Page ) : Page | undefined {
370+ return this . #pageToDevToolsPage. get ( page ) ;
371+ }
372+
340373 /**
341374 * Creates a text snapshot of a page.
342375 */
0 commit comments