Skip to content
Open
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
8 changes: 5 additions & 3 deletions packages/playwright-core/src/tools/mcp/browserFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ async function createCDPBrowser(config: FullConfig): Promise<playwrightTypes.Bro

async function createRemoteBrowser(config: FullConfig): Promise<BrowserWithInfo> {
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 {
Expand All @@ -135,10 +137,10 @@ async function createRemoteBrowser(config: FullConfig): Promise<BrowserWithInfo>
};
}

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' };
}
Expand Down
5 changes: 4 additions & 1 deletion packages/playwright-core/src/tools/mcp/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
51 changes: 51 additions & 0 deletions tests/mcp/config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>Title</title>
<body>Hello, world!</body>
`, '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>Title</title>
<body>exposed-network-content</body>
`, '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'),
});
});
Loading