feat(mcp): 'Clear sign-in data' recovery for stuck MCP auth#2189
Open
benjaminshafii wants to merge 1 commit into
Open
feat(mcp): 'Clear sign-in data' recovery for stuck MCP auth#2189benjaminshafii wants to merge 1 commit into
benjaminshafii wants to merge 1 commit into
Conversation
Stale OAuth state (tokens + clientInfo from a broken flow, e.g. PostHog's 'Unable to determine region') can permanently block re-auth, and the only fix was hand-editing ~/.local/share/opencode/mcp-auth.json. Two gaps: - UI: the sign-out action was only rendered when status === connected — hidden in exactly the broken states (failed / needs_auth / needs_client_registration) where users get stuck. Those states now show a 'Clear sign-in data' button next to Sign in, reusing the existing logout confirm flow, with a hint explaining the reset. - Server: DELETE /workspace/:id/mcp/:name/auth depended on the engine being reachable. When the engine call fails (not a 404), the route now falls back to removing the entry from mcp-auth.json directly (mcp-auth-store.ts, mirroring opencode's xdg data-dir resolution). Also fixes the approval/audit path, which pointed at the config dir instead of the engine's data dir.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
2 issues found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/app/src/react-app/domains/settings/pages/mcp-view.tsx">
<violation number="1" location="apps/app/src/react-app/domains/settings/pages/mcp-view.tsx:1133">
P3: New user-facing strings are hardcoded and bypass i18n, causing untranslated text in non-English locales.</violation>
</file>
<file name="apps/server/src/mcp-auth-store.ts">
<violation number="1" location="apps/server/src/mcp-auth-store.ts:24">
P2: MCP auth-store path resolution omits `OPENWORK_DATA_DIR`, so clear-auth can silently report success without deleting the real entry in orchestrator-managed data dirs.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // opencodeDataDirs() in opencode-db.ts. | ||
| function opencodeDataDirs(): string[] { | ||
| const dirs: string[] = []; | ||
| const xdg = process.env.XDG_DATA_HOME?.trim(); |
There was a problem hiding this comment.
P2: MCP auth-store path resolution omits OPENWORK_DATA_DIR, so clear-auth can silently report success without deleting the real entry in orchestrator-managed data dirs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/server/src/mcp-auth-store.ts, line 24:
<comment>MCP auth-store path resolution omits `OPENWORK_DATA_DIR`, so clear-auth can silently report success without deleting the real entry in orchestrator-managed data dirs.</comment>
<file context>
@@ -0,0 +1,61 @@
+// opencodeDataDirs() in opencode-db.ts.
+function opencodeDataDirs(): string[] {
+ const dirs: string[] = [];
+ const xdg = process.env.XDG_DATA_HOME?.trim();
+ if (xdg) dirs.push(join(xdg, "opencode"));
+ dirs.push(join(homedir(), ".local", "share", "opencode"));
</file context>
| disabled={props.busy || props.logoutBusy} | ||
| onClick={() => props.onRequestLogout(props.entry.name)} | ||
| > | ||
| {clearingThis ? t("mcp.logout_working") : "Clear sign-in data"} |
There was a problem hiding this comment.
P3: New user-facing strings are hardcoded and bypass i18n, causing untranslated text in non-English locales.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/react-app/domains/settings/pages/mcp-view.tsx, line 1133:
<comment>New user-facing strings are hardcoded and bypass i18n, causing untranslated text in non-English locales.</comment>
<file context>
@@ -1110,15 +1110,39 @@ function McpConfiguredServerDetails(props: Parameters<typeof McpConfiguredServer
+ disabled={props.busy || props.logoutBusy}
+ onClick={() => props.onRequestLogout(props.entry.name)}
+ >
+ {clearingThis ? t("mcp.logout_working") : "Clear sign-in data"}
+ </Button>
+ ) : null}
</file context>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Stale MCP OAuth state (tokens + clientInfo + oauthState from a broken flow) can permanently block re-auth. Real case: PostHog's OAuth proxy returns
Unable to determine regionforever once the stored client registration's region mapping expires — retrying Sign in reuses the poisoned client and fails every time. Today the only fix is hand-editing~/.local/share/opencode/mcp-auth.json, which is not something we can walk a customer through.Fix (two gaps)
1. UI gap — the recovery action was hidden exactly when needed. The sign-out button only rendered when
status === "connected". The broken states (failed,needs_auth,needs_client_registration) now show a Clear sign-in data button next to Sign in, reusing the existing logout confirm flow, with a hint: "Stuck signing in? Clear sign-in data to reset the saved OAuth tokens and app registration, then sign in again."2. Server gap — logout depended on the engine being reachable.
DELETE /workspace/:id/mcp/:name/authnow falls back to removing the entry frommcp-auth.jsondirectly when the engine call fails for any reason other than 404 (engine down, old engine, broken state). Newmcp-auth-store.tsmirrors opencode's xdg data-dir resolution; the write is idempotent and only touches the named entry. Also fixes the approval/audit path string, which pointed at~/.config/opencode/instead of the engine's actual data dir (~/.local/share/opencode/).Support flow this enables: "Open the extension → Clear sign-in data → Sign in again" — works even if the engine itself is wedged.
Tests
bun test src/mcp-auth-store.e2e.test.ts— 2 pass: clears the stale entry through the full HTTP route with an unreachable engine, leaves other entries untouched; second delete is idempotentbun test(apps/server) — 413 pass / 7 fail (same 7 pre-existing ondev; the real-engine OAuth e2e flaked once under load at 92s but passes in isolation in 1.6s)pnpm typecheck— app clean; server only the pre-existingSessionMessagesResponse2errorNo video: UI change is a button + hint in an existing row; to reproduce, break an MCP's auth (e.g. PostHog with a stale client) and check the failed/needs-auth state now offers Clear sign-in data.