@@ -15,11 +15,16 @@ import {
1515 urlsEqual ,
1616} from './DevtoolsUtils.js' ;
1717import type { ListenerMap , UncaughtError } from './PageCollector.js' ;
18- import { NetworkCollector , ConsoleCollector } from './PageCollector.js' ;
18+ import {
19+ asTargetEmitter ,
20+ NetworkCollector ,
21+ ConsoleCollector ,
22+ } from './PageCollector.js' ;
1923import { Locator } from './third_party/index.js' ;
2024import type { DevTools } from './third_party/index.js' ;
2125import type {
2226 Browser ,
27+ BrowserContext ,
2328 ConsoleMessage ,
2429 Debugger ,
2530 Dialog ,
@@ -64,13 +69,15 @@ export interface TextSnapshot {
6469 verbose : boolean ;
6570}
6671
67- interface McpContextOptions {
72+ export interface McpContextOptions {
6873 // Whether the DevTools windows are exposed as pages for debugging of DevTools.
6974 experimentalDevToolsDebugging : boolean ;
7075 // Whether all page-like targets are exposed as pages.
7176 experimentalIncludeAllPages ?: boolean ;
7277 // Whether CrUX data should be fetched.
7378 performanceCrux : boolean ;
79+ // Optional BrowserContext for session isolation.
80+ browserContext ?: BrowserContext ;
7481}
7582
7683const DEFAULT_TIMEOUT = 5_000 ;
@@ -108,12 +115,11 @@ function getExtensionFromMimeType(mimeType: string) {
108115export class McpContext implements Context {
109116 browser : Browser ;
110117 logger : Debugger ;
118+ #browserContext?: BrowserContext ;
111119
112- // The most recent page state.
113120 #pages: Page [ ] = [ ] ;
114121 #pageToDevToolsPage = new Map < Page , Page > ( ) ;
115122 #selectedPage?: Page ;
116- // The most recent snapshot.
117123 #textSnapshot: TextSnapshot | null = null ;
118124 #networkCollector: NetworkCollector ;
119125 #consoleCollector: ConsoleCollector ;
@@ -148,12 +154,15 @@ export class McpContext implements Context {
148154 ) {
149155 this . browser = browser ;
150156 this . logger = logger ;
157+ this . #browserContext = options . browserContext ;
151158 this . #locatorClass = locatorClass ;
152159 this . #options = options ;
153160
154- this . #networkCollector = new NetworkCollector ( this . browser ) ;
161+ const targetEmitter = asTargetEmitter ( this . #browserContext ?? this . browser ) ;
162+
163+ this . #networkCollector = new NetworkCollector ( targetEmitter ) ;
155164
156- this . #consoleCollector = new ConsoleCollector ( this . browser , collect => {
165+ this . #consoleCollector = new ConsoleCollector ( targetEmitter , collect => {
157166 return {
158167 console : event => {
159168 collect ( event ) ;
@@ -166,7 +175,7 @@ export class McpContext implements Context {
166175 } ,
167176 } as ListenerMap ;
168177 } ) ;
169- this . #devtoolsUniverseManager = new UniverseManager ( this . browser ) ;
178+ this . #devtoolsUniverseManager = new UniverseManager ( targetEmitter ) ;
170179 }
171180
172181 async #init( ) {
@@ -263,7 +272,9 @@ export class McpContext implements Context {
263272 }
264273
265274 async newPage ( background ?: boolean ) : Promise < Page > {
266- const page = await this . browser . newPage ( { background} ) ;
275+ const page = this . #browserContext
276+ ? await this . #browserContext. newPage ( )
277+ : await this . browser . newPage ( { background} ) ;
267278 await this . createPagesSnapshot ( ) ;
268279 this . selectPage ( page ) ;
269280 this . #networkCollector. addPage ( page ) ;
@@ -485,9 +496,9 @@ export class McpContext implements Context {
485496 * Creates a snapshot of the pages.
486497 */
487498 async createPagesSnapshot ( ) : Promise < Page [ ] > {
488- const allPages = await this . browser . pages (
489- this . #options . experimentalIncludeAllPages ,
490- ) ;
499+ const allPages = this . #browserContext
500+ ? await this . #browserContext . pages ( )
501+ : await this . browser . pages ( this . #options . experimentalIncludeAllPages ) ;
491502
492503 for ( const page of allPages ) {
493504 if ( ! this . #pageIdMap. has ( page ) ) {
@@ -518,9 +529,9 @@ export class McpContext implements Context {
518529
519530 async detectOpenDevToolsWindows ( ) {
520531 this . logger ( 'Detecting open DevTools windows' ) ;
521- const pages = await this . browser . pages (
522- this . #options . experimentalIncludeAllPages ,
523- ) ;
532+ const pages = this . #browserContext
533+ ? await this . #browserContext . pages ( )
534+ : await this . browser . pages ( this . #options . experimentalIncludeAllPages ) ;
524535 this . #pageToDevToolsPage = new Map < Page , Page > ( ) ;
525536 for ( const devToolsPage of pages ) {
526537 if ( devToolsPage . url ( ) . startsWith ( 'devtools://' ) ) {
@@ -770,7 +781,8 @@ export class McpContext implements Context {
770781 * We need to ignore favicon request as they make our test flaky
771782 */
772783 async setUpNetworkCollectorForTesting ( ) {
773- this . #networkCollector = new NetworkCollector ( this . browser , collect => {
784+ const targetEmitter = asTargetEmitter ( this . #browserContext ?? this . browser ) ;
785+ this . #networkCollector = new NetworkCollector ( targetEmitter , collect => {
774786 return {
775787 request : req => {
776788 if ( req . url ( ) . includes ( 'favicon.ico' ) ) {
@@ -780,7 +792,10 @@ export class McpContext implements Context {
780792 } ,
781793 } as ListenerMap ;
782794 } ) ;
783- await this . #networkCollector. init ( await this . browser . pages ( ) ) ;
795+ const pages = this . #browserContext
796+ ? await this . #browserContext. pages ( )
797+ : await this . browser . pages ( ) ;
798+ await this . #networkCollector. init ( pages ) ;
784799 }
785800
786801 async installExtension ( extensionPath : string ) : Promise < string > {
0 commit comments