fix(mcp): isolate OAuth ownership from background connects and harden observability - #1292
Conversation
… observability Background supervisor auto-connects shared the PendingOAuth registry with interactive `mcp auth` flows: a queued 401 connect for the same server disposed the interactive pending entry, rejecting the callback wait with "Authorization cancelled" and failing authentication with no log trail. - McpAuth: drop the never-invalidated in-process cache so CLI-written tokens are visible to a running server without restart. - McpOAuthProvider: add background mode; probe connects no longer write PKCE state or tokens into the shared auth store. - supervisor: background 401s never register PendingOAuth entries; servers enter NeedsAuth and a 30s local check reconnects once credentials exist, with zero network probes while unauthenticated. - observability: cancelPending logs WARN with reason, callback port conflicts name SYNERGY_OAUTH_CALLBACK_PORT, CLI auth failures write to the file log. - tests: race regression (background 401 during interactive wait), live token visibility, NeedsAuth auto-recovery, port-conflict error. Co-authored-by: synergy-agent <299070056+synergy-agent@users.noreply.github.com>
The supervisor's background connect path now transitions a server to needs_auth without creating a PendingOAuth entry; only the interactive startAuth flow registers one. Update the declarative plugin OAuth integration assertion to match. Co-authored-by: synergy-agent <299070056+synergy-agent@users.noreply.github.com>
|
Verification is complete. Here is my review. Review: #1292 — fix(mcp): isolate OAuth ownership from background connects and harden observabilitySummaryThe fix is sound and the reported race is genuinely closed: background connects no longer touch Verification (run in this checkout)
FindingsP2 — Background mode breaks refresh-token renewal for expired-but-refreshable tokens (regression vs. pre-PR behavior).
Pre-PR, background connects used the default interactive provider and persisted refreshed tokens, so this scenario self-healed. The new suite doesn't cover it (the fixture returns Smallest fix: in background mode, persist P3 — P3 — Notes
Synergy: review complete — 0 blocking, 1 should-fix (background refresh renewal), 2 suggestions |
…auth error Address review findings on PR #1292: - Background saveTokens now persists when a stored entry exists, so SDK refresh-token renewal survives instead of being discarded (probe-only connects still never write shared state). - NeedsAuth recovery treats expired-but-refreshable entries as reconnectable, restoring self-healing for long-running daemons. - needs_auth status now carries the actionable error (mirrors needs_client_registration); SDK/OpenAPI regenerated to match. - Remove the dead invalidateCache no-op shim and its test call sites. - Fixture supports refresh_token grant; new regression tests cover token persistence and expired-refreshable recovery. - Declarative plugin test now asserts background 401 no longer creates a PendingOAuth entry (was stale pre-PR behavior). Co-authored-by: synergy-agent <299070056+synergy-agent@users.noreply.github.com>
Summary
Fixes
synergy mcp auth <server>failing withAuthentication failed/Authorization cancelledimmediately after opening the browser for OAuth remote servers (reproduced with Notion).Root cause: background supervisor auto-connects (default
startup: "eager") shared the process-levelPendingOAuthregistry with interactive OAuth flows. A queued background connect for the same server reaching 401 disposed the interactive pending entry, which rejected the callback wait (cancelPending→ "Authorization cancelled"). The CLI then exited before the supervisor logged anything, making the failure silent.Changes
McpAuth— removed the never-invalidated in-process cache; reads go to disk every time, so CLI-authenticated tokens are visible to a running server without restart.McpOAuthProvider— addedbackgroundmode; background probe connects no longer write PKCE state/tokens into the shared auth store.supervisor— background 401s no longer touchPendingOAuth; servers enterNeedsAuthand a 30s local check reconnects once credentials exist (zero network probes while unauthenticated, interactive flow skipped while pending).cancelPendinglogs WARN with reason; callback-port conflicts nameSYNERGY_OAUTH_CALLBACK_PORT; CLIauthfailures write to the file log.Verification
E2E (isolated home):
mcp authwith the callback port occupied prints the actionable error and writesmcp auth failedto the file log.Notes
authMcpformat changes.docs/decisions/implemented/bug-fix/2026-08-31-mcp-oauth-ownership-isolation.md.