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
On Windows, an HTTP MCP server using OAuth can get into a sticky re-auth failure state: repeated /mcp re-auth attempts fail with the same local listener bind error until the cached OAuth registration is manually removed. The observed failure mode is that the CLI reuses a cached, dynamically registered client whose loopback redirect URI contains a fixed port (e.g. http://127.0.0.1:60909/). On my machine that port was inside a Windows excluded TCP port range, so the local loopback listener could not bind and failed with EACCES. Because the same cached redirect URI is reused on each retry, every re-auth attempt hits the same unbindable port, with no self-healing path.
Transient error shown in the TUI during /mcp re-auth:
I could not find this bind error persisted in the CLI log/cache locations I checked; I only observed it transiently in the TUI, which made it difficult to diagnose after the fact.
Evidence that the failure is the local listener bind, not the server/token/config:
netsh interface ipv4 show excludedportrange protocol=tcp showed an excluded range 60868-60967; 60909 is inside it.
Get-NetTCPConnection -LocalPort 60909 -State Listen returned nothing — the port is reserved by the OS, not occupied by a listener (consistent with EACCES rather than EADDRINUSE; see KB 3039044, where tcpip.sys marks excluded-range ports RESERVED and bind() returns WSAEACCES/10013).
Using the still-valid cached access token, a manual POST of an MCP initialize request returned HTTP 200 with a valid response. That indicates the server endpoint, network path, cached token, and MCP config were not the cause.
Affected version
GitHub Copilot CLI 1.0.66-2
Steps to reproduce the behavior
Run on Windows where one or more excluded TCP port ranges exist. Confirm with: netsh interface ipv4 show excludedportrange protocol=tcp
Configure an HTTP MCP server that uses OAuth in ~/.copilot/mcp-config.json.
Let the CLI perform dynamic client registration and cache a loopback redirect URI in ~/.copilot/mcp-oauth-config/<hash>.json.
If the cached redirect URI's port is inside an excluded range, run /mcp and re-authenticate the server.
In my repro the cached redirect URI used port 60909, and Windows reported an excluded range of 60868-60967.
Expected behavior
The CLI should recover automatically instead of looping on an unbindable pinned port:
Validate/recover the loopback port for dynamically registered clients. Before reusing a cached loopback redirect port, attempt to bind it; on EACCES/EADDRINUSE, discard or refresh that cached registration and register a new redirect URI on a bindable port. A robust approach is to bind an OS-selected loopback port first (bind to port 0), read back the assigned port, then use it when constructing the authorization request / dynamic registration. This matches RFC 8252 §7.3, whose expected pattern is for native-app clients to obtain an ephemeral loopback port from the OS at request time — the spec's normative "MUST allow any port" is placed on the authorization server specifically to enable this. §8.4 further notes loopback redirects match on everything except the port. Re-registering with a different loopback port is permitted by Dynamic Client Registration (RFC 7591). Pinning a fixed loopback port is fragile on platforms where a given port may be OS-excluded.
Persist the bind failure (MCP server name, address, port, and errno/code) to the diagnostic log, so a local listener-bind failure can be distinguished from an actual auth-provider failure.
Additional context
OS / environment: Windows (win32-x64). Reproduced on a Microsoft Dev Box / Windows 365 Cloud PC (Manufacturer: Microsoft Corporation, Model: Virtual Machine) with hns, vmcompute, winnat, and WslService running and three excluded TCP ranges present (49723-49822, 50000-50059, 60868-60967). I did not independently determine which component created the range containing 60909.
Trigger scope: Excluded port ranges are common on Windows developer environments that use virtualization/container networking (Hyper-V, WSL2, Docker, HNS, WinNAT). They appear to be common on Microsoft Dev Box / Windows 365 Cloud PC images where these features are enabled by default. When the condition is hit, the failure is sticky and non-obvious: the server stays failed and re-auth loops until the hidden cached registration files are removed.
Manual workaround that fixed it: delete the server's <hash>.json registration and <hash>.tokens.json from ~/.copilot/mcp-oauth-config/, then re-auth — the CLI re-registers on a new (bindable) port and authentication succeeds.
On Windows, an HTTP MCP server using OAuth can get into a sticky re-auth failure state: repeated
/mcpre-auth attempts fail with the same local listener bind error until the cached OAuth registration is manually removed. The observed failure mode is that the CLI reuses a cached, dynamically registered client whose loopback redirect URI contains a fixed port (e.g.http://127.0.0.1:60909/). On my machine that port was inside a Windows excluded TCP port range, so the local loopback listener could not bind and failed withEACCES. Because the same cached redirect URI is reused on each retry, every re-auth attempt hits the same unbindable port, with no self-healing path.Transient error shown in the TUI during
/mcpre-auth:I could not find this bind error persisted in the CLI log/cache locations I checked; I only observed it transiently in the TUI, which made it difficult to diagnose after the fact.
Evidence that the failure is the local listener bind, not the server/token/config:
~/.copilot/mcp-oauth-config/<hash>.jsoncontained"redirectUri": "http://127.0.0.1:60909/"(dynamic registration,isStatic:false).netsh interface ipv4 show excludedportrange protocol=tcpshowed an excluded range60868-60967;60909is inside it.Get-NetTCPConnection -LocalPort 60909 -State Listenreturned nothing — the port is reserved by the OS, not occupied by a listener (consistent withEACCESrather thanEADDRINUSE; see KB 3039044, wheretcpip.sysmarks excluded-range ports RESERVED andbind()returns WSAEACCES/10013).POSTof an MCPinitializerequest returned HTTP 200 with a valid response. That indicates the server endpoint, network path, cached token, and MCP config were not the cause.Affected version
GitHub Copilot CLI 1.0.66-2Steps to reproduce the behavior
netsh interface ipv4 show excludedportrange protocol=tcp~/.copilot/mcp-config.json.~/.copilot/mcp-oauth-config/<hash>.json./mcpand re-authenticate the server.Authentication failed: MCPOAuthError: listen EACCES: permission denied 127.0.0.1:<port>In my repro the cached redirect URI used port
60909, and Windows reported an excluded range of60868-60967.Expected behavior
The CLI should recover automatically instead of looping on an unbindable pinned port:
EACCES/EADDRINUSE, discard or refresh that cached registration and register a new redirect URI on a bindable port. A robust approach is to bind an OS-selected loopback port first (bind to port0), read back the assigned port, then use it when constructing the authorization request / dynamic registration. This matches RFC 8252 §7.3, whose expected pattern is for native-app clients to obtain an ephemeral loopback port from the OS at request time — the spec's normative "MUST allow any port" is placed on the authorization server specifically to enable this. §8.4 further notes loopback redirects match on everything except the port. Re-registering with a different loopback port is permitted by Dynamic Client Registration (RFC 7591). Pinning a fixed loopback port is fragile on platforms where a given port may be OS-excluded.Additional context
win32-x64). Reproduced on a Microsoft Dev Box / Windows 365 Cloud PC (Manufacturer: Microsoft Corporation, Model: Virtual Machine) withhns,vmcompute,winnat, andWslServicerunning and three excluded TCP ranges present (49723-49822,50000-50059,60868-60967). I did not independently determine which component created the range containing60909.<hash>.jsonregistration and<hash>.tokens.jsonfrom~/.copilot/mcp-oauth-config/, then re-auth — the CLI re-registers on a new (bindable) port and authentication succeeds.