MCP OAuth: initialize request after successful OAuth login omits User-Agent header, ignoring configured custom headers
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Shell
- Star
- 11.2k
- Fork
- 1.9k
- Merge trung bình
- 14 giờ 16 phút
- Pull request đã merge (30 ngày)
- 6
Mô tả
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.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Theo dõi yêu cầu initialize tiếp theo OAuth qua rmcp::transport::streamable_http_client và RawCapturingReqwestClient, đồng thời so sánh với các yêu cầu sử dụng các header được cấu hình trong mcp-config.json. Bắt đầu bằng cách tái hiện yêu cầu sau khi đăng nhập với một User-Agent bắt buộc và một header tùy chỉnh. Hoàn thành có nghĩa là yêu cầu initialize gửi một User-Agent không rỗng và giữ nguyên các header tùy chỉnh đã cấu hình, kèm theo kiểm thử hồi quy cho đường dẫn OAuth này.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- rust
- Lĩnh vực
- api, authentication, cli
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 55/100