@@ -564,11 +564,47 @@ export class McpContext implements Context {
564564 isolatedContextNames : Map < Page , string > ;
565565 } > {
566566 const defaultCtx = this . browser . defaultBrowserContext ( ) ;
567- const allPages = await this . browser . pages (
568- this . #options. experimentalIncludeAllPages ,
569- ) ;
570567
568+ // Enumerate targets individually instead of calling browser.pages() so
569+ // that a single frozen/discarded background tab that times out on
570+ // Network.enable cannot abort the entire page enumeration (see #1230).
571571 const allTargets = this . browser . targets ( ) ;
572+ const pageTargets = allTargets . filter ( target => {
573+ const type = target . type ( ) ;
574+ if ( type === 'page' ) return true ;
575+ if ( this . #options. experimentalIncludeAllPages ) {
576+ return type === 'background_page' || type === 'webview' ;
577+ }
578+ return false ;
579+ } ) ;
580+ const pageResults = await Promise . all (
581+ pageTargets . map ( async target => {
582+ try {
583+ const page = await Promise . race ( [
584+ target . page ( ) ,
585+ new Promise < null > ( resolve =>
586+ setTimeout ( ( ) => resolve ( null ) , DEFAULT_TIMEOUT ) ,
587+ ) ,
588+ ] ) ;
589+ if ( ! page ) {
590+ this . logger (
591+ 'Timed out attaching to target at' ,
592+ target . url ( ) ,
593+ '— likely frozen or discarded' ,
594+ ) ;
595+ }
596+ return page ;
597+ } catch ( err ) {
598+ this . logger (
599+ 'Skipping frozen/discarded target at' ,
600+ target . url ( ) ,
601+ err ,
602+ ) ;
603+ return null ;
604+ }
605+ } ) ,
606+ ) ;
607+ const allPages = pageResults . filter ( ( p ) : p is Page => p !== null ) ;
572608 const extensionTargets = allTargets . filter ( target => {
573609 return (
574610 target . url ( ) . startsWith ( 'chrome-extension://' ) &&
@@ -578,7 +614,12 @@ export class McpContext implements Context {
578614
579615 for ( const target of extensionTargets ) {
580616 // Right now target.page() returns null for popup and side panel pages.
581- let page = await target . page ( ) ;
617+ let page = await Promise . race ( [
618+ target . page ( ) ,
619+ new Promise < null > ( resolve =>
620+ setTimeout ( ( ) => resolve ( null ) , DEFAULT_TIMEOUT ) ,
621+ ) ,
622+ ] ) ;
582623 if ( ! page ) {
583624 // We need to cache pages instances for targets because target.asPage()
584625 // returns a new page instance every time.
0 commit comments