docs/bugs/oauth-reconnection-after-login.md
Fixed in: PR #181 (fix/oauth-reconnection-after-login branch) Fix Date: 2025-12-07
After successful OAuth authentication via browser flow, the server remains in "Disconnected" status instead of automatically connecting. Users must manually restart the server to establish a connection.
After OAuth login completes successfully:
After OAuth login completes:
RetryConnection is called but fails with "OAuth authentication required"The issue was in internal/upstream/core/connection.go:
HasRecentOAuthCompletion() check returned false because it only checks in-memory state (per-process)RetryConnection (internal/upstream/manager.go)Connect() is called which goes through tryOAuthAuth()tryOAuthAuth() checks HasRecentOAuthCompletion() - but this is per-process, so cross-process OAuth (CLI → daemon) wasn't detectedThe fix adds three key improvements to internal/upstream/core/connection.go:
// First check for valid persisted token directly (handles cross-process OAuth)
hasTokenPrecheck, hasRefreshPrecheck, tokenExpiredPrecheck := oauth.HasPersistedToken(c.config.Name, c.config.URL, c.storage)
if hasTokenPrecheck && !tokenExpiredPrecheck {
logger.Info("🔄 Valid OAuth token found in persistent storage - will skip browser flow if OAuth error occurs",
zap.String("server", c.config.Name),
zap.Bool("has_refresh_token", hasRefreshPrecheck))
skipBrowserFlow = true
} else if tokenManager.HasRecentOAuthCompletion(c.config.Name) {
// Also check in-memory completion flag (same-process OAuth)
...
}
if client.IsOAuthAuthorizationRequiredError(lastErr) {
// CRITICAL FIX: If we have a valid persisted token (e.g., from CLI OAuth),
// skip browser flow and return retriable error. The token exists but
// the mcp-go client needs to pick it up on retry.
if skipBrowserFlow {
c.logger.Info("🔄 OAuth authorization error but valid token exists - skipping browser flow",
zap.String("server", c.config.Name),
zap.String("tip", "Token should be used on next connection attempt"))
c.clearOAuthState()
return fmt.Errorf("OAuth token exists in storage, retry connection to use it: %w", lastErr)
}
// ... proceed with browser flow only if no valid token exists
}
The same skipBrowserFlow logic was applied to the SSE OAuth flow to handle SSE-based OAuth servers.
internal/upstream/core/connection.go - Main fix location
mcpproxy auth login --server=<name>Added StateConnecting to the state change notifier so UI shows "Connecting" immediately when reconnection starts:
case types.StateConnecting:
// Notify when connection attempt starts (important for UI feedback after OAuth)
if oldState != types.StateConnecting {
nm.NotifyServerConnecting(serverName)
}
This triggers an SSE event to refresh the UI, showing "Connecting" badge instead of "Disconnected" during reconnection.