From 7f947ba7cbaa3ca4d60c78070ce06513b47db164 Mon Sep 17 00:00:00 2001 From: atian8179 Date: Sun, 8 Mar 2026 15:11:41 +0800 Subject: [PATCH 1/3] fix: list_pages should work after selected page is closed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit list_pages was defined with definePageTool which marks it as pageScoped. This causes the handler dispatch in index.ts to call getSelectedMcpPage() before invoking the handler. When the selected page has been closed, getSelectedPptrPage() throws an error instead of returning the page list. list_pages doesn't actually use the page parameter — its handler only calls response.setIncludePages(true). Change it to defineTool so it bypasses the page-scoped check and works regardless of whether a page is currently selected. Fixes #1138 --- src/tools/pages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/pages.ts b/src/tools/pages.ts index 895632bd3..5e5d3cef7 100644 --- a/src/tools/pages.ts +++ b/src/tools/pages.ts @@ -16,7 +16,7 @@ import { timeoutSchema, } from './ToolDefinition.js'; -export const listPages = definePageTool(args => { +export const listPages = defineTool(args => { return { name: 'list_pages', description: `Get a list of pages ${args?.categoryExtensions ? 'including extension service workers' : ''} open in the browser.`, From 5a3e0f765d0e0b763ea0b1216b125802c6f58cc9 Mon Sep 17 00:00:00 2001 From: atian8179 Date: Tue, 10 Mar 2026 17:19:22 +0800 Subject: [PATCH 2/3] test: add coverage for list_pages after selected page is closed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a test that verifies list_pages works correctly when the currently selected page has been closed externally. This exercises the definePageTool → defineTool change that removes the page-scoped requirement from list_pages. Ref #1138 --- tests/tools/pages.test.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/tools/pages.test.ts b/tests/tools/pages.test.ts index d278cd0a3..e9dc7f2d1 100644 --- a/tests/tools/pages.test.ts +++ b/tests/tools/pages.test.ts @@ -46,7 +46,25 @@ describe('pages', () => { it('list pages', async () => { await withMcpContext(async (response, context) => { await listPages().handler( - {params: {}, page: context.getSelectedMcpPage()}, + {params: {}}, + response, + context, + ); + assert.ok(response.includePages); + }); + }); + it('list pages after selected page is closed', async () => { + await withMcpContext(async (response, context) => { + // Create a second page and select it. + const page2 = await context.newPage(); + assert.strictEqual(context.getSelectedMcpPage(), page2); + + // Close the selected page via puppeteer (simulating external close). + await page2.pptrPage.close(); + + // list_pages should still work even though the selected page is gone. + await listPages().handler( + {params: {}}, response, context, ); @@ -71,7 +89,7 @@ describe('pages', () => { categoryExtensions: true, } as ParsedArguments); await listPageDef.handler( - {params: {}, page: context.getSelectedMcpPage()}, + {params: {}}, response, context, ); @@ -117,7 +135,7 @@ describe('pages', () => { categoryExtensions, } as ParsedArguments); await listPageDef.handler( - {params: {}, page: context.getSelectedMcpPage()}, + {params: {}}, response, context, ); @@ -178,7 +196,7 @@ describe('pages', () => { categoryExtensions: true, } as ParsedArguments); await listPageDef.handler( - {params: {}, page: context.getSelectedMcpPage()}, + {params: {}}, response, context, ); From cd94135c03667354f1539394466462babee291f9 Mon Sep 17 00:00:00 2001 From: Piotr Paulski Date: Mon, 30 Mar 2026 08:26:15 +0000 Subject: [PATCH 3/3] Fix linting issues --- tests/tools/pages.test.ts | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/tests/tools/pages.test.ts b/tests/tools/pages.test.ts index e9dc7f2d1..3fb5892b6 100644 --- a/tests/tools/pages.test.ts +++ b/tests/tools/pages.test.ts @@ -45,11 +45,7 @@ describe('pages', () => { describe('list_pages', () => { it('list pages', async () => { await withMcpContext(async (response, context) => { - await listPages().handler( - {params: {}}, - response, - context, - ); + await listPages().handler({params: {}}, response, context); assert.ok(response.includePages); }); }); @@ -63,11 +59,7 @@ describe('pages', () => { await page2.pptrPage.close(); // list_pages should still work even though the selected page is gone. - await listPages().handler( - {params: {}}, - response, - context, - ); + await listPages().handler({params: {}}, response, context); assert.ok(response.includePages); }); }); @@ -88,11 +80,7 @@ describe('pages', () => { const listPageDef = listPages({ categoryExtensions: true, } as ParsedArguments); - await listPageDef.handler( - {params: {}}, - response, - context, - ); + await listPageDef.handler({params: {}}, response, context); const result = await response.handle(listPageDef.name, context); const textContent = result.content.find(c => c.type === 'text') as { @@ -134,11 +122,7 @@ describe('pages', () => { const listPageDef = listPages({ categoryExtensions, } as ParsedArguments); - await listPageDef.handler( - {params: {}}, - response, - context, - ); + await listPageDef.handler({params: {}}, response, context); const result = await response.handle(listPageDef.name, context); const textContent = result.content.find(c => c.type === 'text') as { @@ -195,11 +179,7 @@ describe('pages', () => { const listPageDef = listPages({ categoryExtensions: true, } as ParsedArguments); - await listPageDef.handler( - {params: {}}, - response, - context, - ); + await listPageDef.handler({params: {}}, response, context); const result = await response.handle(listPageDef.name, context); const textContent = result.content.find(c => c.type === 'text') as {