From 0983e4f2a022d9f12b49fa00f5f8600655ec4c60 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Wed, 4 Mar 2026 13:34:05 +0530 Subject: [PATCH] Fix MCP server URL and tools management --- .../components/mcp_tools/mcp_server_edit.tsx | 27 ++++++++-- .../mcp_tools/mcp_tool_configuration.tsx | 54 ++++++++++++------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx index 4209d8bf111..cf2eafd43f5 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx @@ -51,6 +51,17 @@ const MCPServerEdit: React.FC = ({ const [oauthAccessToken, setOauthAccessToken] = useState(null); + // Watch form fields that affect tool fetching + const currentUrl = Form.useWatch("url", form); + const currentSpecPath = Form.useWatch("spec_path", form); + const currentServerName = Form.useWatch("server_name", form); + const currentAuthType = Form.useWatch("auth_type", form); + const currentStaticHeaders = Form.useWatch("static_headers", form); + const currentCredentials = Form.useWatch("credentials", form); + const currentAuthorizationUrl = Form.useWatch("authorization_url", form); + const currentTokenUrl = Form.useWatch("token_url", form); + const currentRegistrationUrl = Form.useWatch("registration_url", form); + const persistEditUiState = () => { if (typeof window === "undefined") { return; @@ -879,12 +890,18 @@ const MCPServerEdit: React.FC = ({ oauthAccessToken={oauthAccessToken} formValues={{ server_id: mcpServer.server_id, - server_name: mcpServer.server_name, - url: mcpServer.url, - transport: mcpServer.transport, - auth_type: mcpServer.auth_type, + server_name: currentServerName ?? mcpServer.server_name, + url: currentUrl ?? mcpServer.url, + spec_path: currentSpecPath ?? mcpServer.spec_path, + transport: transportType ?? mcpServer.transport, + auth_type: currentAuthType ?? mcpServer.auth_type, mcp_info: mcpServer.mcp_info, - oauth_flow_type: mcpServer.token_url ? OAUTH_FLOW.M2M : OAUTH_FLOW.INTERACTIVE, + oauth_flow_type: (currentTokenUrl ?? mcpServer.token_url) ? OAUTH_FLOW.M2M : OAUTH_FLOW.INTERACTIVE, + static_headers: currentStaticHeaders ?? mcpServer.static_headers, + credentials: currentCredentials, + authorization_url: currentAuthorizationUrl ?? mcpServer.authorization_url, + token_url: currentTokenUrl ?? mcpServer.token_url, + registration_url: currentRegistrationUrl ?? mcpServer.registration_url, }} allowedTools={allowedTools} existingAllowedTools={mcpServer.allowed_tools || null} diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_tool_configuration.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_tool_configuration.tsx index 404172623b9..25c20dd0746 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_tool_configuration.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_tool_configuration.tsx @@ -21,8 +21,9 @@ const MCPToolConfiguration: React.FC = ({ existingAllowedTools, onAllowedToolsChange, }) => { - const previousToolsLengthRef = useRef(0); + const previousToolsRef = useRef([]); const [toolSearchTerm, setToolSearchTerm] = useState(""); + const hasInitializedRef = useRef(false); const { tools, isLoadingTools, toolsError, canFetchTools } = useTestMCPConnection({ accessToken, @@ -40,28 +41,43 @@ const MCPToolConfiguration: React.FC = ({ ); }); - // Auto-select tools when tools are first loaded + // Auto-select tools when tools are first loaded or when tools list changes useEffect(() => { - // Only auto-select if: - // 1. We have tools - // 2. Tools length changed (new tools loaded) - // 3. No tools are currently selected (initial state) - if (tools.length > 0 && tools.length !== previousToolsLengthRef.current && allowedTools.length === 0) { - if (existingAllowedTools && existingAllowedTools.length > 0) { - // If we have existing allowed tools, use those as the initial selection - // Filter to only include tools that are actually available from the server - const availableToolNames = tools.map((tool) => tool.name); - const validExistingTools = existingAllowedTools.filter((toolName) => availableToolNames.includes(toolName)); - onAllowedToolsChange(validExistingTools); + // Check if the tools list has actually changed by comparing tool names + const currentToolNames = tools.map((tool) => tool.name).sort().join(","); + const previousToolNames = previousToolsRef.current.map((tool) => tool.name).sort().join(","); + const toolsListChanged = currentToolNames !== previousToolNames; + + if (tools.length > 0 && toolsListChanged) { + const availableToolNames = tools.map((tool) => tool.name); + + // On initial load (first time tools are fetched) + if (!hasInitializedRef.current) { + hasInitializedRef.current = true; + + if (existingAllowedTools && existingAllowedTools.length > 0) { + // Edit mode: pre-select tools that match existing allowed tools + const validExistingTools = existingAllowedTools.filter((toolName) => availableToolNames.includes(toolName)); + onAllowedToolsChange(validExistingTools); + } else { + // Create mode: auto-select all tools + onAllowedToolsChange(availableToolNames); + } } else { - // If no existing allowed tools, auto-select all tools (create mode) - const allToolNames = tools.map((tool) => tool.name); - onAllowedToolsChange(allToolNames); + // Tools list changed after initial load (e.g., URL was edited) + // Keep any tools from the current selection that exist in the new tools list + const matchingTools = allowedTools.filter((toolName) => availableToolNames.includes(toolName)); + onAllowedToolsChange(matchingTools); } + } else if (tools.length === 0 && previousToolsRef.current.length > 0) { + // Tools were cleared (e.g., URL became invalid or is being edited) + // Don't clear allowedTools here - let the user keep their selection + // until new tools are loaded } - // Update ref to track tools length (will be 0 when tools clear) - previousToolsLengthRef.current = tools.length; - }, [tools, allowedTools.length, existingAllowedTools, onAllowedToolsChange]); + + // Update ref to track current tools + previousToolsRef.current = tools; + }, [tools, allowedTools, existingAllowedTools, onAllowedToolsChange]); const handleToolToggle = (toolName: string) => { if (allowedTools.includes(toolName)) {