Skip to content

github-mcp-server: /mcp authenticate always fails on Copilot Enterprise — enterprise MCP host advertises a cross-origin resource identifier #4408

Description

@xjli1972

Describe the bug

On a Copilot Enterprise-routed account, selecting the built-in github-mcp-server in /mcp starts an OAuth flow that can never succeed:

Authenticating: github-mcp-server
Authentication failed: MCPOAuthError: Failed to discover authorization server metadata for https://api.enterprise.githubcopilot.com/mcp/readonly

Root cause — the built-in server URL is derived from the account's Copilot API base, so for enterprise-routed accounts it becomes https://api.enterprise.githubcopilot.com/mcp/readonly. But that host advertises a protected-resource identifier on a different origin:

$ curl -si -X POST https://api.enterprise.githubcopilot.com/mcp/readonly \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/json, text/event-stream' \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}'

HTTP/2 401
www-authenticate: Bearer error="invalid_request",
  error_description="No access token was provided in this request",
  resource_metadata="https://api.githubcopilot.com/.well-known/oauth-protected-resource/mcp/readonly"
                     ^^^^^^^^^^^^^^^^^^^^^^^^^ different origin than the resource server
$ curl -s https://api.enterprise.githubcopilot.com/.well-known/oauth-protected-resource/mcp/readonly
{
  "resource": "https://api.githubcopilot.com/mcp/readonly",
   ^^^^^^^^^^ declares the NON-enterprise origin
  "authorization_servers": ["https://github.com/login/oauth"],
  ...
}

The CLI enforces RFC 9728 same-origin on the resource identifier — runtime.node contains the guard string:

Protected resource metadata declares resource , which does not belong to

so discovery aborts before an authorization server is ever contacted. Both requests above are unauthenticated, so this reproduces for any enterprise-routed account regardless of local credentials.

Note the AS metadata itself is fine and reachable (https://github.com/.well-known/oauth-authorization-server/login/oauth → 200) — the flow never gets that far.

This looks like the built-in first-party instance of #3100: /mcp initiates OAuth discovery on selection even when the server already has a working Authorization: Bearer header. Here the server is healthy — its tools work normally in the same session — so the OAuth attempt is both unnecessary and unsatisfiable.

Affected version

1.0.79-9 (macOS 15 / darwin-arm64). Account is enterprise-routed, so authGetCopilotApiUrl resolves to https://api.enterprise.githubcopilot.com.

Steps to reproduce the behavior

  1. Sign in with an account whose Copilot is provided through a GitHub Enterprise (so the Copilot API base is api.enterprise.githubcopilot.com).
  2. Confirm the built-in server is healthy — e.g. invoke github-mcp-server/search_users. It succeeds.
  3. Run /mcp and select github-mcp-server from the numbered list (the only action offered is "authenticate").
  4. Observe Authentication failed: MCPOAuthError: Failed to discover authorization server metadata for https://api.enterprise.githubcopilot.com/mcp/readonly.

Expected behavior

Any of:

  1. Skip OAuth when a bearer is already attached. The built-in server is authenticated via an injected Authorization: Bearer header (Starting pending GitHub MCP server "github-mcp-server" after authentication), so it should report authenticated and not offer/enter an OAuth flow at all. (Same ask as HTTP MCP server with Bearer token fails OAuth discovery instead of falling back to headers auth #3100.)
  2. Honour the advertised resource identifier when the resource server explicitly points at a sibling Copilot origin, rather than rejecting it as cross-origin.
  3. Or fix the service side so api.enterprise.githubcopilot.com advertises its own origin in resource / resource_metadata.

Additional context

  • Discovery is rejected purely on the URL — independent of token, scopes, keychain, or local config. Verified unauthenticated via curl above.
  • GITHUB_MCP_URL_OVERRIDE appears not to be read from the process environment in 1.0.79-9: setting it to an unroutable URL (http://127.0.0.1:9/mcp/readonly) still produced a fully working github-mcp-server with no connection attempt to that address, so it can't be used as a workaround.
  • Overriding the built-in by declaring a user-level github-mcp-server in mcp-config.json pointed at https://api.githubcopilot.com/mcp/readonly does suppress the failure (log: User has explicitly configured github-mcp-server by name, skipping built-in setup), but it is not a viable workaround: the plain endpoint doesn't expose the Copilot-only tools, so web_search, get_copilot_space and list_copilot_spaces all disappear.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authenticationLogin, OAuth, device auth, token management, and keychain integrationarea:enterpriseGitHub Enterprise (GHE/GHES) support, org policies, and enterprise settingsarea: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