Skip to content

Commit 52374e9

Browse files
committed
feat: support extra headers
feat: try simplify headers setting
1 parent 4a87702 commit 52374e9

4 files changed

Lines changed: 66 additions & 4 deletions

File tree

src/McpContext.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ interface McpContextOptions {
5858
experimentalDevToolsDebugging: boolean;
5959
// Whether all page-like targets are exposed as pages.
6060
experimentalIncludeAllPages?: boolean;
61+
// Custom headers to add to all network requests made by the browser.
62+
headers?: Record<string, string>;
6163
}
6264

6365
const DEFAULT_TIMEOUT = 5_000;
@@ -104,6 +106,9 @@ export class McpContext implements Context {
104106
#textSnapshot: TextSnapshot | null = null;
105107
#networkCollector: NetworkCollector;
106108
#consoleCollector: ConsoleCollector;
109+
110+
// Custom headers to add to all network requests made by the browser.
111+
#headers?: Record<string, string>;
107112

108113
#isRunningTrace = false;
109114
#networkConditionsMap = new WeakMap<Page, string>();
@@ -127,8 +132,11 @@ export class McpContext implements Context {
127132
this.logger = logger;
128133
this.#locatorClass = locatorClass;
129134
this.#options = options;
135+
this.#headers = options.headers;
130136

131-
this.#networkCollector = new NetworkCollector(this.browser);
137+
this.#networkCollector = new NetworkCollector(this.browser, undefined, {
138+
headers: this.#headers,
139+
});
132140

133141
this.#consoleCollector = new ConsoleCollector(this.browser, collect => {
134142
return {
@@ -675,6 +683,8 @@ export class McpContext implements Context {
675683
collect(req);
676684
},
677685
} as ListenerMap;
686+
}, {
687+
headers: this.#headers,
678688
});
679689
await this.#networkCollector.init(await this.browser.pages());
680690
}

src/PageCollector.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ class PageIssueSubscriber {
349349
}
350350

351351
export class NetworkCollector extends PageCollector<HTTPRequest> {
352+
#headers?: Record<string, string>;
353+
352354
constructor(
353355
browser: Browser,
354356
listeners: (
@@ -360,8 +362,36 @@ export class NetworkCollector extends PageCollector<HTTPRequest> {
360362
},
361363
} as ListenerMap;
362364
},
365+
options?: Record<string, unknown> & {
366+
headers?: Record<string, string>
367+
}
363368
) {
364369
super(browser, listeners);
370+
if (options?.headers) {
371+
this.#headers = options?.headers;
372+
}
373+
}
374+
375+
override async init(pages: Page[]): Promise<void> {
376+
for (const page of pages) {
377+
await this.#applyHeadersToPage(page);
378+
}
379+
await super.init(pages);
380+
}
381+
382+
override addPage(page: Page): void {
383+
super.addPage(page);
384+
void this.#applyHeadersToPage(page);
385+
}
386+
387+
async #applyHeadersToPage(page: Page): Promise<void> {
388+
if (this.#headers) {
389+
try {
390+
await page.setExtraHTTPHeaders(this.#headers);
391+
} catch (error) {
392+
logger('Error applying headers to page:', error);
393+
}
394+
}
365395
}
366396
override splitAfterNavigation(page: Page) {
367397
const navigations = this.storage.get(page) ?? [];

src/cli.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,27 @@ export const cliOptions = {
8787
}
8888
},
8989
},
90+
headers: {
91+
type: 'string',
92+
description:
93+
'Custom headers to add to all network requests made by the browser in JSON format (e.g., \'{"Authorization":"Bearer token","User-Agent":"Custom"}\').',
94+
coerce: (val: string | undefined) => {
95+
if (!val) {
96+
return;
97+
}
98+
try {
99+
const parsed = JSON.parse(val);
100+
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
101+
throw new Error('Headers must be a JSON object');
102+
}
103+
return parsed as Record<string, string>;
104+
} catch (error) {
105+
throw new Error(
106+
`Invalid JSON for headers: ${(error as Error).message}`,
107+
);
108+
}
109+
},
110+
},
90111
headless: {
91112
type: 'boolean',
92113
description: 'Whether to run in headless (no UI) mode.',

src/main.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ async function getContext(): Promise<McpContext> {
8585

8686
if (context?.browser !== browser) {
8787
context = await McpContext.from(browser, logger, {
88-
experimentalDevToolsDebugging: devtools,
89-
experimentalIncludeAllPages: args.experimentalIncludeAllPages,
90-
});
88+
experimentalDevToolsDebugging: devtools,
89+
experimentalIncludeAllPages: args.experimentalIncludeAllPages,
90+
headers: args.headers,
91+
});
9192
}
9293
return context;
9394
}

0 commit comments

Comments
 (0)