Skip to content

MCP: user-configured api.githubcopilot.com/mcp/ server loses the injected Copilot token on 1.0.81-10, and /mcp auth cannot rescue it (github.com advertises no dynamic client registration) #4604

Description

@examon

Resolution

Addressed by github/copilot-agent-runtime#18279.

The fix moves CLI-managed GitHub/Copilot bearer injection to the shared MCP session boundary, so trusted user-configured GitHub MCP endpoints receive the current Copilot credential in root sessions and custom-agent/subagent sessions. Explicit user-supplied Authorization headers continue to take precedence, and CLI-managed credentials remain ephemeral rather than being serialized into MCP configuration.

It also keeps credential rotation, logout, reconnect, and server removal synchronized; prevents a rejected CLI-managed bearer from falling through to GitHub OAuth dynamic registration; and preserves legitimate OAuth scope-upgrade handling for 403 insufficient_scope responses.

Describe the bug On 1.0.81-10 a user-configured https://api.githubcopilot.com/mcp/ server no longer receives the injected Copilot token. It starts with no Authorization header, takes a 401, and is reported as needing auth. The only remedy the CLI then offers — OAuth — is impossible, because github.com's authorization server does not advertise dynamic client registration: Authenticating: github Authentication failed: MCPOAuthError: Client registration failed: Authorization server does not support dynamic client registration On 1.0.80 the same config works and that OAuth prompt is merely spurious. So 1.0.801.0.81-10 turns a cosmetic false prompt into a hard block for this configuration. Workarounds exist (a PAT header, a static oauthClientId, or switching to the built-in github-mcp-server), but none is discoverable from the error, which points at an /mcp auth that cannot succeed. ### Affected version 1.0.81-10 (npm dist-tag prerelease). Not present on 1.0.80 (dist-tag latest). Linux x64, enterprise-routed account. ### Steps to reproduce the behavior Add the server exactly as a user would: console $ copilot mcp add --transport http github https://api.githubcopilot.com/mcp/ Then ask for a tool from it, denying shell so the model cannot silently answer with curl: console $ copilot -p "Call get_me from the MCP server named github and print only the login. \ Do not use shell/curl/bash; if the MCP tool is unavailable say exactly UNAVAILABLE." \ --allow-all-tools --deny-tool shell | version | result | /mcp shows | | --- | --- | --- | | 1.0.80 | Get my user profile (MCP: github) → real login | ✓ Connected, Tools (48/48 enabled) | | 1.0.81-10 | UNAVAILABLE | !, and Details: Tools unavailable: Error: MCP server "github" is not connected | Reproduced on 1.0.81-10 from a clean profile that never attempted auth, so this is not poisoned state from the failed OAuth attempt. ### Debug log — the credential-injection path simply does not run Same prompt, both versions pinned, each with its own HOME and COPILOT_HOME, both launched with --no-auto-update, counted with --log-level debug: | log line | 1.0.80 | 1.0.81-10 | | --- | --- | --- | | Starting pending GitHub MCP server "github" after authentication | 1 | 0 | | No access token was provided in this request | 0 | 6 | | Browser-based OAuth required | 0 | 2 | 1.0.80: [DEBUG] Starting pending GitHub MCP server "github" after authentication 1.0.81-10: [ERROR] worker quit with fatal: Transport channel closed, when Client(OAuthChallenge { ... "No access token was provided in this request" ... status_code: 401 }) 1.0.81-10: [WARNING] MCP OAuth authorization failed; reporting the server as needing auth {"server":"github","error":"Browser-based OAuth required for https://api.githubcopilot.com/mcp/"} The built-in github-mcp-server connects fine in the same 1.0.81-10 run, so credentials and payload are healthy — it is specifically the injection into the user-configured server that stops happening. > Careful when reproducing: the launcher auto-updates, and the payload is resolved and cached per-HOME, so a throwaway HOME pulls whatever latest is rather than the version you think you pinned. Pin the payload per version, pass --no-auto-update, and re-print copilot --version from inside the same HOME/COPILOT_HOME as the failing run — nothing else establishes which build produced a result. ### The second half: OAuth cannot rescue it Verified unauthenticated, so this is independent of any local credential: console $ curl -s https://github.com/.well-known/oauth-authorization-server/login/oauth {"issuer":"https://github.com/login/oauth", ... } # no registration_endpoint https://api.githubcopilot.com/.well-known/oauth-protected-resource/mcp/ advertises authorization_servers: ["https://github.com/login/oauth"], and that authorization server publishes no registration_endpoint. The runtime bypasses absent dynamic client registration only when the authorization server is Microsoft/Entra, so GitHub's own authorization server falls straight into registration and fails immediately. Setting oauthClientId on the server does skip registration (a self-registered OAuth App), so this is not literally unrecoverable — but nothing in the failure points there. Note the current docs steer people to the built-in server, and the custom-remote example uses a PAT, so I can't claim the URL-only form is itself the documented path — only that it is the natural one to try, and that it used to work on 1.0.80. ### Expected behavior 1. Restore the token injection for a user-configured server on a recognized Copilot MCP host, so 1.0.81 behaves as 1.0.80 did; and 2. Give GitHub's authorization server the same no-registration fallback that Microsoft/Entra already gets, so the offered remedy is not one that cannot succeed; and 3. Don't offer authenticate on a server that is already carrying a bearer. ### Additional context - Related but distinct: #4408 is the built-in server on Copilot Enterprise dying at metadata discovery (cross-origin resource identifier); #3100 asks for fallback to a user-supplied header. Here the CLI's own injected token stopped being applied, and the failure is at registration. - Worth noting for #4408: the enterprise protected-resource document already advertises authorization_servers: ["https://github.com/login/oauth"]. So once github/github-mcp-server-remote#957 fixes the advertised origin, discovery will succeed and the flow will land on this same missing-registration wall. 957 looks necessary but not sufficient for #4408. - One thing I could not rule out: the injection path may be gated by a server-side experiment rather than purely by version, in which case the split may not be strictly 1.0.80 vs 1.0.81-10 for every account.

Generated by Copilot

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authenticationLogin, OAuth, device auth, token management, and keychain integrationarea:mcpMCP server configuration, discovery, connectivity, OAuth, policy, and registry

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions