github / github/copilot-cli

MCP OAuth: initialize request after successful OAuth login omits User-Agent header, ignoring configured custom headers

オープン
#4,681 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

area:authentication area:mcp area:networking
主要言語
Shell
スター
11.2k
フォーク
1.9k
平均マージ
14時間 16分
マージ済み PR(30日)
6

説明

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

  1. 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"
    
  2. Trigger authentication (e.g. via Authenticate in the Copilot App, or by using the tool in Copilot CLI).
  3. Complete the browser-based OAuth login/consent flow successfully.
  4. Observe that the subsequent initialize request fails if the target server (or infrastructure in front of it) rejects requests lacking a User-Agent header — even though the configured custom User-Agent header was set on the server config.

Expected Behavior

  • The MCP client should always send a non-empty User-Agent header (e.g. an SDK/product default such as GitHubCopilotCLI/<version>) on all requests, including the post-OAuth initialize request.
  • Any custom headers configured for the MCP server (via --header, or the headers field in mcp-config.json) should be honored consistently across all requests sent to that server, including the OAuth-authenticated initialize request — not only a subset of requests.

Actual Behavior

  • The initialize request sent after a successful OAuth token exchange appears to omit the User-Agent header entirely (confirmed via server-side testing: a request without any User-Agent header reproduces the exact same generic, non-JSON 403 Forbidden response observed by the client).
  • Configuring a custom User-Agent header via copilot mcp add --header "User-Agent: ..." does not change this behavior — the header is stored in mcp-config.json but is not applied to the initialize request.
  • 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-up initialize call.

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-Agent header: omitting it reproduces byte-for-byte the same generic HTML 403 response seen by the CLI/App, while including any non-empty User-Agent returns 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 initialize request after OAuth is issued via a code path (RawCapturingReqwestClient in rmcp::transport::streamable_http_client) that either uses a fresh/default reqwest::Client without the configured User-Agent/custom headers, or otherwise doesn't propagate the per-server header configuration used for other requests.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

OAuth 後続の initialize リクエストを rmcp::transport::streamable_http_client と RawCapturingReqwestClient を通して追跡し、設定された mcp-config.json のヘッダーを使用するリクエストと比較します。まず、必須の User-Agent とカスタムヘッダーを指定したログイン後のリクエストを再現します。完了条件は、initialize リクエストが空でない User-Agent を送信し、設定されたカスタムヘッダーを保持すること、およびこの OAuth パスに対する回帰テストがあることです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
rust
領域
api, authentication, cli
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
55/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。