Skip to content

Commit cf7e2a7

Browse files
waleedlatif1claude
andcommitted
fix(mcp): stable mutateAsync dep + preserve OAuth connection on no-op upsert
- useMcpOauthPopup: depend on the stable mutateAsync reference instead of the whole mutation object (which changes identity every render and defeats the useCallback memoization). - POST /api/mcp/servers upsert path: only force connectionStatus to 'disconnected' / clear lastConnected for OAuth servers when we actually cleared the OAuth row (URL/credential change or revival). When the upsert is a no-op for OAuth state, the existing tokens stay valid and the server should remain connected — we now leave both columns alone in that case. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b8364ac commit cf7e2a7

2 files changed

Lines changed: 12 additions & 5 deletions

File tree

apps/sim/app/api/mcp/servers/route.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,18 @@ export const POST = withRouteHandler(
197197
timeout: body.timeout || 30000,
198198
retries: body.retries || 3,
199199
enabled: body.enabled !== false,
200-
connectionStatus: resolvedAuthType === 'oauth' ? 'disconnected' : 'connected',
201-
lastConnected: resolvedAuthType === 'oauth' ? null : new Date(),
202200
updatedAt: new Date(),
203201
deletedAt: null,
204202
}
203+
if (resolvedAuthType === 'oauth') {
204+
if (shouldClearOauth) {
205+
updateValues.connectionStatus = 'disconnected'
206+
updateValues.lastConnected = null
207+
}
208+
} else {
209+
updateValues.connectionStatus = 'connected'
210+
updateValues.lastConnected = new Date()
211+
}
205212
if (oauthClientIdProvided) updateValues.oauthClientId = oauthClientId
206213
if (oauthClientSecretProvided) {
207214
updateValues.oauthClientSecret = oauthClientSecretEncrypted

apps/sim/hooks/mcp/use-mcp-oauth-popup.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface UseMcpOauthPopupProps {
1515

1616
export function useMcpOauthPopup({ workspaceId }: UseMcpOauthPopupProps) {
1717
const queryClient = useQueryClient()
18-
const startOauthMutation = useStartMcpOauth()
18+
const { mutateAsync: startOauth } = useStartMcpOauth()
1919

2020
const [connectingServers, setConnectingServers] = useState<Set<string>>(() => new Set())
2121
const popupIntervalsRef = useRef<Map<string, number>>(new Map())
@@ -76,7 +76,7 @@ export function useMcpOauthPopup({ workspaceId }: UseMcpOauthPopupProps) {
7676
})
7777
}
7878
try {
79-
const result = await startOauthMutation.mutateAsync({ serverId, workspaceId })
79+
const result = await startOauth({ serverId, workspaceId })
8080
if (result.status === 'already_authorized') {
8181
clear()
8282
return
@@ -92,7 +92,7 @@ export function useMcpOauthPopup({ workspaceId }: UseMcpOauthPopupProps) {
9292
toast.error(toError(e).message || 'Failed to start authorization')
9393
}
9494
},
95-
[startOauthMutation, workspaceId]
95+
[startOauth, workspaceId]
9696
)
9797

9898
return { connectingServers, startOauthForServer }

0 commit comments

Comments
 (0)