From 1f4d3c3e7741c6787b06e5482c24cd52d8122477 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Wed, 6 Aug 2025 15:24:59 -0500 Subject: [PATCH] fix: resolve MCP selector issues and simplify implementation - Fixed useEffect to properly detect MCP object format { mcp: { included: [...] } } - Fixed empty selection behavior to enable all MCP servers instead of disabling MCP - Removed tuple format handling since this feature hasn't been released yet - Simplified code to only handle the new object format for MCP configuration - Removed unused GroupOptions import When no specific servers are selected, MCP is added as a string (enables all servers). When specific servers are selected, MCP is added as an object with the included list. This ensures the MCP selector properly loads configurations and maintains the expected behavior where empty selection means all servers are enabled. --- src/core/prompts/sections/mcp-servers.ts | 30 ++++------------ .../src/components/modes/McpSelector.tsx | 36 ++++++++++--------- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/core/prompts/sections/mcp-servers.ts b/src/core/prompts/sections/mcp-servers.ts index 3b2f15e018..f3d660f6b4 100644 --- a/src/core/prompts/sections/mcp-servers.ts +++ b/src/core/prompts/sections/mcp-servers.ts @@ -52,36 +52,20 @@ export async function getMcpServersSection( let mcpIncludedList: string[] | undefined if (currentMode) { - // Find MCP group configuration + // Find MCP group configuration - object format: { mcp: { included: [...] } } const mcpGroup = currentMode.groups.find((group: GroupEntry) => { - // Handle tuple format: ["mcp", { mcp: { included: [...] } }] - if (Array.isArray(group) && group.length === 2 && group[0] === "mcp") { - return true - } - // Handle direct object format: { mcp: { included: [...] } } if (typeof group === "object" && !Array.isArray(group) && "mcp" in group) { return true } return getGroupName(group) === "mcp" }) - // Extract mcpIncludedList based on the format - if (mcpGroup) { - let mcpOptions: { mcp?: { included?: unknown[] } } | undefined - - if (Array.isArray(mcpGroup) && mcpGroup.length === 2) { - // Tuple format - mcpOptions = mcpGroup[1] as { mcp?: { included?: unknown[] } } - } else if (typeof mcpGroup === "object" && !Array.isArray(mcpGroup) && "mcp" in mcpGroup) { - // Direct object format - mcpOptions = mcpGroup as { mcp?: { included?: unknown[] } } - } - - if (mcpOptions) { - mcpIncludedList = Array.isArray(mcpOptions.mcp?.included) - ? mcpOptions.mcp.included.filter((item: unknown): item is string => typeof item === "string") - : undefined - } + // Extract mcpIncludedList from the MCP configuration + if (mcpGroup && typeof mcpGroup === "object" && !Array.isArray(mcpGroup) && "mcp" in mcpGroup) { + const mcpOptions = mcpGroup as { mcp?: { included?: unknown[] } } + mcpIncludedList = Array.isArray(mcpOptions.mcp?.included) + ? mcpOptions.mcp.included.filter((item: unknown): item is string => typeof item === "string") + : undefined } } diff --git a/webview-ui/src/components/modes/McpSelector.tsx b/webview-ui/src/components/modes/McpSelector.tsx index a2a1b57e78..eef9459442 100644 --- a/webview-ui/src/components/modes/McpSelector.tsx +++ b/webview-ui/src/components/modes/McpSelector.tsx @@ -14,7 +14,7 @@ import { CommandItem, } from "@src/components/ui" import { useAppTranslation } from "@src/i18n/TranslationContext" -import { ModeConfig, GroupEntry, GroupOptions } from "@roo-code/types" +import { ModeConfig, GroupEntry } from "@roo-code/types" import { McpServer } from "@roo/mcp" interface McpSelectorProps { @@ -55,42 +55,46 @@ const McpSelector: React.FC = ({ return } - const mcpGroupArr = currentMode.groups?.find( - (g: GroupEntry): g is ["mcp", GroupOptions] => Array.isArray(g) && g.length === 2 && g[0] === "mcp", - ) + // Find MCP group - object format: { mcp: { included: [...] } } + const mcpGroup = currentMode.groups?.find((g: GroupEntry) => { + return typeof g === "object" && !Array.isArray(g) && "mcp" in g + }) - const rawGroupOptions: GroupOptions | undefined = mcpGroupArr ? mcpGroupArr[1] : undefined + let included: string[] = [] - const included = Array.isArray(rawGroupOptions?.mcp?.included) - ? (rawGroupOptions.mcp.included.filter((item) => typeof item === "string") as string[]) - : [] + if (mcpGroup && typeof mcpGroup === "object" && !Array.isArray(mcpGroup) && "mcp" in mcpGroup) { + const mcpOptions = mcpGroup as { mcp?: { included?: unknown[] } } + included = Array.isArray(mcpOptions.mcp?.included) + ? (mcpOptions.mcp.included.filter((item) => typeof item === "string") as string[]) + : [] + } // Sync MCP settings when mode changes setMcpIncludedList(included) }, [currentMode]) // Handle save function updateMcpGroupOptions(groups: GroupEntry[] = [], _group: string, mcpIncludedList: string[]): GroupEntry[] { - // Filter out any existing "mcp" entries (both string and object forms) + // Filter out any existing "mcp" entries (string or object forms) const filteredGroups = groups.filter((g) => { if (typeof g === "string") { return g !== "mcp" } - if (Array.isArray(g) && g[0] === "mcp") { - return false - } if (typeof g === "object" && g !== null && !Array.isArray(g) && "mcp" in g) { return false } return true }) - // Add the new MCP configuration if there are selected servers + // Always add MCP back if it's enabled + // If mcpIncludedList is empty, it means all servers are enabled (default behavior) + // If mcpIncludedList has items, only those servers are enabled if (mcpIncludedList.length > 0) { - // Directly add the mcp object without wrapping in an array + // Specific servers selected return [...filteredGroups, { mcp: { included: mcpIncludedList } }] as GroupEntry[] + } else { + // No specific servers selected - enable all (just add "mcp" string) + return [...filteredGroups, "mcp"] as GroupEntry[] } - - return filteredGroups as GroupEntry[] } // Handle save