(
event.preventDefault();
toggleServerSelection(serverName);
}}
+ disabled={isServerInitializing}
className={cn(
'flex items-center gap-2 rounded-lg px-2 py-1.5 text-text-primary hover:cursor-pointer',
'scroll-m-1 outline-none transition-colors',
'hover:bg-black/[0.075] dark:hover:bg-white/10',
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
'w-full min-w-0 justify-between text-sm',
+ isServerInitializing &&
+ 'opacity-50 hover:bg-transparent dark:hover:bg-transparent',
)}
>
diff --git a/client/src/components/MCP/ServerInitializationSection.tsx b/client/src/components/MCP/ServerInitializationSection.tsx
index 2113a9f84..0623ba1a2 100644
--- a/client/src/components/MCP/ServerInitializationSection.tsx
+++ b/client/src/components/MCP/ServerInitializationSection.tsx
@@ -34,7 +34,7 @@ export default function ServerInitializationSection({
const serverOAuthUrl = getOAuthUrl(serverName);
const handleInitializeClick = useCallback(() => {
- initializeServer(serverName);
+ initializeServer(serverName, false);
}, [initializeServer, serverName]);
const handleCancelClick = useCallback(() => {
diff --git a/client/src/hooks/MCP/useMCPServerManager.ts b/client/src/hooks/MCP/useMCPServerManager.ts
index 71ffa471b..b42854545 100644
--- a/client/src/hooks/MCP/useMCPServerManager.ts
+++ b/client/src/hooks/MCP/useMCPServerManager.ts
@@ -171,6 +171,7 @@ export function useMCPServerManager() {
message: localize('com_ui_mcp_oauth_timeout', { 0: serverName }),
status: 'error',
});
+ clearInterval(pollInterval);
cleanupServerState(serverName);
return;
}
@@ -180,10 +181,15 @@ export function useMCPServerManager() {
message: localize('com_ui_mcp_init_failed'),
status: 'error',
});
+ clearInterval(pollInterval);
cleanupServerState(serverName);
+ return;
}
} catch (error) {
console.error(`[MCP Manager] Error polling server ${serverName}:`, error);
+ clearInterval(pollInterval);
+ cleanupServerState(serverName);
+ return;
}
}, 3500);
@@ -201,7 +207,7 @@ export function useMCPServerManager() {
);
const initializeServer = useCallback(
- async (serverName: string) => {
+ async (serverName: string, autoOpenOAuth: boolean = true) => {
updateServerState(serverName, { isInitializing: true });
try {
@@ -216,7 +222,9 @@ export function useMCPServerManager() {
isInitializing: true,
});
- window.open(response.oauthUrl, '_blank', 'noopener,noreferrer');
+ if (autoOpenOAuth) {
+ window.open(response.oauthUrl, '_blank', 'noopener,noreferrer');
+ }
startServerPolling(serverName);
} else {
@@ -265,13 +273,25 @@ export function useMCPServerManager() {
const cancelOAuthFlow = useCallback(
(serverName: string) => {
- queryClient.invalidateQueries([QueryKeys.mcpConnectionStatus]);
- cleanupServerState(serverName);
- cancelOAuthMutation.mutate(serverName);
+ // Call backend cancellation first, then clean up frontend state on success
+ cancelOAuthMutation.mutate(serverName, {
+ onSuccess: () => {
+ // Only clean up frontend state after backend confirms cancellation
+ cleanupServerState(serverName);
+ queryClient.invalidateQueries([QueryKeys.mcpConnectionStatus]);
- showToast({
- message: localize('com_ui_mcp_oauth_cancelled', { 0: serverName }),
- status: 'warning',
+ showToast({
+ message: localize('com_ui_mcp_oauth_cancelled', { 0: serverName }),
+ status: 'warning',
+ });
+ },
+ onError: (error) => {
+ console.error(`[MCP Manager] Failed to cancel OAuth for ${serverName}:`, error);
+ showToast({
+ message: localize('com_ui_mcp_init_failed', { 0: serverName }),
+ status: 'error',
+ });
+ },
});
},
[queryClient, cleanupServerState, showToast, localize, cancelOAuthMutation],
@@ -309,6 +329,10 @@ export function useMCPServerManager() {
const disconnectedServers: string[] = [];
serverNames.forEach((serverName) => {
+ if (isInitializing(serverName)) {
+ return;
+ }
+
const serverStatus = connectionStatus[serverName];
if (serverStatus?.connectionState === 'connected') {
connectedServers.push(serverName);
@@ -323,11 +347,15 @@ export function useMCPServerManager() {
initializeServer(serverName);
});
},
- [connectionStatus, setMCPValues, initializeServer],
+ [connectionStatus, setMCPValues, initializeServer, isInitializing],
);
const toggleServerSelection = useCallback(
(serverName: string) => {
+ if (isInitializing(serverName)) {
+ return;
+ }
+
const currentValues = mcpValues ?? [];
const isCurrentlySelected = currentValues.includes(serverName);
@@ -343,7 +371,7 @@ export function useMCPServerManager() {
}
}
},
- [mcpValues, setMCPValues, connectionStatus, initializeServer],
+ [mcpValues, setMCPValues, connectionStatus, initializeServer, isInitializing],
);
const handleConfigSave = useCallback(