Repository navigation
fix: avoid OAuth auth lock on streamable MCP connections - #51149
THArrowofApollo wants to merge 1 commit into
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Allows OAuth Streamable-HTTP data-plane to use a plain bearer header with cached tokens, avoiding the OAuthClientProvider auth lock that was blocking subsequent tools/list POST calls. Adds two regression tests for bearer header materialization and token refresh. Good fix with test coverage.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused OAuth transport fix. The lock premise remains present on current main: tools/mcp_tool.py:2361-2367 obtains the SDK provider and tools/mcp_tool.py:2490-2501 passes it to the shared Streamable HTTP client. In MCP 1.26.0, mcp/client/auth/oauth2.py:484-503 holds the OAuth context lock while yielding the request, and mcp/client/streamable_http.py:266-275 can keep the GET/SSE request open.
Problems
- The new regression test covers only
_MCP_NEW_HTTP=True. The changed_oauth_auth = Nonebehavior also reaches the SSE path (tools/mcp_tool.py:2383-2409) and legacy Streamable HTTP path (tools/mcp_tool.py:2523-2532), without assertions for their header/auth wiring.
Suggested changes
- During salvage onto current main, cover the legacy Streamable HTTP branch and assert it receives the bearer header without the SDK auth provider; cover SSE too if that change is intentional.
This is an automated hermes-sweeper review.
| _bearer_header = await _oauth_manager.get_bearer_authorization_header( | ||
| self.name, url, config.get("oauth"), | ||
| ) | ||
| if _bearer_header: |
There was a problem hiding this comment.
This clears _oauth_auth for the later SSE and legacy Streamable HTTP branches as well as the new client path. Please add coverage for at least the legacy branch to verify it receives the bearer header and no SDK auth provider; add an SSE assertion too if changing its auth behavior is intentional.
|
Rebase-on-behalf delivery — this PR's branch was rebased onto current main ( Rebased branch: Conflict resolution (2 files):
To adopt (author): py_compile verified; test-coverage superset verified. This unblocks the mcp_tool extraction window (hunk gate). |
|
Closing with credit — you diagnosed this lock-held-across-the-streamable-GET class first (June 23). The fix that landed (PR #97458 by @helix4u, merge 9a1eef7) takes a different mechanism: it keeps the OAuth provider on the data plane but converts the SDK's task-owned lock to a binary semaphore released around resource I/O, so refresh still works mid-session. Your bearer-materialization approach would have bypassed refresh on the data plane. Thanks for the early, correct diagnosis. |
Summary
Why
Eden's Streamable HTTP MCP transport opens a long-lived GET/SSE stream after initialize. The Python MCP SDK OAuth provider can hold its auth-flow lock while that response remains open, which blocks subsequent POST requests such as tools/list. Hermes then hangs during tool discovery despite having valid OAuth credentials.
Test Plan