diff --git a/packages/playwright-core/src/tools/mcp/browserFactory.ts b/packages/playwright-core/src/tools/mcp/browserFactory.ts index ad08a527f69b7..494d71ffa97d4 100644 --- a/packages/playwright-core/src/tools/mcp/browserFactory.ts +++ b/packages/playwright-core/src/tools/mcp/browserFactory.ts @@ -119,7 +119,9 @@ async function createCDPBrowser(config: FullConfig): Promise { testDebug('create browser (remote)'); - const descriptor = await serverRegistry.find(config.browser.remoteEndpoint!); + const remoteEndpoint = config.browser.remoteEndpoint!; + const endpoint = typeof remoteEndpoint === 'string' ? remoteEndpoint : remoteEndpoint.endpoint; + const descriptor = await serverRegistry.find(endpoint); if (descriptor) { const browser = await connectToBrowserAcrossVersions(descriptor); return { @@ -135,10 +137,10 @@ async function createRemoteBrowser(config: FullConfig): Promise }; } - const endpoint = config.browser.remoteEndpoint!; + const connectOptions = typeof remoteEndpoint === 'string' ? { endpoint: remoteEndpoint } : remoteEndpoint; const playwrightObject = playwright as Playwright; // Use connectToBrowser instead of playwright[browserName].connect because we don't have browserName. - const browser = await connectToBrowser(playwrightObject, { endpoint }); + const browser = await connectToBrowser(playwrightObject, connectOptions); browser._connectToBrowserType(playwrightObject[browser._browserName], {}, undefined); return { browser, browserInfo: browserInfo(browser, config), canBind: false, ownership: 'attached' }; } diff --git a/packages/playwright-core/src/tools/mcp/config.d.ts b/packages/playwright-core/src/tools/mcp/config.d.ts index 6756d9a731650..06bdda2128d47 100644 --- a/packages/playwright-core/src/tools/mcp/config.d.ts +++ b/packages/playwright-core/src/tools/mcp/config.d.ts @@ -83,8 +83,11 @@ export type Config = { /** * Remote endpoint to connect to an existing Playwright server. + * Can be a URL string or a ConnectOptions object for advanced configuration + * (e.g. `exposeNetwork`, `headers`, `slowMo`, `timeout`). + * @see https://playwright.dev/docs/api/class-browsertype#browser-type-connect */ - remoteEndpoint?: string; + remoteEndpoint?: string | playwright.ConnectOptions & { endpoint: string }; /** * Paths to TypeScript files to add as initialization scripts for Playwright page. diff --git a/tests/mcp/config.spec.ts b/tests/mcp/config.spec.ts index cb42d5214555c..6b6cf1fb59ca7 100644 --- a/tests/mcp/config.spec.ts +++ b/tests/mcp/config.spec.ts @@ -173,3 +173,54 @@ test('browser_get_config returns merged config from file, env and cli', async ({ // From CLI arg (--isolated). expect(config.browser.isolated).toBe(true); }); + +test('remoteEndpoint as ConnectOptions object', async ({ startClient, server, wsEndpoint }) => { + server.setContent('/', ` + Title + Hello, world! + `, 'text/html'); + + const { client } = await startClient({ + config: { + browser: { + remoteEndpoint: { + endpoint: wsEndpoint, + }, + isolated: true, + }, + }, + }); + + expect(await client.callTool({ + name: 'browser_navigate', + arguments: { url: server.PREFIX }, + })).toHaveResponse({ + snapshot: expect.stringContaining('Hello, world!'), + }); +}); + +test('remoteEndpoint as ConnectOptions object with exposeNetwork', async ({ startClient, server, wsEndpoint }) => { + server.setContent('/', ` + Title + exposed-network-content + `, 'text/html'); + + const { client } = await startClient({ + config: { + browser: { + remoteEndpoint: { + endpoint: wsEndpoint, + exposeNetwork: '*', + }, + isolated: true, + }, + }, + }); + + expect(await client.callTool({ + name: 'browser_navigate', + arguments: { url: server.PREFIX }, + })).toHaveResponse({ + snapshot: expect.stringContaining('exposed-network-content'), + }); +});