@@ -11,45 +11,53 @@ import path from 'node:path';
1111import type {
1212 Browser ,
1313 ChromeReleaseChannel ,
14- ConnectOptions ,
1514 LaunchOptions ,
1615 Target ,
1716} from 'puppeteer-core' ;
1817import puppeteer from 'puppeteer-core' ;
1918
2019let browser : Browser | undefined ;
2120
22- const ignoredPrefixes = new Set ( [
23- 'chrome://' ,
24- 'chrome-extension ://' ,
25- 'chrome-untrusted ://' ,
26- 'devtools ://',
27- ] ) ;
21+ function makeTargetFilter ( devtools : boolean ) {
22+ const ignoredPrefixes = new Set ( [
23+ 'chrome://' ,
24+ 'chrome-extension ://' ,
25+ 'chrome-untrusted ://',
26+ ] ) ;
2827
29- function targetFilter ( target : Target ) : boolean {
30- if ( target . url ( ) === 'chrome://newtab/' ) {
31- return true ;
28+ if ( ! devtools ) {
29+ ignoredPrefixes . add ( 'devtools://' ) ;
3230 }
33- for ( const prefix of ignoredPrefixes ) {
34- if ( target . url ( ) . startsWith ( prefix ) ) {
35- return false ;
31+ return function targetFilter ( target : Target ) : boolean {
32+ if ( target . url ( ) === 'chrome://newtab/' ) {
33+ return true ;
3634 }
37- }
38- return true ;
35+ for ( const prefix of ignoredPrefixes ) {
36+ if ( target . url ( ) . startsWith ( prefix ) ) {
37+ return false ;
38+ }
39+ }
40+ return true ;
41+ } ;
3942}
4043
41- const connectOptions : ConnectOptions = {
42- targetFilter,
43- } ;
44-
45- export async function ensureBrowserConnected ( browserURL : string ) {
44+ export async function ensureBrowserConnected ( options : {
45+ browserURL : string ;
46+ devtools : boolean ;
47+ } ) {
4648 if ( browser ?. connected ) {
4749 return browser ;
4850 }
4951 browser = await puppeteer . connect ( {
50- ... connectOptions ,
51- browserURL,
52+ targetFilter : makeTargetFilter ( options . devtools ) ,
53+ browserURL : options . browserURL ,
5254 defaultViewport : null ,
55+ // @ts -expect-error no types.
56+ _isPageTarget ( target ) {
57+ return (
58+ target . type ( ) === 'other' && target . url ( ) . startsWith ( 'devtools://' )
59+ ) ;
60+ } ,
5361 } ) ;
5462 return browser ;
5563}
@@ -68,7 +76,8 @@ interface McpLaunchOptions {
6876 height : number ;
6977 } ;
7078 args ?: string [ ] ;
71- }
79+ devtools : boolean ;
80+ } ;
7281
7382export async function launch ( options : McpLaunchOptions ) : Promise < Browser > {
7483 const { channel, executablePath, customDevTools, headless, isolated} = options ;
@@ -101,6 +110,9 @@ export async function launch(options: McpLaunchOptions): Promise<Browser> {
101110 args . push ( '--screen-info={3840x2160}' ) ;
102111 }
103112 let puppeteerChannel : ChromeReleaseChannel | undefined ;
113+ if ( options . devtools ) {
114+ args . push ( '--auto-open-devtools-for-tabs' ) ;
115+ }
104116 if ( ! executablePath ) {
105117 puppeteerChannel =
106118 channel && channel !== 'stable'
@@ -110,15 +122,21 @@ export async function launch(options: McpLaunchOptions): Promise<Browser> {
110122
111123 try {
112124 const browser = await puppeteer . launch ( {
113- ...connectOptions ,
114125 channel : puppeteerChannel ,
126+ targetFilter : makeTargetFilter ( options . devtools ) ,
115127 executablePath,
116128 defaultViewport : null ,
117129 userDataDir,
118130 pipe : true ,
119131 headless,
120132 args,
121133 acceptInsecureCerts : options . acceptInsecureCerts ,
134+ // @ts -expect-error no types.
135+ _isPageTarget ( target ) {
136+ return (
137+ target . type ( ) === 'other' && target . url ( ) . startsWith ( 'devtools://' )
138+ ) ;
139+ } ,
122140 } ) ;
123141 if ( options . logFile ) {
124142 // FIXME: we are probably subscribing too late to catch startup logs. We
0 commit comments