Skip to content

fix(mcp): reconnect to the browser after disconnect#41966

Open
yury-s wants to merge 7 commits into
microsoft:mainfrom
yury-s:fix-41874
Open

fix(mcp): reconnect to the browser after disconnect#41966
yury-s wants to merge 7 commits into
microsoft:mainfrom
yury-s:fix-41874

Conversation

@yury-s

@yury-s yury-s commented Jul 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Recreate the MCP backend when its browser disconnected between tool calls, so the next call transparently reconnects: --extension reopens connect.html (silent with token bypass), cdp mode reconnects to the endpoint, persistent/isolated modes relaunch the browser.
  • Stop the single-shot extension relay and its http server once the browser connection drops.
  • Relaunch a crashed shared browser (--isolated/--shared-browser-context with multiple HTTP clients) instead of caching the dead one until all clients disconnect.

Fixes #41874

yury-s added 4 commits July 23, 2026 11:07
When the extension dropped the relay connection (MV3 service worker idle
timeout, browser restart, extension reload), the next tool call failed
against the dead browser. Recreate the backend when its browser has
disconnected, so the call transparently re-establishes the extension
connection instead. Also stop the single-shot relay servers once the
browser connection drops.

Fixes: microsoft#41874
The stale-backend recreation also covers a remote CDP browser that was
restarted and an isolated browser that died: the next tool call
reconnects or relaunches transparently. Log the observed disconnect
under pw:mcp:backend so tests can synchronize on it.
- CDPRelayServer.stop() now closes its http server, so callers do not
  need to pair the two calls.
- Share the dispose-and-reset logic between the stale and isClose paths
  in the tool call handler.
- Extract readExtensionToken test helper.
The factory cached the shared browser until every client disconnected,
so after a crash the stale backends were recreated against the dead
browser and tool calls kept failing for all clients. Drop the cached
browser when it is no longer connected, and balance the client count
when backend creation fails so the browser close bookkeeping stays
correct.
@yury-s
yury-s requested a review from pavelfeldman July 23, 2026 21:30
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread tests/mcp/cdp.spec.ts
});
});

test('transparently reconnects when the remote browser is restarted', async ({ cdpServer, startClient, server }) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a good thing? What if that's some completely unrelated browser? Do we have any evidence this is a useful scenario?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what has been asked for the extension. We discussed it offline ad decided to make it transpantly reconnect if the remote connection is lost for whatever reason. It especially makes sense when you connect from and mcp client over stdio which doesn't restart the server if it fails and would require manual intervention. When the server is reconnected the agent will see that the state has changed (due to a user action, crash, update or what not) and adapt.

Comment thread tests/mcp/http.spec.ts Outdated
});

test('http transport isolated closes the browser despite an earlier failed backend creation', async ({ serverEndpoint, server }, testInfo) => {
// A failed backend creation must not leak the client count, otherwise the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this comment mean?

@yury-s yury-s Jul 24, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a bug in program.ts, see new clientCount--; in the catch block. But I agree the comment does not make sense out of that context. Will remove.

Comment thread tests/mcp/http.spec.ts
});
});

test('http transport isolated multiclient relaunches a crashed shared browser', async ({ serverEndpoint, server }, testInfo) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a common scenario - with a crashed browser? I think this is more common when the user closes the browser window manually (for whatever reason) - do we want to relaunch it in this case?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I believe this makes sense as it is the mcp server that launched the browser. The same logic as above.

@yury-s
yury-s requested a review from dgozman July 24, 2026 17:11
@github-actions

Copy link
Copy Markdown
Contributor

Test results for "MCP"

1 failed
❌ [chrome] › mcp/annotate.spec.ts:57 › should capture multiple screenshots in one annotation @mcp-ubuntu-latest-chrome

7847 passed, 1278 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Hi, I'm the Playwright bot and I took a look at the CI failures on the latest run.

🟢 CI is clear — the one failure is a pre-existing flake

The only failure is mcp/annotate.spec.ts:57 › should capture multiple screenshots in one annotation on chrome, a file this PR doesn't touch. It's a known cross-PR flake, not a regression.

Details

Overall: no failure is attributable to this PR. The diff is confined to the MCP backend reconnect path (browserBackend.ts, cdpRelay.ts, extensionContextFactory.ts, program.ts, server.ts) plus the launch/cdp/http/extension tests. The screencast/annotate flow that failed isn't reached by that change.

Pre-existing flake / infra

Note: earlier reports on this PR flagged mcp/launch.spec.ts:164 failing on Firefox/WebKit (a real, PR-caused gap). That test passes in the latest run, so it looks already addressed.

Triaged by the Playwright bot - agent run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: --extension mode: relay does not reconnect to browser extension after disconnect

2 participants