From f4e19127475c1b8dae95960584f194ff20b9858a Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 12 Sep 2025 09:09:21 -0700 Subject: [PATCH 1/2] fix(mcp): allowed/blcked-origin accept origins not hosts --- packages/playwright/src/mcp/browser/context.ts | 4 ++-- tests/mcp/request-blocking.spec.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/playwright/src/mcp/browser/context.ts b/packages/playwright/src/mcp/browser/context.ts index cabfa540ad622..a30a40f270ac8 100644 --- a/packages/playwright/src/mcp/browser/context.ts +++ b/packages/playwright/src/mcp/browser/context.ts @@ -177,12 +177,12 @@ export class Context { await context.route('**', route => route.abort('blockedbyclient')); for (const origin of this.config.network.allowedOrigins) - await context.route(`*://${origin}/**`, route => route.continue()); + await context.route(`${origin}/**`, route => route.continue()); } if (this.config.network?.blockedOrigins?.length) { for (const origin of this.config.network.blockedOrigins) - await context.route(`*://${origin}/**`, route => route.abort('blockedbyclient')); + await context.route(`${origin}/**`, route => route.abort('blockedbyclient')); } } diff --git a/tests/mcp/request-blocking.spec.ts b/tests/mcp/request-blocking.spec.ts index 0bcfd343010af..ac4b6a47124ba 100644 --- a/tests/mcp/request-blocking.spec.ts +++ b/tests/mcp/request-blocking.spec.ts @@ -38,7 +38,7 @@ test('default to allow all', async ({ server, client }) => { test('blocked works', async ({ startClient }) => { const { client } = await startClient({ - args: ['--blocked-origins', 'microsoft.com;example.com;playwright.dev'] + args: ['--blocked-origins', 'https://microsoft.com;https://example.com;https://playwright.dev'] }); const result = await fetchPage(client, 'https://example.com/'); expect(result).toMatch(BLOCK_MESSAGE); @@ -47,7 +47,7 @@ test('blocked works', async ({ startClient }) => { test('allowed works', async ({ server, startClient }) => { server.setContent('/ppp', 'content:PPP', 'text/html'); const { client } = await startClient({ - args: ['--allowed-origins', `microsoft.com;${new URL(server.PREFIX).host};playwright.dev`] + args: ['--allowed-origins', `https://microsoft.com;${new URL(server.PREFIX).origin};https://playwright.dev`] }); const result = await fetchPage(client, server.PREFIX + '/ppp'); expect(result).toContain('content:PPP'); @@ -56,8 +56,8 @@ test('allowed works', async ({ server, startClient }) => { test('blocked takes precedence', async ({ startClient }) => { const { client } = await startClient({ args: [ - '--blocked-origins', 'example.com', - '--allowed-origins', 'example.com', + '--blocked-origins', 'https://example.com', + '--allowed-origins', 'https://example.com', ], }); const result = await fetchPage(client, 'https://example.com/'); @@ -66,7 +66,7 @@ test('blocked takes precedence', async ({ startClient }) => { test('allowed without blocked blocks all non-explicitly specified origins', async ({ startClient }) => { const { client } = await startClient({ - args: ['--allowed-origins', 'playwright.dev'], + args: ['--allowed-origins', 'https://playwright.dev'], }); const result = await fetchPage(client, 'https://example.com/'); expect(result).toMatch(BLOCK_MESSAGE); From 90b98fc8b2c478f0fc34872453ef7fb4b1ed26f8 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 12 Sep 2025 09:24:42 -0700 Subject: [PATCH 2/2] support legacy host only --- .../playwright/src/mcp/browser/context.ts | 16 +++++- tests/mcp/request-blocking.spec.ts | 55 +++++++++++++++++-- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/packages/playwright/src/mcp/browser/context.ts b/packages/playwright/src/mcp/browser/context.ts index a30a40f270ac8..3b9584802bb81 100644 --- a/packages/playwright/src/mcp/browser/context.ts +++ b/packages/playwright/src/mcp/browser/context.ts @@ -177,12 +177,12 @@ export class Context { await context.route('**', route => route.abort('blockedbyclient')); for (const origin of this.config.network.allowedOrigins) - await context.route(`${origin}/**`, route => route.continue()); + await context.route(originOrHostGlob(origin), route => route.continue()); } if (this.config.network?.blockedOrigins?.length) { for (const origin of this.config.network.blockedOrigins) - await context.route(`${origin}/**`, route => route.abort('blockedbyclient')); + await context.route(originOrHostGlob(origin), route => route.abort('blockedbyclient')); } } @@ -234,6 +234,18 @@ export class Context { } } +function originOrHostGlob(originOrHost: string) { + try { + const url = new URL(originOrHost); + // localhost:1234 will parse as protocol 'localhost:' and 'null' origin. + if (url.origin !== 'null') + return `${url.origin}/**`; + } catch { + } + // Support for legacy host-only mode. + return `*://${originOrHost}/**`; +} + export class InputRecorder { private _context: Context; private _browserContext: playwright.BrowserContext; diff --git a/tests/mcp/request-blocking.spec.ts b/tests/mcp/request-blocking.spec.ts index ac4b6a47124ba..a2ca31879ba70 100644 --- a/tests/mcp/request-blocking.spec.ts +++ b/tests/mcp/request-blocking.spec.ts @@ -36,7 +36,15 @@ test('default to allow all', async ({ server, client }) => { expect(result).toContain('content:PPP'); }); -test('blocked works', async ({ startClient }) => { +test('blocked works (hostname)', async ({ startClient }) => { + const { client } = await startClient({ + args: ['--blocked-origins', 'microsoft.com;example.com;playwright.dev'] + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('blocked works (origin)', async ({ startClient }) => { const { client } = await startClient({ args: ['--blocked-origins', 'https://microsoft.com;https://example.com;https://playwright.dev'] }); @@ -44,7 +52,16 @@ test('blocked works', async ({ startClient }) => { expect(result).toMatch(BLOCK_MESSAGE); }); -test('allowed works', async ({ server, startClient }) => { +test('allowed works (hostname)', async ({ server, startClient }) => { + server.setContent('/ppp', 'content:PPP', 'text/html'); + const { client } = await startClient({ + args: ['--allowed-origins', `microsoft.com;${new URL(server.PREFIX).host};playwright.dev`] + }); + const result = await fetchPage(client, server.PREFIX + '/ppp'); + expect(result).toContain('content:PPP'); +}); + +test('allowed works (origin)', async ({ server, startClient }) => { server.setContent('/ppp', 'content:PPP', 'text/html'); const { client } = await startClient({ args: ['--allowed-origins', `https://microsoft.com;${new URL(server.PREFIX).origin};https://playwright.dev`] @@ -53,7 +70,18 @@ test('allowed works', async ({ server, startClient }) => { expect(result).toContain('content:PPP'); }); -test('blocked takes precedence', async ({ startClient }) => { +test('blocked takes precedence (hostname)', async ({ startClient }) => { + const { client } = await startClient({ + args: [ + '--blocked-origins', 'example.com', + '--allowed-origins', 'example.com', + ], + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('blocked takes precedence (origin)', async ({ startClient }) => { const { client } = await startClient({ args: [ '--blocked-origins', 'https://example.com', @@ -64,7 +92,15 @@ test('blocked takes precedence', async ({ startClient }) => { expect(result).toMatch(BLOCK_MESSAGE); }); -test('allowed without blocked blocks all non-explicitly specified origins', async ({ startClient }) => { +test('allowed without blocked blocks all non-explicitly specified origins (hostname)', async ({ startClient }) => { + const { client } = await startClient({ + args: ['--allowed-origins', 'playwright.dev'], + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('allowed without blocked blocks all non-explicitly specified origins (origin)', async ({ startClient }) => { const { client } = await startClient({ args: ['--allowed-origins', 'https://playwright.dev'], }); @@ -72,7 +108,7 @@ test('allowed without blocked blocks all non-explicitly specified origins', asyn expect(result).toMatch(BLOCK_MESSAGE); }); -test('blocked without allowed allows non-explicitly specified origins', async ({ server, startClient }) => { +test('blocked without allowed allows non-explicitly specified origins (hostname)', async ({ server, startClient }) => { server.setContent('/ppp', 'content:PPP', 'text/html'); const { client } = await startClient({ args: ['--blocked-origins', 'example.com'], @@ -80,3 +116,12 @@ test('blocked without allowed allows non-explicitly specified origins', async ({ const result = await fetchPage(client, server.PREFIX + '/ppp'); expect(result).toContain('content:PPP'); }); + +test('blocked without allowed allows non-explicitly specified origins (origin)', async ({ server, startClient }) => { + server.setContent('/ppp', 'content:PPP', 'text/html'); + const { client } = await startClient({ + args: ['--blocked-origins', 'https://example.com'], + }); + const result = await fetchPage(client, server.PREFIX + '/ppp'); + expect(result).toContain('content:PPP'); +});