Missing Token Refresh Mechanism for MCP Server Integrations
Resolved 💬 36 comments Opened Aug 13, 2025 by fokkedekker Closed May 23, 2026
💡 Likely answer: A maintainer (localden, collaborator)
responded on this thread — see the highlighted reply below.
Bug Description
This isn't technically a bug but rather a missing feature. Currently there is no way for Claude Code to refresh tokens for MCP servers. This means that we either have to have a very long lived token or manually refresh it.
Our platform deeply integrates with Claude Code and our MCP is effecively a state machine that has claude call various MCP calls to build and deploy applications. This building process can take 30-60 minutes.
The MCP spec does seem to call for a refresh token ability but I don't think Claude Code implements it. Happy to provide more feedback if you want you can reach me at fokke@liquidmetal.ai
Environment Info
- Platform: darwin
- Terminal: WarpTerminal
- Version: 1.0.77
- Feedback ID: 03061b16-5aa1-46a6-9c91-4125d664ee73
Errors
[]
36 Comments
I am seeing this same issue. I can get Claude Code to authenticate our MCP sever via Oauth (using WorkOS as the provider) but when the token expires, it does not refresh the token. We send a 401 with the /.well-known/oath-protected-resource header. Claude Code calls that end point but never goes to the /.well-known/oauth-authorization-server to get the authentication endpoint.
Can someone actually comment if this is even working on WebUI? I currently have no way to know if we can refresh, like we never see any attempts and it's super frustrating. The idea may be to just allow for a long lived JWT but without the refresh mechanism it's kind of pointless
Also btw to acknowledge OP: You can just use API key if you need to use it without any Oauth system.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
i have built an MCP server using fastmcp and i am having this problem too
Set JWT to 30 days.. don't do refresh
Im seeing the same issue. @plappag - I dont have option to tweak the JWT
Facing the same issue, our custom MCP is protected by Microsoft OAuth, which issues access tokens that expire in 60-90 minutes. Manual re-auth is super tedious. Refresh tokens are issued but not consumed by Claude Code
Well, it's an option.
I notice Linear's MCP server chose that workaround too: their access tokens expire in 7 days by default.
But I don't think it's the right solution, and neither do the MCP protocol authors, who say:
The same page says MCP's authorization is based on OAuth 2.1, which says:
Somehow, Claude Code gives me an uninterrupted experience with the Linear MCP: I haven't had to reauthenticate or reauthorize in months. I don't think it can be dynamically registering a new client every time.
So I feel Claude Code must _already_ implement refresh, but it's not working at shorter lifetimes?
Implementing or fixing refresh would make for a much smoother MCP experience.
This is a huge issue for revo (@atlassian) https://community.atlassian.com/forums/Rovo-questions/The-MCP-Auth-expires-too-fast/qaq-p/3124036 ; it makes it basically unusable after ~5 minutes
Major issue for me too. Reauth'ing our company MCP every 8-24 hours or so means that workflows, often, fail unexpectedly, only to find mid session an MCP server is gone. So incredibly painful
+1 here - we use JWTs with ~1h TTL to get past Istio's auth and reach internal MCP servers.
Would also welcome integrations with standard tools like KeyCloak, cloud provider OIDC tokens, GH OIDC tokens etc.
Can confirm that Asana MCP has the same issue, re-auth is sometimes needed multiple times per day.
Atlassian MCP also has the same problem
Same issue with Google Workspace MCP (and anything else that uses a token with a short lived expiry, as is the security best practice for such things). Claude Code does not currently refresh OAuth tokens for MCP servers automatically, causing them to expire in idle or long-running sessions. It is a long running and well known issue (seeing as this very github issue I'm commenting on dates back to august) but more importantly (especially given who maintains the project), it's a violation of the MCP spec.
MCP Spec - 2.5.3 Token Refresh When access tokens expire, clients SHOULD use refresh tokens (if available) to obtain a new access token without additional user interaction. Token refresh MUST follow the refresh token grant defined in OAuth 2.1 Section 4.3.
Same thing, anoying to work with:
theoretically all of these support refresh tokens, but claude code does not use it
This bug is not a responsibility of CC.
CC do refresh token when it is connected directly to the MCP server via HTTP.
The issue is with the plethora of
vibecodeofficial servers that did not implement the auto refresh.As @taylorwilsdon stated , the spec 2.5.3 does say :
clients SHOULD use refresh tokens.But in this case CC is dealing with a middleman (the STDIO server) and STDIO protocol has no Authorization concept.
This bug will affect you no matter if you using CC, Codex or any other harness.
+1 - hitting this with the Atlassian MCP server. Tokens expire frequently and the only workaround is manual re-auth via
/mcp, which breaks long-running sessions. Would love to see proper refresh token support per the MCP spec. Happy to help test if a fix lands.@seuros I am not talking about any local MPC servers.
The official Notion mcp is using http protocol.
The docs make it clear it does support refresh tokens.
Internally it is using cloudflare/workers-oauth-provider, which does support refresh.
However I still have to authenticate it every day, so it seems something is not going right with claude code refresh.
See https://developers.notion.com/guides/mcp/build-mcp-client#notion-mcp-oauth-specifics
https://github.com/cloudflare/workers-oauth-provider?tab=readme-ov-file#token-exchange-callback
<img width="708" height="394" alt="Image" src="https://github.com/user-attachments/assets/dd978ffa-5b60-4285-be96-06575a25e9ae" />
Hm, I don't think any of the servers being discussed here are stdio (workspace mcp, atlassian and notion certainly aren't at least) and in a compliant OAuth 2.1 MCP spec implementation, the client is responsible for refresh token handling so I think it's very much a claude code responsibility...
Chiming in to say we're running into the same issue. Our MCP server is leveraging WorkOS for the OAuth portion and this is handled well in claude.ai as well as other CLI's. Looks like using
mcp-remotemight be a workaround, but haven't tested itDetailed reproduction with Notion MCP — token refresh works mid-session but NOT at startup
Adding concrete data points from the official Notion MCP (
https://mcp.notion.com/mcp, HTTP transport, installed via official marketplace plugin).Environment: macOS (Darwin 25.3.0), Claude Code v2.1.56 (stable), Max plan
Key finding: Claude Code does refresh tokens when a tool is invoked mid-session, but does not refresh expired tokens during MCP server connection at session startup. Mid-session refresh may also be unreliable — it worked in this test but has failed in other sessions.
Timeline (all times EET, Feb 25 2026):
| Time | Event |
expiresAt|accessToken(suffix) |refreshToken(suffix) ||------|-------|-------------|----------------------|----------------------|
| 10:10 | Checked
~/.claude/.credentials.json— token still valid |1772009914023(10:58) |...HSmlbmJE3i|...FJKDGboBbKSJ8x|| 10:58 | Token expired | — | — | — |
| 11:05 | Checked file — no change, no refresh attempted |
1772009914023(10:58) |...HSmlbmJE3i|...FJKDGboBbKSJ8x|| 11:37 | Checked again — still no change |
1772009914023(10:58) |...HSmlbmJE3i|...FJKDGboBbKSJ8x|| 11:38 | Invoked
notion-fetchtool — worked! |1772015903772(12:38) |...g5H3sRh8ZA|...ilQZLTAcAC|Observations:
~/.claude/.credentials.jsonand works correctlyrefresh_tokeningrant_types_supported△ needs authenticationwarning — even though a valid refresh token was availablescopefield is empty ("") in the stored credentials — unclear if this affects the refresh logicRoot cause hypothesis: The MCP health check at session startup sees an expired
expiresAt, and instead of attempting arefresh_tokengrant, it immediately falls back to showing "needs authentication". The on-demand refresh path (triggered when a tool is actually called) exists but appears unreliable.Expected behavior: On session startup, if
expiresAthas passed but arefreshTokenis present and the server's metadata includesrefresh_tokeningrant_types_supported, Claude Code should attempt the refresh grant before falling back to re-authentication.— Posted by Claude Code (Opus 4.6) on behalf of @danmana
Were some edge cases fixed in the latest Claude Code release?
@nkovacic I haven't seen the issue in the last day.
It seems now the token is refreshed when a new claude code is started, as well as if it expires during a session.
Unless there are more corner cases, I think this is fixed.
I'll keep an eye on this and post here if it happens again
Well the strangest thing happened right after posting that.
I closed a claude code session and started claude again, and on the first message I typed it said
Not logged in · Please run /loginLogged in again, and then the Notion mcp needed Authorization again
Yes it seems Claude Code is now refreshing (with v2.1.63): it is definitely no longer missing a token refresh mechanism.
Yes, I haven't had any issues with Notion at least in the last week.
So I think this is fixed.
Can confirm I'm seeing refreshes land as well. Looks like it was fixed in that push last week but they didn't close out the issue.
In case this comes up again (OAuth is tricky, especially if multiple CC sessions are involved).
I built Bindify to solve exactly this. It's an MCP auth proxy that sits between Claude Code and GitHub, Todoist, etc. You authenticate once through Bindify, get a secret URL, and paste it into Claude Code (or Claude.ai) as a remote MCP server. Bindify handles the OAuth token refresh server-side. If you still run into issues, you can fall back to API token authentication, even with Claude.ai/mobile via Bindify's secure URLs.
Setup guide: https://bindify.dev/fix/claude-todoist-mcp-expired — use code CLAUDEAUTHFIX to try it free for 2 months (limited to 10 people).
Disclaimer: I'm the developer behind Bindify. Feel free to reach out with questions.
Having this issue as well. I'm using oath middleware that refreshes a token used by headersHelper, which unfortunately doesn't handle token refresh for a remote hosted MCP Server. Yes I can do a local MCP Server proxy, but I'd rather not do that.
@etanlightstone : that sounds like this bug has reappeared.
You can try Bindify.dev for handling your tokens with remote mcp servers. It does have a cost of $2/month after a free trial. It’s a good way to keep your workflow going strong while they sort these bugs out.
Disclaimer: I’m the developer behind Bindify.
@dylancwood
That's ok, I have my own solution / workaround. Also it's portable (will work seamlessly with other coding agents other than Claude Code). Local "lightweight" STDIO style MCP Server that acts as a proxy to the remote one and also handles OAuth refresh.
@etanlightstone-domino That's exactly the pattern mcp-stdio implements — a local stdio relay that bridges to a remote Streamable HTTP MCP server and handles OAuth token refresh transparently (401 → refresh → retry). Open source (MIT), single binary via
pip/uvx/brew, only depends onhttpx.Example config for Claude Desktop / Claude Code:
Tokens are cached in
~/.config/mcp-stdio/tokens.json(0600) and refreshed automatically when the upstream returns 401 mid-session. It also implements the full MCP authorization spec (RFC 9728 / 8414 / 8707 / 7636 / 7591 / 6750), so it works with providers that enforce strict scope or resource indicator requirements.That's a great workaround, and the right way to go for coding agents. Bindify.dev is still necessary to solve the problem for claude mobile and web.
Thanks for the report. Token refresh for direct MCP connections was added and has been reliable since 2.1.69. If you are still being asked to re-authenticate on a current version, please open a new issue with the server URL and version.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.