You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out of #4378, which carries two faults. The registry policy 401 in that issue has a cause and a workaround. This one does not, and it survives that workaround.
Summary
In a Copilot cloud agent session on a GHEC data residency tenant (<tenant>.ghe.com), every call to a playwright/* tool fails. The Playwright server is healthy for the whole session. The coordinator's MCP session to it is not. The second error message is wrong and sends a reader after a sign-in problem that does not exist.
The built-in Playwright MCP server is enabled by default and is documented as needing no setup. It is unusable here.
Reproduction
Any session in any repository on the tenant. Serve any page on localhost and call playwright/browser_navigate. It needs no repository-specific state.
First call:
MCP server 'playwright': Tool call failed: Error: MCP request failed: Transport closed
Recovery attempt:
MCP server 'playwright': Tool call failed after session recovery:
MCPOAuthBrowserRequiredError: Browser-based OAuth required for http://localhost:3100/mcp
The second message is misleading. The server is on localhost, it is unauthenticated, and it needs no sign-in of any kind.
The server is healthy throughout
It runs from /opt/copilot-runtime on the runner image's own Node 24.
It listens on port 3100 for the whole session.
A direct MCP initialize answers HTTP 200 and reports Playwright MCP 0.0.40.
The coordinator retrieves all 21 of its tools at session start, and they appear in the agent's tool list.
By the time the agent calls a tool, the coordinator's MCP session to that server is already closed. The recovery request gets HTTP 404, because the session no longer exists. The client then enters OAuth handling for an unauthenticated localhost server.
The coordinator does not talk to the Playwright server directly
The coordinator connects through a bridge process, not to port 3100:
The peer it initializes against names itself accordingly:
[INFO] Created session: <redacted>
[ERROR] Using deferred connection for default Playwright server
[INFO] [rust:rmcp::service] Service initialized as client
peer_info: Implementation { name: "mcp-proxy-bridge/playwright", version: "1.0.0" }
Three things follow.
Using deferred connection for default Playwright server is logged at ERROR level, 216 milliseconds after the session is created, before the bridge initializes. It is the only error in the runtime lifecycle log.
The transport that closes is the coordinator's connection through that bridge. It is not a connection to Playwright.
Session lifetime: the server is not the cause
I created an MCP session against port 3100 by hand and held it idle.
initialize HTTP/1.1 200 OK
serverInfo: {"name":"Playwright","version":"0.0.40"}
notifications/initialized HTTP/1.1 202 Accepted
tools/list immediately HTTP/1.1 200 OK (21 tools)
tools/list after 120 seconds HTTP/1.1 200 OK (21 tools)
tools/list after 420 seconds HTTP/1.1 200 OK (21 tools)
GET /mcp opened then killed (stream closed by the client)
tools/list after that close HTTP/1.1 200 OK (21 tools)
No 404 at any point. The Playwright server does not expire an idle session, and it does not drop a session when the client closes the SSE stream. Whatever closes the coordinator's transport is above the server.
It is not a timing problem either
I called playwright/browser_navigate with about:blank as the very first action of a session, before reading a file and before any shell command. It failed with the same two errors. So the transport is not closed by the agent's own work, and calling the browser early is not a workaround.
The Node version the repository installs.actions/setup-node puts Node 26 on GITHUB_PATH for the shell. The runtime starts its MCP servers on the image's own Node 24. The two never meet.
An environment variable holding a personal access token. The first failing session carried none, and the failure survived renaming the secret.
The application under test. The frontend served correctly on http://localhost:4200 in the same session.
An egress proxy with no localhost exclusion. The runtime process carries no HTTP_PROXY, HTTPS_PROXY, ALL_PROXY or NO_PROXY variable in any case.
The Playwright server expiring the session. See the lifetime table above.
The agent taking too long before the first call. See the first-action test above.
What I could not find reported anywhere
There is no report of MCP request failed: Transport closed against the built-in default Playwright server, and no report of Browser-based OAuth required for http://localhost:3100/mcp. Every public MCPOAuthBrowserRequiredError I found is a genuine remote OAuth server.
What I ask for
The cause of the transport closing. It is closed before the agent's first action, so it is not an idle timeout and not the agent's doing.
A correct error for a closed MCP session. The current message tells a customer to sign in to an unauthenticated localhost server, which is neither possible nor needed.
If the built-in Playwright server is not expected to work on a .ghe.com tenant, document it. The data residency feature overview lists no such limitation today.
Impact
The built-in browser is the intended route for a Copilot cloud agent to look at a page it changed. On this tenant it never works. Session ids and full runtime logs are available on request.
Describe the bug
Split out of #4378, which carries two faults. The registry policy 401 in that issue has a cause and a workaround. This one does not, and it survives that workaround.
Summary
In a Copilot cloud agent session on a GHEC data residency tenant (
<tenant>.ghe.com), every call to aplaywright/*tool fails. The Playwright server is healthy for the whole session. The coordinator's MCP session to it is not. The second error message is wrong and sends a reader after a sign-in problem that does not exist.The built-in Playwright MCP server is enabled by default and is documented as needing no setup. It is unusable here.
Reproduction
Any session in any repository on the tenant. Serve any page on
localhostand callplaywright/browser_navigate. It needs no repository-specific state.First call:
Recovery attempt:
The second message is misleading. The server is on
localhost, it is unauthenticated, and it needs no sign-in of any kind.The server is healthy throughout
/opt/copilot-runtimeon the runner image's own Node 24.initializeanswers HTTP 200 and reports Playwright MCP0.0.40.By the time the agent calls a tool, the coordinator's MCP session to that server is already closed. The recovery request gets HTTP 404, because the session no longer exists. The client then enters OAuth handling for an unauthenticated localhost server.
The coordinator does not talk to the Playwright server directly
The coordinator connects through a bridge process, not to port 3100:
The peer it initializes against names itself accordingly:
Three things follow.
Using deferred connection for default Playwright serveris logged at ERROR level, 216 milliseconds after the session is created, before the bridge initializes. It is the only error in the runtime lifecycle log.127.0.0.1:2301is the same internal MCP proxy named in Cloud agent: MCP registry policy fetch fails with 401/403 on GHEC data residency, silently blocking all user-configured MCP servers #4378.Session lifetime: the server is not the cause
I created an MCP session against port 3100 by hand and held it idle.
No 404 at any point. The Playwright server does not expire an idle session, and it does not drop a session when the client closes the SSE stream. Whatever closes the coordinator's transport is above the server.
It is not a timing problem either
I called
playwright/browser_navigatewithabout:blankas the very first action of a session, before reading a file and before any shell command. It failed with the same two errors. So the transport is not closed by the agent's own work, and calling the browser early is not a workaround.Ruled out, with evidence
GH_HOST=<tenant>.ghe.comset and no 401 anywhere in the runtime log.actions/setup-nodeputs Node 26 onGITHUB_PATHfor the shell. The runtime starts its MCP servers on the image's own Node 24. The two never meet.http://localhost:4200in the same session.HTTP_PROXY,HTTPS_PROXY,ALL_PROXYorNO_PROXYvariable in any case.What I could not find reported anywhere
There is no report of
MCP request failed: Transport closedagainst the built-in default Playwright server, and no report ofBrowser-based OAuth required for http://localhost:3100/mcp. Every publicMCPOAuthBrowserRequiredErrorI found is a genuine remote OAuth server.What I ask for
127.0.0.1:2301.GITHUB_COPILOT_3P_MCP_POLICY_ENABLEDistruein this session, and the only ERROR in the lifecycle log is the deferred connection line.Using deferred connection for default Playwright serveris expected. It is logged at ERROR level. [RFC] autoConnect: false — Deferred MCP Server Registration + On-Demand Lifecycle Init #1938 is an open request for deferred connection as a feature, which suggests it is not yet a settled behavior..ghe.comtenant, document it. The data residency feature overview lists no such limitation today.Impact
The built-in browser is the intended route for a Copilot cloud agent to look at a page it changed. On this tenant it never works. Session ids and full runtime logs are available on request.
Affected version
No response
Steps to reproduce the behavior
No response
Expected behavior
No response
Additional context
No response