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