fix(mcp): pass OAuthClientProvider to call_mcp_tool for automatic token refresh - #9267
fix(mcp): pass OAuthClientProvider to call_mcp_tool for automatic token refresh#9267Fizza-Mukhtar wants to merge 5 commits into
Conversation
Greptile SummaryThis PR fixes OAuth MCP tool calls silently failing with 401 errors after the access token expires by passing an auth provider to Key changes:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[MCPTool.run called] --> B[Build connection headers]
B --> C{auth_type == OAUTH?}
C -- No --> G[call_mcp_tool without auth]
C -- Yes --> D{transport == SSE?}
D -- Yes --> E[Log warning: refresh unsupported]
E --> G
D -- No --> F[Construct OAuthClientProvider]
F --> H[call_mcp_tool with auth provider]
H --> I{Token valid?}
I -- Yes --> J[Request sent with current token]
I -- No --> K[SDK attempts token refresh]
K -- Success --> L[Store new tokens, retry request]
K -- Refresh expired --> M[redirect_handler raises ValueError]
M --> N[Caught as auth error, prompt user to reconnect]
G --> O[Return ToolResponse]
J --> O
L --> O
N --> O
Last reviewed commit: 75b24ff |
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/onyx/tools/tool_implementations/mcp/mcp_tool.py">
<violation number="1" location="backend/onyx/tools/tool_implementations/mcp/mcp_tool.py:274">
P2: Generic `"reconnect"` substring matching can misclassify transport/runtime failures as authentication failures and return misleading credential-update guidance.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
Thanks for the fix! I can confirm the root cause analysis is correct. One thing I noticed while working around this on my end: this PR may not fully solve the problem for OAuth providers whose token refresh responses omit the The MCP SDK's self.context.current_tokens = token_response
await self.context.storage.set_tokens(token_response)If a refresh response only contains A fix would be to preserve the old if not token_response.refresh_token and self.context.current_tokens and self.context.current_tokens.refresh_token:
token_response = OAuthToken(
access_token=token_response.access_token,
token_type=token_response.token_type,
expires_in=token_response.expires_in,
scope=token_response.scope,
refresh_token=self.context.current_tokens.refresh_token,
)This might belong in the MCP SDK itself rather than in Onyx though. |
Thanks for confirming and for the detailed follow-up! You're right — this edge case is separate from the fix here. I agree it likely belongs in the MCP SDK itself. Happy to follow up if the team thinks a workaround should live in Onyx too! |
|
I've filed the upstream fix for the refresh_token preservation issue in the MCP Python SDK:
If that's merged and released, Onyx will need to bump its |
|
LGTM, I'll make a mirror to run our CI |
|
Hi @evan-onyx 👋 |
some CI is failing #9414 that looks like it might be real issues (most accurately, a test or two that needs to be updated). @Fizza-Mukhtar if you're willing to make those fixes it would be fantastic, otherwise I'll get to it when I have time (hopefully later today, but might be a few days at worst) |
Sure, I'll take a look at the failing tests and push a fix! |
actually sorry I just pushed one 😅 it ended up being pretty simple |
|
@Fizza-Mukhtar I'll merge the mirror once it passes, which should be soon! |
…r automatic token refresh (#9414) Co-authored-by: Fizza-Mukhtar <fizzamukhtar01@gmail.com>
|
The mirror PR #9414 has been merged! |
Summary
OAuth MCP tool calls fail with
401 Unauthorizedafter the access tokenexpires (~10 min).
MCPTool.run()was passing only staticconnection_headers(with the Bearer token) tocall_mcp_tool(), butnever the
OAuthClientProvider— so the MCP SDK had no way to refreshthe token automatically.
The admin tool discovery path (
_list_mcp_tools_by_id) already constructsan
OAuthClientProviderviamake_oauth_provider()and passes it through.This fix brings tool execution into parity with tool discovery.
Root Cause
In
MCPTool.run():Fix
MCPTool.__init__: adduser_idparameterMCPTool.run(): constructOAuthClientProviderforOAUTHservers andpass
auth=tocall_mcp_tool(), enabling automatic token refresh viathe MCP SDK
tool_constructor.py: passuser_id=str(user.id)when constructingMCPToolTesting
_list_mcp_tools_by_idRelated
Closes #9237
Additional Options
Summary by cubic
Fixes OAuth MCP tool calls failing with 401s after token expiry by passing an
OAuthClientProvidertocall_mcp_tool, enabling automatic token refresh. Aligns tool execution with the discovery path and closes #9237.OAUTHservers, passauth(OAuthClientProvider) tocall_mcp_toolfor automatic token refresh; onSSEtransport, log a warning and skip the provider.user_idtoMCPTooland wire it fromtool_constructor.py.Written for commit 75b24ff. Summary will update on new commits.