Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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.
- **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.',
),
...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
Loading