fix(mcp): skip OAuth discovery when static Authorization header is configured#1357
Merged
Merged
Conversation
…nfigured When an operator configures a static Authorization header on an HTTP MCP server via --header, the daemon was blocking the connection entirely with an 'Awaiting Auth' status if the server responded to the OAuth discovery probe with a 401 + WWW-Authenticate containing resource_metadata= (GitHub issue #1350). This happened because CreateClientAsync only checked for cached OAuth tokens before running the discovery probe, ignoring whether the user had already configured static auth headers. Fix: skip OAuth discovery if the server entry has any Authorization header configured. The static header will be sent through to the server as normal. Also added: - McpOAuthHeaderConflictTests.cs: 3 regression tests reproducing the bug and verifying the fix (one would fail without the fix) - CachedOAuthTokens_AreCheckedBeforeOAuthDiscovery: validates that pre-existing cached tokens are still respected Fixes #1350
Extract shared setup into CreateManager helper, use `using var` for manager disposal, reduce CTS timeout from 2 min to 15 sec, and add Assert.NotNull guard on the reflected _tokens field.
Broaden the check from Authorization-only to any configured headers. The OAuth probe doesn't send user-configured headers, so its 401 is misleading for servers that use X-API-Key, custom tokens, or any non-Authorization auth mechanism. See #1350. Added NonAuthorizationHeader_WhenServerReturnsOAuthMetadata_StillConnects test covering the X-API-Key case.
Instead of skipping the probe when headers exist, always run it so metadata is cached for the runtime fallback in BuildConnectionFailureStatus. Only block with AwaitingAuth when the user has no configured headers — if headers are present, let the real connection attempt (which carries the user's credentials) decide whether auth succeeds or fails. This avoids guessing which headers are auth-related and ensures the runtime fallback correctly identifies OAuth-required servers even when the user's credentials turn out to be wrong.
… probe test Add --require-auth flag to the smoke MCP server: unauthenticated requests get 401 + WWW-Authenticate with resource_metadata pointing back to the server's own OAuth discovery endpoints. The server serves the full metadata chain (resource-metadata, well-known/oauth-authorization-server) so the OAuth probe resolves without hitting an external provider. The e2e test ConfiguredHeader_WhenOAuthProbeReturnsMetadata_StillReachesServer now uses this mode — both the OAuth probe and the MCP transport hit the same real server with no fakes. Proves the static Authorization header reaches the server even when the probe discovers OAuth metadata. Reverted the oauthHttpOverride on McpSmokeHarness (no longer needed).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When an operator configures a static
Authorizationheader on an HTTP MCP server vianetclaw mcp add --header "Authorization: Bearer ...", the daemon blocks the connection entirely with an "Awaiting Auth" status if the server responds to the OAuth discovery probe with a401 + WWW-Authenticateheader containingresource_metadata=.This means users who want to authenticate via a static bearer token are forced into an interactive OAuth flow that they did not request and may not be able to complete.
Root Cause
In
McpClientManager.CreateClientAsync()(lines 513-528), the code only checked for cached OAuth tokens (_oauthService.GetTokenSet(name)) before running the OAuth discovery probe. It did not check whether the user had configured a staticAuthorizationheader on the server entry (entry.Headers).If OAuth metadata was found, the daemon returned
nulland set status toAwaitingAuth— never reachingCreateTransport()where the configured headers would be sent.Fix
Added a check for existing
Authorizationheaders inentry.Headersbefore running the OAuth discovery probe:If static auth headers are configured, discovery is skipped and the connection proceeds normally with the configured bearer token sent through to the server.
Testing
Added
McpOAuthHeaderConflictTests.cswith 3 regression tests:StaticAuthHeader_WhenServerReturnsOAuthMetadata_StillConnects— the bug reproduction. Without the fix, this fails withclient == nullbecause OAuth blocking aborts the connection even though a static header is configured.StaticAuthHeader_WhenServerReturnsNoOAuthMetadata_ConnectsNormally— positive control validating the test harness works.CachedOAuthTokens_AreCheckedBeforeOAuthDiscovery— validates pre-existing cached tokens are still respected.All 57 MCP tests pass with zero regressions.
Fixes #1350