Description
Description
Description
When a remote MCP server uses OAuth authentication (e.g., PostHog at https://mcp.posthog.com/mcp), OpenCode appends an extra closing brace } to ~/.local/share/opencode/mcp-auth.json every time it refreshes tokens. This makes the file invalid JSON, which prevents ALL remote MCP servers from connecting on subsequent startups.
Steps to reproduce
- Add a remote MCP that requires OAuth to
opencode.json:"PostHog": { "enabled": true, "type": "remote", "url": "https://mcp.posthog.com/mcp" }
- Start OpenCode — OAuth flow triggers, browser authorization completes.
- Check
~/.local/share/opencode/mcp-auth.json— valid JSON, PostHog tokens saved. - Restart OpenCode.
- Check
mcp-auth.jsonagain — an extra}has been appended at the end. - All remote MCP servers now fail to connect (SSE parse error).
Expected behavior
mcp-auth.json remains valid JSON after token refresh.
Actual behavior
Every restart appends one extra } to the file. After N restarts, the file has N extra closing braces.
Evidence
$ python3 -c "import json; json.load(open('$HOME/.local/share/opencode/mcp-auth.json'))"
JSONDecodeError: Extra data: line 18 column 1 (char 3737)
$ tail -c 20 ~/.local/share/opencode/mcp-auth.json
}
}
}
The file has 3 } at the end where it should have 2. One extra } per restart.
Impact
- All remote MCP servers (context7, langfuse-docs, etc) stop connecting.
- No error message in the UI — they just appear as "disabled" and cannot be enabled.
- The only visible error is
SSE error: Unexpected non-whitespace character after JSON at position Nin the Toggle MCPs Screen( /mcp) in OpenCode Desktop.
Workaround
After each restart, trim the file to valid JSON:
python3 -c "
import json, os
p = os.path.expanduser('~/.local/share/opencode/mcp-auth.json')
with open(p) as f: c = f.read()
for i in range(len(c), 0, -1):
try:
json.loads(c[:i])
open(p, 'w').write(c[:i])
break
except: continue
"Environment
- OpenCode version: 1.15.12
- OS: macOS 26.5 (arm64)
- Node (system): v26.0.0
- Node (OpenCode bundled): v24.14.1
Plugins
No response
OpenCode version
1.15.12
Steps to reproduce
- Add a remote MCP that requires OAuth to opencode.json:
"PostHog": { "enabled": true, "type": "remote", "url": "https://mcp.posthog.com/mcp" } - Start OpenCode — OAuth flow triggers, browser authorization completes.
- Check ~/.local/share/opencode/mcp-auth.json — valid JSON, PostHog tokens saved.
- Restart OpenCode.
- Check mcp-auth.json again — an extra } has been appended at the end.
- All remote MCP servers now fail to connect (SSE parse error).
Expected: mcp-auth.json remains valid JSON after token refresh.
Actual: Every restart appends one extra } to the file.
Environment: OpenCode 1.15.12, macOS 26.5 (arm64), Node v26.0.0 (bundled v24.14.1)
Screenshot and/or share link
No response
Operating System
macOS 26.5 (arm64)
Terminal
No response
Activity
github-actions commentedon May 28, 2026
This issue might be a duplicate of existing issues. Please check:
mcp-auth.jsonbecoming corrupted with JSON parse errors in an OAuth remote MCP setup. The root cause may differ (token expiry vs. extra}appended on token refresh), but the symptom and affected file are the same.fix(opencode): serialize mcp-auth.json writes to prevent concurrent c…
JunJieLiu51520 commentedon May 29, 2026
Hi @nexxeln 👋 — I've opened a PR that fixes the concurrent write race condition using
Effect.Semaphore(1)to serialiseMcpAuth.set()andremove(). Would you be able to take a look when you have a moment?PR: #29820
frankxai commentedon Aug 6, 2026
A distinct corruption shape reproduced on Windows with OpenCode 1.14.48. This is older than current, so I am not claiming it reproduces on the latest release, but it strengthens the case for parse-failure recovery and atomic/truncating writes.
Sanitized evidence:
~/.local/share/opencode/mcp-auth.json: 169 bytesJSON Parse error: Unrecognized token '\u0000'McpAuth.Entryshapeopencode --pure mcp listfails before repair, so external plugins are not causalThe shared read path is
McpAuth.all()→AppFileSystem.readJson()→JSON.parse(). The parse failure escaped as a fatal Effect defect instead of a recoverable bad-store diagnostic.A targeted local repair preserved a backup, atomically replaced the file with its already-valid 153-byte prefix, and retained the existing OAuth client metadata. Afterward:
opencode --pure mcp listexited successfully and listed the connected serverUseful regression coverage would include valid JSON plus trailing NULs, malformed-store recovery from
McpAuth.all(), and a shorter-over-longer write test asserting the exact new file length. Deleting all OpenCode state or reinstalling was not necessary.