From aecd3fddd954526044c04b6799807e9f0e45c6a1 Mon Sep 17 00:00:00 2001 From: Aditya Kulraj Date: Tue, 24 Mar 2026 12:52:46 +0530 Subject: [PATCH 1/2] Fix MCP status drift across auth/reload/restart flows --- src/core/runtime/hooks/useAgentRuntime.ts | 46 +++++++++--------- .../workspace/hooks/useWorkspaceSessions.ts | 48 +++++++++---------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/core/runtime/hooks/useAgentRuntime.ts b/src/core/runtime/hooks/useAgentRuntime.ts index e210aa0..18c9015 100644 --- a/src/core/runtime/hooks/useAgentRuntime.ts +++ b/src/core/runtime/hooks/useAgentRuntime.ts @@ -69,6 +69,15 @@ export function useOAgent({ const [contextUsage, setContextUsage] = useState(null); const [isCompacting, setIsCompacting] = useState(false); const [mcpServerStatuses, setMcpServerStatuses] = useState([]); + const mapMcpStatuses = useCallback( + (servers: Array<{ name: string; status: string; error?: string }> = []): McpServerStatus[] => + servers.map((s) => ({ + name: s.name, + status: toMcpStatusState(s.status), + ...(s.error ? { error: s.error } : {}), + })), + [], + ); const buffer = useRef(new StreamingBuffer()); const parentToolMap = useRef(new Map()); @@ -256,22 +265,15 @@ export function useOAgent({ version: init.claude_code_version, permissionMode: init.permissionMode, }); - if (init.mcp_servers?.length) { - setMcpServerStatuses(init.mcp_servers.map((s) => ({ - name: s.name, - status: toMcpStatusState(s.status), - }))); - // Auto-refresh detailed MCP status after a short delay (auth flows may still be in progress) - const sid = sessionIdRef.current; - if (sid) { - setTimeout(() => { - window.clientCore.mcpStatus(sid).then((result) => { - if (result.servers?.length) { - setMcpServerStatuses(result.servers as McpServerStatus[]); - } - }).catch(() => { /* session may have been stopped */ }); - }, 3000); - } + setMcpServerStatuses(mapMcpStatuses(init.mcp_servers ?? [])); + // Auto-refresh detailed MCP status after a short delay (auth flows may still be in progress) + const sid = sessionIdRef.current; + if (sid) { + setTimeout(() => { + window.clientCore.mcpStatus(sid).then((result) => { + setMcpServerStatuses(mapMcpStatuses(result.servers ?? [])); + }).catch(() => { /* session may have been stopped */ }); + }, 3000); } setIsConnected(true); setIsProcessing(true); @@ -587,16 +589,14 @@ export function useOAgent({ // After auth completes, refresh MCP server statuses if (!authEvt.isAuthenticating && sessionIdRef.current) { window.clientCore.mcpStatus(sessionIdRef.current).then((result) => { - if (result.servers?.length) { - setMcpServerStatuses(result.servers as McpServerStatus[]); - } + setMcpServerStatuses(mapMcpStatuses(result.servers ?? [])); }).catch(() => { /* session may have been stopped */ }); } break; } } }, - [resetStreaming, scheduleFlush, flushNow, handleSubagentEvent], + [resetStreaming, scheduleFlush, flushNow, handleSubagentEvent, mapMcpStatuses], ); const send = useCallback( @@ -751,10 +751,8 @@ export function useOAgent({ const refreshMcpStatus = useCallback(async () => { if (!sessionIdRef.current) return; const result = await window.clientCore.mcpStatus(sessionIdRef.current); - if (result.servers?.length) { - setMcpServerStatuses(result.servers as McpServerStatus[]); - } - }, []); + setMcpServerStatuses(mapMcpStatuses(result.servers ?? [])); + }, [mapMcpStatuses]); const reconnectMcpServer = useCallback(async (serverName: string) => { if (!sessionIdRef.current) return; diff --git a/src/core/workspace/hooks/useWorkspaceSessions.ts b/src/core/workspace/hooks/useWorkspaceSessions.ts index 38a1b6a..9b1a744 100644 --- a/src/core/workspace/hooks/useWorkspaceSessions.ts +++ b/src/core/workspace/hooks/useWorkspaceSessions.ts @@ -38,6 +38,15 @@ export function useSessionManager(projects: Project[], settings: Settings) { const [draftMcpStatuses, setDraftMcpStatuses] = useState([]); const draftMcpStatusesRef = useRef([]); draftMcpStatusesRef.current = draftMcpStatuses; + const mapMcpStatuses = useCallback( + (servers: Array<{ name: string; status: string; error?: string }> = []): McpServerStatus[] => + servers.map((s) => ({ + name: s.name, + status: toMcpStatusState(s.status), + ...(s.error ? { error: s.error } : {}), + })), + [], + ); // OAP agent tracking — needed to restart the session with updated MCP servers const oapAgentIdRef = useRef(null); // OAP-side session ID — persisted so we can call session/load on revival after restart @@ -193,11 +202,8 @@ export function useSessionManager(projects: Project[], settings: Settings) { // couldn't match it (preStartedSessionIdRef was still null). Query MCP // status directly now that the session is initialized. const statusResult = await window.clientCore.mcpStatus(result.sessionId); - if (statusResult.servers?.length && preStartedSessionIdRef.current === result.sessionId) { - setDraftMcpStatuses(statusResult.servers.map(s => ({ - name: s.name, - status: toMcpStatusState(s.status), - }))); + if (preStartedSessionIdRef.current === result.sessionId) { + setDraftMcpStatuses(mapMcpStatuses(statusResult.servers ?? [])); } } else { // Draft was abandoned before eager start completed @@ -351,12 +357,7 @@ export function useSessionManager(projects: Project[], settings: Settings) { backgroundStoreRef.current.handleEvent(event); if (event.type === "system" && "subtype" in event && event.subtype === "init") { const init = event as SystemInitEvent; - if (init.mcp_servers?.length) { - setDraftMcpStatuses(init.mcp_servers.map(s => ({ - name: s.name, - status: toMcpStatusState(s.status), - }))); - } + setDraftMcpStatuses(mapMcpStatuses(init.mcp_servers ?? [])); } return; } @@ -987,6 +988,7 @@ export function useSessionManager(projects: Project[], settings: Settings) { setAcpMcpStatuses((result.mcpStatuses ?? []).map(s => ({ name: s.name, status: toMcpStatusState(s.status), + ...(s.error ? { error: s.error } : {}), }))); setInitialMessages(messagesRef.current); setInitialMeta({ isProcessing: false, isConnected: true, sessionInfo: null, totalCost: totalCostRef.current }); @@ -1258,9 +1260,13 @@ export function useSessionManager(projects: Project[], settings: Settings) { compact: engine.compact, oapConfigOptions: oap.configOptions, setOAPConfig: oap.setConfig, - mcpServerStatuses: isOAP - ? (oapMcpStatuses.length > 0 ? oapMcpStatuses : draftMcpStatuses) - : (agent.mcpServerStatuses.length > 0 ? agent.mcpServerStatuses : draftMcpStatuses), + mcpServerStatuses: isDraft + ? ( + isOAP + ? (oapMcpStatuses.length > 0 ? oapMcpStatuses : draftMcpStatuses) + : (agent.mcpServerStatuses.length > 0 ? agent.mcpServerStatuses : draftMcpStatuses) + ) + : (isOAP ? oapMcpStatuses : agent.mcpServerStatuses), mcpStatusPreliminary: isDraft && draftMcpStatuses.length > 0 && ( isOAP ? oapMcpStatuses.length === 0 : agent.mcpServerStatuses.length === 0 ), @@ -1269,12 +1275,7 @@ export function useSessionManager(projects: Project[], settings: Settings) { : (preStartedSessionId && isDraft) ? (async () => { const result = await window.clientCore.mcpStatus(preStartedSessionId); - if (result.servers?.length) { - setDraftMcpStatuses(result.servers.map(s => ({ - name: s.name, - status: toMcpStatusState(s.status), - }))); - } + setDraftMcpStatuses(mapMcpStatuses(result.servers ?? [])); }) : agent.refreshMcpStatus, reconnectMcpServer: isOAP @@ -1298,12 +1299,7 @@ export function useSessionManager(projects: Project[], settings: Settings) { await new Promise(r => setTimeout(r, 3000)); } const statusResult = await window.clientCore.mcpStatus(preStartedSessionId); - if (statusResult.servers?.length) { - setDraftMcpStatuses(statusResult.servers.map(s => ({ - name: s.name, - status: toMcpStatusState(s.status), - }))); - } + setDraftMcpStatuses(mapMcpStatuses(statusResult.servers ?? [])); }) : agent.reconnectMcpServer, restartWithMcpServers: isOAP From 943967d5a30fdb037d84478d0a5180afb5306999 Mon Sep 17 00:00:00 2001 From: Aditya Kulraj Date: Tue, 24 Mar 2026 13:00:56 +0530 Subject: [PATCH 2/2] Fix OAP MCP status mapping type error --- src/core/workspace/hooks/useWorkspaceSessions.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/workspace/hooks/useWorkspaceSessions.ts b/src/core/workspace/hooks/useWorkspaceSessions.ts index 9b1a744..4bce1c3 100644 --- a/src/core/workspace/hooks/useWorkspaceSessions.ts +++ b/src/core/workspace/hooks/useWorkspaceSessions.ts @@ -985,11 +985,7 @@ export function useSessionManager(projects: Project[], settings: Settings) { ? { ...s, id: newId, agentSessionId: result.agentSessionId ?? s.agentSessionId } : s, )); - setAcpMcpStatuses((result.mcpStatuses ?? []).map(s => ({ - name: s.name, - status: toMcpStatusState(s.status), - ...(s.error ? { error: s.error } : {}), - }))); + setAcpMcpStatuses(mapMcpStatuses(result.mcpStatuses ?? [])); setInitialMessages(messagesRef.current); setInitialMeta({ isProcessing: false, isConnected: true, sessionInfo: null, totalCost: totalCostRef.current }); if (result.configOptions?.length) setInitialConfigOptions(result.configOptions);