-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Prerelease CLI builds can block non-default MCP servers after registry policy fetch fails #2552
Description
Bug Report: Prerelease CLI builds can block non-default MCP servers after registry policy fetch fails
Related Issues
- All MCP servers blocked by policy when GHE returns 404 on /copilot/mcp_registry #2498 — "All MCP servers blocked by policy when GHE returns 404 on /copilot/mcp_registry" — Same GHES 404 symptom on stable v1.0.17. Our report adds the prerelease-specific trigger mechanism, root cause analysis of the update channel logic, and a complete workaround including pkg cache cleanup.
- Failed to fetch MCP registry policy for individual user (404) #2479 — "Failed to fetch MCP registry policy for individual user (404)" — Original report for individual/Pro users on stable 1.0.14–1.0.15, marked fixed in 1.0.16/1.0.19.
- ! 1 MCP server was blocked by policy: #2486 — "1 MCP server was blocked by policy" — Personal Pro+ user, same registry 404, documents the auto-update pkg cache override behavior independently.
This report documents the same 404 failure pattern re-emerging specifically in prerelease builds (1.0.20-x) within a GHES enterprise environment, via a distinct trigger: certain config states cause the CLI to default to the prerelease update channel, which installs builds with a different client audience parameter that the registry does not recognize.
Summary
Copilot CLI prerelease builds (tested: 1.0.20-0, 1.0.20-1) receive HTTP 404 when fetching MCP policy from the enterprise registry during startup. The CLI then blocks all non-default MCP servers. The tested stable build (1.0.19) did not block non-default servers.
Environment
- OS: Windows 11 (x64)
- Node: v22.16.0
- CLI broken versions:
@github/copilot1.0.20-0 and 1.0.20-1 (prerelease channel) - CLI working version:
@github/copilot1.0.19 (stable/latest channel) - Deployment: GitHub Enterprise Server (GHES) environment
Reproduction Steps
- Configure
~/.copilot/config.jsonwith a config state that selects the prerelease update channel by default (e.g., no explicit"update_channel"set, with internal flags that default to prerelease) - Allow auto-update to run (or run
copilot update) - The CLI selects the prerelease update channel and installs a prerelease build (e.g., 1.0.20-0)
- On next startup, the MCP registry policy fetch returns HTTP 404
- Debug logs show:
"Non-default MCP servers will be blocked until the policy can be fetched" - All non-default/plugin-contributed MCP servers are blocked
- Only the built-in default
github-mcp-serverloads
Alternative repro: Directly install a prerelease build via npm install -g @github/copilot@prerelease and start the CLI in a GHES environment.
To observe: Enable debug logging via "logLevel": "all" in ~/.copilot/config.json and check logs in ~/.copilot/logs/.
Observed Root Cause
Update channel logic (from published npm package sdk/index.js):
The update channel selection logic can default to "prerelease" based on certain config states. The prerelease channel fetches all GitHub releases (including prereleases), while the stable channel fetches only /releases/latest.
Observed correlation
The tested prerelease binaries (1.0.20-0, 1.0.20-1) contain a different client-side audience parameter value than the tested stable binary (1.0.19). The registry policy fetch fails (404) with the prerelease audience value and succeeds or is skipped with the stable audience value. Server-side gating logic was not directly verified — this is an observed correlation between the client audience value and the registry response.
npm dist-tags (as of 2026-04-07):
latest: 1.0.19 — non-default MCP servers load ✅prerelease: 1.0.20-1 — registry fetch returns 404, servers blocked ❌
Impact
- All observed non-default/plugin-contributed MCP servers in the GHES environment were blocked
- Skills depending on plugin MCP servers become non-functional
- In our testing, the failure was only evident in debug logs; we did not observe a clear user-facing remediation message
- Users whose config defaults to the prerelease update channel are disproportionately affected
Workaround
- Fully exit the CLI (stop any running Copilot session)
- Add
"update_channel": "stable"to~/.copilot/config.json - Run
npm install -g @github/copilot@latestto reinstall the stable version - Delete any prerelease entries from the auto-update cache at
~/.copilot/pkg/universal/(e.g., directories named1.0.20-0,1.0.20-1). In our testing, a cached prerelease binary took precedence over the npm-installed version at startup. - Restart the CLI
- Verify: Confirm the running version is stable (check
/version) and that non-default MCP servers load (check debug logs forservers_blocked_count=0)
Expected Behavior
- Prerelease builds should not break MCP server loading for GHES users
- The registry should handle the client values emitted by supported CLI builds gracefully (not return 404)
- OR: The CLI should not fail closed on registry 404 — it should fall back to a permissive default or allow previously-loaded servers
- Users should receive a visible warning when auto-updating to a prerelease that may change client behavior
Verified Evidence
| Observation | Status | Method |
|---|---|---|
| Prerelease binaries contain different audience value than stable | ✅ Verified | Binary string extraction |
| Registry returns 404 with prerelease binary | ✅ Verified | Debug log analysis |
| Stable binary did not block non-default MCP servers | ✅ Verified | Debug log analysis |
| Config state causes prerelease channel default | ✅ Verified | SDK source code inspection |
update_channel: "stable" overrides the default |
✅ Verified | Config change + restart |
| Auto-update pkg cache can override npm-installed version | ✅ Verified | Observed after npm reinstall |
| ALL prerelease builds have the different audience value | ❓ Unverified | Only tested 1.0.20-0 and 1.0.20-1 |
| Registry is explicitly audience-gated server-side | ❓ Inferred | Correlation between client value and response |
Log Evidence
Stable (1.0.19) — non-default servers allowed:
mcp_allowlist_policy_check: outcome="no_registries", registry_count=0
custom_mcp_allowed=true, servers_blocked_count=0
Note: The stable build's log shows outcome="no_registries" — this may indicate the registry was not queried rather than a successful fetch. Either way, non-default servers were not blocked.
Prerelease (1.0.20-0) — non-default servers blocked:
mcp_policy_check: registry fetch 404
"Non-default MCP servers will be blocked until the policy can be fetched"
custom_mcp_allowed=false, servers_blocked_count=4
Caveat
This bug report has been reviewed and sanitized to remove any personally identifiable information, proprietary details, and organization-specific data. As a result, certain environment details, configuration values, and reproduction specifics have been generalized or omitted. Some gaps in this report may be a consequence of that redaction rather than a lack of investigation. The original findings were more detailed but could not be disclosed publicly for privacy and security reasons. The CLI team may request additional context privately if needed to fully reproduce or diagnose the issue.