Summary
In enterprise mode, Copilot CLI's built-in github-mcp-server fails to start with:
Failed to connect to MCP server github-mcp-server
The first fix attempt — intercepting Copilot's remote MCP host api.githubcopilot.com and stamping a GitHub Bearer token (commit c80aa7c, REQ-GITHUB-003 AC1/AC2) — is deployed and live but does not resolve the failure.
Environment
What was tried (and is confirmed insufficient)
c80aa7c added api.githubcopilot.com to interceptedGithubHosts and added a Bearer-injection branch in the GitHubInterceptor:
src/github-interceptor.ts:51-58 — gitCopilotMcpHost + interceptedGithubHosts now include api.githubcopilot.com (env-overridable via GITHUB_COPILOT_MCP_HOST).
src/github-interceptor.ts:162-166 — on api.githubcopilot.com it strips the container placeholder and sets Authorization: Bearer <user GitHub token> (no X-GitHub-Api-Version).
- Wired at container start in
src/container/index.ts (wireGithubInterception) — confirmed it loops all three GitHub hosts.
Unit tests pass (the interceptor does stamp Bearer on that host), but the real-world outcome the AC claims — "the remote github-mcp-server connects authenticated" — is false in production. So either the request isn't actually reaching/leaving the interceptor as expected, or a static GitHub Bearer token is not what that endpoint's handshake requires.
Candidate root causes (to be confirmed with logs, ranked by likelihood)
- The remote GitHub MCP server uses an OAuth 2.0 handshake, not a static Bearer token. MCP Streamable-HTTP servers commonly answer the initial request with
401 + WWW-Authenticate pointing at an authorization server, then the client runs an OAuth/discovery dance (potentially across other hosts, e.g. github.com/login/oauth/* or a .well-known endpoint). Injecting a static Bearer <github-oauth-token> would not satisfy that flow, and the multi-step connect would fail → generic "Failed to connect". This is the leading hypothesis.
- Wrong credential kind.
api.githubcopilot.com/mcp may require a Copilot-scoped token, not the user's GitHub OAuth token from the codeflare deploy-keys connect flow. (Would more likely surface as a 401, but could also break the handshake.)
- Request isn't actually being intercepted. Possible if: the MCP transport opens a connection the L7
interceptOutboundHttps layer doesn't cover; the container doesn't trust the interception CA for this host; or (under strict egress) host precedence routes it to the EgressController catch-all / env.EGRESS instead of the GitHubInterceptor. Note the cf1:network EGRESS binding is committed commented-out, so if strict egress were ON the path would fail-closed 503 — but git over the same GitHubInterceptor works, suggesting strict egress is OFF here and this is less likely.
- HTTP/transport handling in the interceptor breaks MCP.
redirect:'manual' surfaces a 3xx (e.g. /mcp → /mcp/) to the client instead of following it; or a stripped/altered header (Mcp-Session-Id, Accept: text/event-stream, content negotiation) breaks the Streamable-HTTP handshake.
- Wrong/incomplete host or path. Copilot may dial an additional endpoint (token/discovery) beyond
api.githubcopilot.com/mcp that is not intercepted.
Diagnostic plan (do this before any further code change)
wrangler tail the enterprise-integration worker while reproducing in a fresh session. Confirm whether GitHubInterceptor: injected credential ... api.githubcopilot.com/mcp fires at all:
- Not hit → interception/precedence/CA/host problem (causes 3/5).
- Hit, upstream non-2xx (esp. 401 +
WWW-Authenticate) → OAuth-handshake / wrong-credential problem (causes 1/2).
- Hit, upstream 3xx → redirect/transport problem (cause 4).
- Capture the exact host(s) + path(s) + status codes Copilot's
github-mcp-server requests during connect (it may be more than one host).
- Identify what credential the endpoint actually expects (GitHub PAT vs OAuth-app token vs Copilot token) and whether an OAuth discovery/authorization step is involved.
Follow-ups
- Spec truth: REQ-GITHUB-003 AC2 currently asserts Copilot's MCP "connects authenticated". Until root cause is fixed, that claim is not satisfied in production — the AC / Status should be revisited (the interceptor test verifies header-stamping, not end-to-end connection).
- Once the real mechanism is known, decide whether interception+Bearer can ever work, or whether Copilot's remote MCP requires a fundamentally different approach in the zero-secret enterprise container.
References
Summary
In enterprise mode, Copilot CLI's built-in
github-mcp-serverfails to start with:The first fix attempt — intercepting Copilot's remote MCP host
api.githubcopilot.comand stamping a GitHubBearertoken (commitc80aa7c, REQ-GITHUB-003 AC1/AC2) — is deployed and live but does not resolve the failure.Environment
enterprise-integration(worker headc782c74, branchmesh_sync, now also ondevelopvia PR feat: enterprise egress & governance stack (strict Gateway egress, Governed Mode, zero-secret container, view-only storage, faster startup sync) + reliability fixes #593).api.githubcopilot.com— this is not a stale-session artifact).Failed to connect to MCP server github-mcp-server(not a 401/403 auth-rejection).What was tried (and is confirmed insufficient)
c80aa7caddedapi.githubcopilot.comtointerceptedGithubHostsand added a Bearer-injection branch in theGitHubInterceptor:src/github-interceptor.ts:51-58—gitCopilotMcpHost+interceptedGithubHostsnow includeapi.githubcopilot.com(env-overridable viaGITHUB_COPILOT_MCP_HOST).src/github-interceptor.ts:162-166— onapi.githubcopilot.comit strips the container placeholder and setsAuthorization: Bearer <user GitHub token>(noX-GitHub-Api-Version).src/container/index.ts(wireGithubInterception) — confirmed it loops all three GitHub hosts.Unit tests pass (the interceptor does stamp Bearer on that host), but the real-world outcome the AC claims — "the remote
github-mcp-serverconnects authenticated" — is false in production. So either the request isn't actually reaching/leaving the interceptor as expected, or a static GitHubBearertoken is not what that endpoint's handshake requires.Candidate root causes (to be confirmed with logs, ranked by likelihood)
401 + WWW-Authenticatepointing at an authorization server, then the client runs an OAuth/discovery dance (potentially across other hosts, e.g.github.com/login/oauth/*or a.well-knownendpoint). Injecting a staticBearer <github-oauth-token>would not satisfy that flow, and the multi-step connect would fail → generic "Failed to connect". This is the leading hypothesis.api.githubcopilot.com/mcpmay require a Copilot-scoped token, not the user's GitHub OAuth token from the codeflare deploy-keys connect flow. (Would more likely surface as a 401, but could also break the handshake.)interceptOutboundHttpslayer doesn't cover; the container doesn't trust the interception CA for this host; or (under strict egress) host precedence routes it to theEgressControllercatch-all /env.EGRESSinstead of theGitHubInterceptor. Note thecf1:networkEGRESS binding is committed commented-out, so if strict egress were ON the path would fail-closed503— but git over the sameGitHubInterceptorworks, suggesting strict egress is OFF here and this is less likely.redirect:'manual'surfaces a 3xx (e.g./mcp→/mcp/) to the client instead of following it; or a stripped/altered header (Mcp-Session-Id,Accept: text/event-stream, content negotiation) breaks the Streamable-HTTP handshake.api.githubcopilot.com/mcpthat is not intercepted.Diagnostic plan (do this before any further code change)
wrangler tailthe enterprise-integration worker while reproducing in a fresh session. Confirm whetherGitHubInterceptor: injected credential ... api.githubcopilot.com/mcpfires at all:WWW-Authenticate) → OAuth-handshake / wrong-credential problem (causes 1/2).github-mcp-serverrequests during connect (it may be more than one host).Follow-ups
References
c80aa7c(REQ-GITHUB-003), deployed inc782c74.src/github-interceptor.ts,src/container/index.ts(wireGithubInterception).