[BUG] Claude Desktop 3P: managedMcpServers OAuth never refreshes on-demand — a failed silent refresh 403s every call until manual reconnect
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
On Claude Desktop (third-party / 3P), a managedMcpServers entry configured with an oauth
block (external OIDC IdP, short access-token lifetime) does not recover on its own after a
single failed silent token refresh.
The access token is short-lived (5 min in our IdP). The app refreshes it on a background timer.
When one refresh fails for a transient reason — a laptop sleep or Wi-Fi switch, i.e. normal
mobile use — the app enters an escalating backoff (observed up to 30 minutes) and does not:
- refresh on demand when the user actually invokes a tool (it holds a valid long-lived
offline refresh token, but doesn't use it at call time — it just fails), nor
- reset the backoff when network connectivity returns.
Result: every tool call returns Forbidden for up to ~30 minutes, and the connector's status
badge still shows "connected" the whole time (it reflects the transport session established at
connect, not current token validity). The only recovery is a manual disconnect/reconnect,
which a non-technical end user will never discover. This makes managed OAuth MCP servers
unreliable for a fleet.
What Should Happen?
The connector should self-heal without user intervention. Any of these would fix it:
- Refresh on demand: when a tool call hits an expired access token, attempt a refresh (using
the held offline refresh token) before failing the call. This alone would make the failure
invisible.
- Reset backoff on network recovery (online event), instead of holding a 30-minute timer.
- Reflect auth state in the connector status so "connected" doesn't display while every call
is 403ing (secondary, but it's why the failure is so confusing).
Error Messages/Logs
From main.log (hostnames genericized):
[warn] [custom3p-mcp] mid-session refresh did not rotate
{ server: 'Web Search', failCount: 7, backoffMs: 1800000,
reason: 'discovery: net::ERR_INTERNET_DISCONNECTED' }
[info] [custom3p-mcp host] [directMcpHost:Web Search] callTool failed:
<tool>: Streamable HTTP error: Error POSTing to endpoint:
{"error":"Forbidden","request_id":"…"}
The gateway side confirms the presented token is simply expired (rejected at IdP-token
validation) — the server is behaving correctly; the client never renewed. Note alsoreason: 'discovery: net::ERR_…' — the refresh re-runs full OIDC discovery each time, so a
blip during discovery (not just the token endpoint) fails the whole refresh; caching discovery
would make refresh more resilient.
Steps to Reproduce
- Deploy a 3P
managedMcpServersentry with anoauthblock against an external OIDC IdP whose
access-token lifetime is short (e.g. 5 min), with offline_access so a refresh token is held.
- Connect and complete the OAuth sign-in; confirm tools work.
- Cause one silent refresh to fail transiently — sleep the laptop or switch networks across
a background-refresh tick (log shows mid-session refresh did not rotate … net::ERR_…).
- Restore network; wait past the access-token lifetime.
- Invoke a tool on that server →
Forbidden, and it keeps failing (no on-demand refresh)
while the connector shows connected, until the backoff elapses or you manually
disconnect/reconnect.
Claude Model
N/A (third-party inference; behavior is in the MCP OAuth client, model-independent)
Is this a regression?
Not sure — appears to be current 3P behavior since GA.
Last Working Version
N/A
Claude Code Version
Claude Desktop (3P) 1.19367.0
Platform
Claude Desktop (third-party / 3P)
Operating System
macOS (Darwin 25.5)
Terminal/Shell
N/A (desktop app)
Additional Information
- Config surface:
managedMcpServers[].oauthwithclientId+authorizationServer
(external IdP), appendOfflineAccess: true. The held offline refresh token remains valid, so
on-demand refresh is possible — the app just doesn't attempt it at call time.
- Same managed-MCP area as #64578, #72808, #69953 — the OAuth-lifecycle robustness of managed
servers on 3P.
- Happy to provide full logs or a reproduction environment.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗