github / github/copilot-cli

MCP OAuth re-auth repeatedly fails on Windows when the cached loopback redirect port is in an excluded TCP port range

未關閉
#3,973 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
area:authentication area:mcp area:platform-windows
主要語言
Shell
星號
11.2k
分支
1.9k
平均合併
14 小時 16 分鐘
30 天內合併 PR
6

描述

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:

```
Authenticating: foundry-mcp
Authentication failed: MCPOAuthError: listen EACCES: permission denied 127.0.0.1:60909
```

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:
- Cached registration `~/.copilot/mcp-oauth-config/.json` contained `"redirectUri": "http://127.0.0.1:60909/"` (dynamic registration, `isStatic:false`).
- `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](https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/error-10013-wsaeacces-is-returned), 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

1. Run on Windows where one or more excluded TCP port ranges exist. Confirm with: `netsh interface ipv4 show excludedportrange protocol=tcp`
2. Configure an HTTP MCP server that uses OAuth in `~/.copilot/mcp-config.json`.
3. Let the CLI perform dynamic client registration and cache a loopback redirect URI in `~/.copilot/mcp-oauth-config/.json`.
4. If the cached redirect URI's port is inside an excluded range, run `/mcp` and re-authenticate the server.
5. Observe repeated failure: `Authentication failed: MCPOAuthError: listen EACCES: permission denied 127.0.0.1:`

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:

1. **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](https://www.rfc-editor.org/rfc/rfc8252.html#section-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](https://www.rfc-editor.org/rfc/rfc7591.html)). Pinning a fixed loopback port is fragile on platforms where a given port may be OS-excluded.
2. **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 `.json` registration and `.tokens.json` from `~/.copilot/mcp-oauth-config/`, then re-auth — the CLI re-registers on a new (bindable) port and authentication succeeds.
- I found related but apparently distinct OAuth issues (#3393, #3039 headless/SSH browser; #3838 reauth not attached). I did not find one covering a Windows excluded-port listener bind failure.

貢獻指南

開啟貢獻指南

研究方向

從 `/mcp` 重新驗證流程和 `~/.copilot/mcp-oauth-config/` 下的快取檔案開始,然後使用 `netsh interface ipv4 show excludedportrange protocol=tcp` 在 Windows 上重現。追蹤動態註冊和迴路返送監聽器繫結,包括診斷記錄。完成標準是:重新驗證能夠從被排除或已被佔用的快取連接埠中復原,且繫結失敗會持久化記錄其伺服器、位址、連接埠和錯誤碼。

由索引模型根據 Issue 內容生成。

評估

領域
authentication, cli, networking, operating-systems
Issue 類型
缺陷
難度
4/5
預估耗時
3-5 天
活躍度
冷清
描述清晰度
基本清楚
新手友好度
52/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。