Repository navigation
Closed
Closed
Copy link
Description
Bug: mcp-auth.json loses tokens for multiple servers — MCP servers suddenly need re-auth
Summary
OAuth tokens in ~/.local/share/opencode/mcp-auth.json get wiped for several MCP servers at once. Sessions that were authenticated start prompting for auth again, even though the OAuth server's refresh token is still valid. It is not server-specific — several unrelated servers lost tokens in the same rewrite.
Observed
- File
mcp-auth.jsonwas rewritten (mtime changed) without a manual edit. - Before rewrite: several servers had a
tokensobject (accessToken,refreshToken,expiresAt,scope). - After rewrite: only servers whose entries contained NO leftover PKCE state (
codeVerifier/oauthState) kept theirtokens. Every entry that still carriedcodeVerifier+oauthStatelost itstokens— reduced toclientInfo+codeVerifier+oauthState+serverUrl. - The affected servers use different OAuth providers (custom SDK OAuth, Keycloak, Jira, etc.), so this is not one provider's token format.
What this looks like per entry
{
"clientInfo": { "clientId": "...", "clientIdIssuedAt": 1786703712 },
"codeVerifier": "...",
"oauthState": "...",
"serverUrl": "https://..."
}→ no tokens key at all. The server-side refresh token still exists and works (verified by calling the token endpoint with grant_type=refresh_token — returns a fresh access token), so the only thing lost is the client's stored copy.
Impact
Any MCP server that does OAuth (dynamic client registration) requires a full interactive re-auth every time the file is rewritten. This happened at least twice in our setup within days.
Hypothesis
- Re-running
opencode mcp add <server>overwrites the existing entry with a fresh clientInfo/PKCE state and drops the stored tokens. - Or: the auth file is rewritten wholesale (version upgrade / config change / another process), and only entries written with tokens survive; anything mid-flow or registered-but-not-completed loses its tokens.
- Correlates with leftover PKCE state: entries that still hold
codeVerifier/oauthStateare the ones that lost tokens — clean entries (no leftover PKCE state) kept theirs.
Expected
opencode mcp add/ re-config on an existing server should preserve existingtokens(or warn that re-auth is required instead of silently dropping them).- If the file is rewritten wholesale, tokens should be merged/retained per server.
Environment
- opencode, Linux, latest as of 2026-08-16.
mcp-auth.jsonpath:~/.local/share/opencode/mcp-auth.json- Trigger not yet pinned to a single command — file mtime changed without a manual edit.
Metadata
Metadata
Assignees
Labels
No labels
Activity
github-actions commentedon Aug 16, 2026
This issue might be a duplicate of existing issues. Please check:
opencode mcp authre-registers a new dynamic client every run instead of reusing the stored registration #35625: MCP OAuth re-registers a new dynamic client every run instead of reusing stored registration — the hypothesis aboutopencode mcp addoverwriting an entry and dropping tokens aligns closely with this issue.iamwoz commentedon Aug 17, 2026
Same issue here — opencode
1.18.18, Linux (headless host).Setup
Remote MCP server at
https://mcp.fibery.io/mcp(OAuth + dynamic client registration), configured asfibery-[redacted]. It was previously namedFiberyand later renamed.Symptoms
Every new opencode session drops back to
needs_authand forces a full interactive re-auth.The log has ~30 occurrences over the last few days:
level=WARN message="server unavailable" key=fibery-[redacted] type=remote status=needs_auth
One long-lived session stayed authenticated for ~23 hours, so the refresh flow works within a process — it's the persisted token that's lost, not the server-side refresh token.
mcp-auth.json state
Matches the report's signature exactly: leftover PKCE state, no
tokenskey.{ "fibery-[redacted]": { "clientInfo": { "clientId": "ccfac24a-…" }, "codeVerifier": "…", "oauthState": "…", "serverUrl": "https://mcp.fibery.io/mcp" }, "Fibery": { "clientInfo": { "clientId": "3a61e33e-…" }, "codeVerifier": "…", "oauthState": "…", "serverUrl": "https://mcp.fibery.io/mcp" } }Two things stand out:
opencode mcp authre-registers a new dynamic client every run instead of reusing the stored registration #35625.Confirmed not a provider issue
Fibery's authorization server metadata (/.well-known/oauth-authorization-server) advertises
grant_types_supported: ["authorization_code","refresh_token"] and scopes_supported: "openid","offline"]. Exercising the token endpoint directly with grant_type=refresh_token returns a fresh access token, so the server-side refresh token is still valid — only opencode's stored copy was dropped.
big-andy-coates commentedon Aug 19, 2026
Hit this with the
atlassian-rovo-mcpremote server (https://mcp.atlassian.com/v1/mcp/authv2) and traced it end to end — adding as a concrete data point since this issue doesn't currently mention Atlassian/Rovo.Symptom: despite having a 90-day refresh token (
offline_accessscope, rotating), the server needed a full interactive re-auth (opencode mcp auth atlassian-rovo-mcp) roughly every 8 hours — i.e. exactly the access token's lifetime, as if the refresh token were never being used at all.Server log (
~/.local/share/opencode/log/opencode.log) shows the pattern clearly — repeated failures every 20-90 min for hours with no refresh attempt or error ever logged in between, just an immediate fall-through toneeds_auth:Root cause appears to be upstream in the MCP TypeScript SDK. Atlassian issues rotating refresh tokens (
"https://id.atlassian.com/atl_token_type":"ROTATING_REFRESH"in the decoded JWT) — each refresh invalidates the old refresh token and issues a new one that must be persisted immediately. The SDK's ownauth()helper had a bug where aprovider.saveTokens()failure during that persistence step was silently swallowed and the client fell through to requesting a brand new authorization — exactly this symptom. Confirmed via the SDK's own changeset description:Fixed upstream in modelcontextprotocol/typescript-sdk#2053, merged 2026-08-18 — but not yet in any published release (latest npm
@modelcontextprotocol/sdkis still1.30.0from 2026-07-27, before the fix), and opencode itself currently pins1.29.0inpackages/opencode/package.json, one minor behind even that.So right now there's no available fix at either layer for OAuth servers with rotating refresh tokens (Atlassian, Keycloak, and per the SDK changeset this is "the OAuth 2.1 default"). Once the SDK cuts a release containing #2053, opencode will also need to bump its
@modelcontextprotocol/sdkdependency past1.29.0/1.30.0to pick it up.rekram1-node commentedon Sep 22, 2026
V2 no longer uses
mcp-auth.json. OAuth tokens, the client registration, and the refresh state for each MCP server are stored as a credential in the local database and written atomically per server, so an in-progress login for one server cannot rewrite or drop another server's tokens. Closing as resolved on V2; if tokens go missing on the current release, please open a new issue with steps to reproduce.