MCP OAuth: initialize request after successful OAuth login omits User-Agent header, ignoring configured custom headers
Personne n'a encore pris cette issue.
- Langage dominant
- Shell
- Étoiles
- 11.2k
- Forks
- 1.9k
- Merge moyen
- 14 h 16 min
- PR mergées (30 j)
- 6
Description
Summary
When connecting to a remote MCP server (HTTP/Streamable-HTTP transport) that requires OAuth authentication, the underlying rmcp/reqwest-based HTTP client used by Copilot CLI/App does not send a User-Agent header on the initialize request that follows a successful OAuth token exchange. Custom headers configured for the MCP server in mcp-config.json (via copilot mcp add --header "...") are also not applied to this specific request.
This causes initialize requests to fail against any MCP server that is fronted by infrastructure which rejects requests without a User-Agent header (e.g. AWS WAF's managed rule AWSManagedRulesCommonRuleSet / NoUserAgent_HEADER, or similar reverse-proxy/WAF configurations), even though the OAuth handshake itself (authorize/token exchange) completes successfully.
Steps to Reproduce
- Configure a remote HTTP MCP server that requires OAuth, optionally with a custom header:
copilot mcp add --transport http my-server https://example.com/mcp --header "User-Agent: MyCustomAgent/1.0" - Trigger authentication (e.g. via
Authenticatein the Copilot App, or by using the tool in Copilot CLI). - Complete the browser-based OAuth login/consent flow successfully.
- Observe that the subsequent
initializerequest fails if the target server (or infrastructure in front of it) rejects requests lacking aUser-Agentheader — even though the configured customUser-Agentheader was set on the server config.
Expected Behavior
- The MCP client should always send a non-empty
User-Agentheader (e.g. an SDK/product default such asGitHubCopilotCLI/<version>) on all requests, including the post-OAuthinitializerequest. - Any custom headers configured for the MCP server (via
--header, or theheadersfield inmcp-config.json) should be honored consistently across all requests sent to that server, including the OAuth-authenticatedinitializerequest — not only a subset of requests.
Actual Behavior
- The
initializerequest sent after a successful OAuth token exchange appears to omit theUser-Agentheader entirely (confirmed via server-side testing: a request without anyUser-Agentheader reproduces the exact same generic, non-JSON403 Forbiddenresponse observed by the client). - Configuring a custom
User-Agentheader viacopilot mcp add --header "User-Agent: ..."does not change this behavior — the header is stored inmcp-config.jsonbut is not applied to theinitializerequest. - The resulting error surfaces as:
RPC error -32603: Request session.mcp.oauth.login failed with message: failed to initialize MCP client: Send message error Transport [rmcp::transport::worker::WorkerTransport<rmcp::transport::streamable_http_client::StreamableHttpClientWorker<mcp::client::RawCapturingReqwestClient>>] error: unexpected server response: HTTP 403 Forbidden: <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> </body> </html> , when send initialize request - The prior OAuth challenge/token exchange step succeeds (HTTP 401 with a proper
WWW-Authenticate/OAuth challenge, then successful browser login/consent) — the failure occurs specifically on the follow-upinitializecall.
Environment
- GitHub Copilot CLI/App version: 1.0.82 (latest at time of testing)
- OS: macOS (Darwin)
- MCP server transport:
http(Streamable HTTP), OAuth-protected (dynamic client registration / RFC 9728 protected resource metadata) - Same MCP server + OAuth flow works correctly in VS Code's Copilot Chat extension, suggesting this is specific to the
rmcp-based client used by Copilot CLI/App rather than a server-side issue.
Additional Notes
- This was root-caused by directly testing the target MCP server with and without a
User-Agentheader: omitting it reproduces byte-for-byte the same generic HTML 403 response seen by the CLI/App, while including any non-emptyUser-Agentreturns the expected JSON response from the server's own application layer. - No corporate proxy, VPN, or network-level header rewriting was involved — headers were confirmed to pass through the network unmodified in isolated testing.
- We suspect the
initializerequest after OAuth is issued via a code path (RawCapturingReqwestClientinrmcp::transport::streamable_http_client) that either uses a fresh/defaultreqwest::Clientwithout the configuredUser-Agent/custom headers, or otherwise doesn't propagate the per-server header configuration used for other requests.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Suivez la requête d'initialisation qui suit OAuth à travers rmcp::transport::streamable_http_client et RawCapturingReqwestClient, en la comparant aux requêtes qui utilisent les headers configurés de mcp-config.json. Commencez par reproduire la requête post-connexion avec un User-Agent obligatoire et un header personnalisé. La tâche est terminée lorsque la requête d'initialisation envoie un User-Agent non vide et conserve les headers personnalisés configurés, avec une couverture de régression pour ce chemin OAuth.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- rust
- Domaine
- api, authentication, cli
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 55/100