fix(mcp): create a browser context when connecting to a remote browser with no contexts - #41354
Conversation
Connecting to a remote browser via --endpoint forces isolated=false, so the server takes the browser.contexts()[0] branch. A browserType.connect()-ed browser has no contexts, so contexts()[0] is undefined and BrowserBackend crashes on the first tool call with "Cannot read properties of undefined (reading 'once')". Create a context when none exists.
|
Dmitry Gozman (@dgozman) please review this PR |
|
Yury Semikhatsky (@yury-s) Devin Rousso (@dcrousso) please review as well |
| await browser.bind(sessionName, { workspaceDir: clientInfo.cwd }); | ||
| } | ||
| const browserContext = config.browser.isolated ? await browser.newContext(config.browser.contextOptions) : browser.contexts()[0]; | ||
| const browserContext = config.browser.isolated || !browser.contexts().length ? await browser.newContext(config.browser.contextOptions) : browser.contexts()[0]; |
There was a problem hiding this comment.
NIT: browser.contexts() is potentially not a cheap operation, so can we reorganize this a little?
let browserContext = browser.contexts()[0];
if (!browserContext || config.browser.isolated)
browserContext = await browser.newContext(config.browser.contextOptions);There was a problem hiding this comment.
browser.contexts() is free.
Test results for "MCP"7354 passed, 1122 skipped Merge workflow run. |
|
Abhishek Gadekar (@abhishek-lambda) We require an issue for every non-trivial contribution, see this guide. |
Yes, please start with that. Which version of mcp are you using? I believe this was fixed in #41203 |
|
I don't think we want to create a context in a non-isolated mode. What is your exact use case? |
Problem
Driving the Playwright MCP server against a remote browser via
--endpointconnects successfully, but the first tool call (e.g.browser_navigate) throws:Root cause
In
packages/playwright-core/src/tools/mcp/program.ts, the backend resolves the context like this:For the
--endpoint(remote) transport, config resolution forcesisolated = false, so thebrowser.contexts()[0]branch is taken. A browser obtained viabrowserType.connect()has zero contexts (the caller is expected to create one), socontexts()[0]isundefined.BrowserBackendthen dereferences it (browserContext.once('close', …)), crashing on the first tool call.The sibling
cli-daemon/program.tsalready anticipates the empty-contexts case (it throws an explicit error there), but the MCP server path neither guards nor handles it.Fix
Create a context when the connected browser has none — a one-condition change, no duplicated
newContextcall:Behavior is unchanged for the local/persistent and isolated paths (which already have a context or explicitly create one); it only adds a context for remote-connected browsers that start with none.
Verification
Reproduced against a remote Playwright endpoint (LambdaTest grid,
wss://cdp.lambdatest.com/playwright) on@playwright/mcpv0.0.76:browser_navigatethrowsCannot read properties of undefined (reading 'once').navigate → type → wait → snapshotruns end-to-end with no errors.The same root cause is currently worked around externally by supplying a
contextGetterto the programmaticcreateConnection(config, contextGetter)API; this change makes the stock--endpointflag work without that workaround.