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

[]

View original on GitHub ↗

36 Comments

harrymower · 10 months ago

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.

plappag · 9 months ago

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

plappag · 9 months ago

Also btw to acknowledge OP: You can just use API key if you need to use it without any Oauth system.

github-actions[bot] · 7 months ago

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.

agusdmb · 7 months ago

i have built an MCP server using fastmcp and i am having this problem too

plappag · 7 months ago

Set JWT to 30 days.. don't do refresh

skishtapuram-loyaltymethods · 7 months ago

Im seeing the same issue. @plappag - I dont have option to tweak the JWT

mauricekleine · 7 months ago

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

pjcdawkins · 7 months ago
Set JWT to 30 days.. don't do refresh

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:

Authorization servers SHOULD issue short-lived access tokens to reduce the impact of leaked tokens.

The same page says MCP's authorization is based on OAuth 2.1, which says:

Authorization servers SHOULD issue short-lived bearer tokens, particularly when issuing tokens to clients that run within a web browser or other environments where information leakage may occur. Using short-lived bearer tokens can reduce the impact of them being leaked.

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.

theshadow27 · 6 months ago

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

mattheworiordan · 5 months ago

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

achilleasatha · 5 months ago

+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.

nkovacic · 5 months ago

Can confirm that Asana MCP has the same issue, re-auth is sometimes needed multiple times per day.

bmz1 · 5 months ago

Atlassian MCP also has the same problem

taylorwilsdon · 5 months ago

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.

danmana · 4 months ago

Same thing, anoying to work with:

  • Notion mcp - expires in 1 hour, refresh supported but claude code doesn't refresh it
  • Figma mcp - not sure how long, feels like daily
  • Sentry mcp

theoretically all of these support refresh tokens, but claude code does not use it

seuros · 4 months ago

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 vibecode official 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.

mr-lee · 4 months ago

+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.

danmana · 4 months ago

@seuros I am not talking about any local MPC servers.

The official Notion mcp is using http protocol.

 "Notion": {
      "type": "http",
      "url": "https://mcp.notion.com/mcp"
    }

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" />

taylorwilsdon · 4 months ago
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 vibecode official 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.

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...

ndom91 · 4 months ago

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-remote might be a workaround, but haven't tested it

danmana · 4 months ago

Detailed 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-fetch tool — worked! | 1772015903772 (12:38) | ...g5H3sRh8ZA | ...ilQZLTAcAC |

Observations:

  1. The refresh token IS stored in ~/.claude/.credentials.json and works correctly
  2. Notion's server advertises refresh_token in grant_types_supported
  3. Notion uses refresh token rotation — both access and refresh tokens change on each refresh
  4. Token TTL is ~1 hour
  5. When opening Claude Code, Notion MCP showed the △ needs authentication warning — even though a valid refresh token was available
  6. Once a Notion tool was invoked within an active session, the refresh happened automatically and succeeded in this case — but this has not been reliable across all sessions. Sometimes mid-session tool calls also fail with auth errors instead of triggering a refresh
  7. The scope field is empty ("") in the stored credentials — unclear if this affects the refresh logic
  8. If Notion uses refresh token rotation and a mid-session refresh fails (or a concurrent session rotates the token), the stored refresh token becomes permanently invalid, forcing a full re-auth

Root cause hypothesis: The MCP health check at session startup sees an expired expiresAt, and instead of attempting a refresh_token grant, 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 expiresAt has passed but a refreshToken is present and the server's metadata includes refresh_token in grant_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

nkovacic · 4 months ago

Were some edge cases fixed in the latest Claude Code release?

danmana · 4 months ago

@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

danmana · 4 months ago

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 /login

Logged in again, and then the Notion mcp needed Authorization again

pjcdawkins · 4 months ago

Yes it seems Claude Code is now refreshing (with v2.1.63): it is definitely no longer missing a token refresh mechanism.

danmana · 4 months ago

Yes, I haven't had any issues with Notion at least in the last week.
So I think this is fixed.

taylorwilsdon · 4 months ago

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.

dylancwood · 4 months ago

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.

etanlightstone · 3 months ago

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.

dylancwood · 3 months ago

@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.

etanlightstone-domino · 3 months ago
@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.

shigechika · 3 months ago

@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 on httpx.

Example config for Claude Desktop / Claude Code:

{
  "mcpServers": {
    "my-server": {
      "command": "mcp-stdio",
      "args": ["--oauth", "https://your-server.example.com/mcp"]
    }
  }
}

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.

dylancwood · 3 months ago

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.

localden collaborator · 1 month ago

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.

github-actions[bot] · 3 days ago

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.