Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/tool-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
**Parameters:**

- **url** (string) **(required)**: URL to load in a new page.
- **background** (boolean) _(optional)_: Whether to open the page in the background without bringing it to the front. Default is false (foreground).
- **timeout** (integer) _(optional)_: Maximum wait time in milliseconds. If set to 0, the default timeout will be used.

---
Expand Down
4 changes: 2 additions & 2 deletions src/McpContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ export class McpContext implements Context {
return this.#consoleCollector.getById(this.getSelectedPage(), id);
}

async newPage(): Promise<Page> {
const page = await this.browser.newPage();
async newPage(background?: boolean): Promise<Page> {
const page = await this.browser.newPage({background});
await this.createPagesSnapshot();
this.selectPage(page);
this.#networkCollector.addPage(page);
Expand Down
2 changes: 1 addition & 1 deletion src/tools/ToolDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export type Context = Readonly<{
getPageById(pageId: number): Page;
getPageId(page: Page): number | undefined;
isPageSelected(page: Page): boolean;
newPage(): Promise<Page>;
newPage(background?: boolean): Promise<Page>;
closePage(pageId: number): Promise<void>;
selectPage(page: Page): void;
getElementByUid(uid: string): Promise<ElementHandle<Element>>;
Expand Down
8 changes: 7 additions & 1 deletion src/tools/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ export const newPage = defineTool({
},
schema: {
url: zod.string().describe('URL to load in a new page.'),
background: zod
.boolean()
.optional()
.describe(
'Whether to open the page in the background without bringing it to the front. Default is false (foreground).',
),
...timeoutSchema,
},
handler: async (request, response, context) => {
const page = await context.newPage();
const page = await context.newPage(request.params.background);

await context.waitForEventsAfterAction(async () => {
await page.goto(request.params.url, {
Expand Down
24 changes: 24 additions & 0 deletions tests/tools/pages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@ describe('pages', () => {
assert.ok(response.includePages);
});
});
it('create a page in the background', async () => {
await withMcpContext(async (response, context) => {
const originalPage = context.getPageById(1);
assert.strictEqual(originalPage, context.getSelectedPage());
// Ensure original page has focus
await originalPage.bringToFront();
assert.strictEqual(
await originalPage.evaluate(() => document.hasFocus()),
true,
);
await newPage.handler(
{params: {url: 'about:blank', background: true}},
response,
context,
);
// New page should be selected but original should retain focus
assert.strictEqual(context.getPageById(2), context.getSelectedPage());
assert.strictEqual(
await originalPage.evaluate(() => document.hasFocus()),
true,
);
assert.ok(response.includePages);
});
});
});
describe('close_page', () => {
it('closes a page', async () => {
Expand Down