From 9daa70a84289df40f8cf0449297c91a718f20304 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Mon, 9 Mar 2026 16:13:39 -0700 Subject: [PATCH] fix(ui): move key tools preview inside Tool Configuration card --- .../mcp_tools/OpenAPIFormSection.tsx | 56 ++----------------- .../mcp_tools/create_mcp_server.tsx | 5 +- .../mcp_tools/mcp_tool_configuration.tsx | 48 +++++++++++++++- 3 files changed, 55 insertions(+), 54 deletions(-) diff --git a/ui/litellm-dashboard/src/components/mcp_tools/OpenAPIFormSection.tsx b/ui/litellm-dashboard/src/components/mcp_tools/OpenAPIFormSection.tsx index a453e1b06c1..6d18f209103 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/OpenAPIFormSection.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/OpenAPIFormSection.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { Form, Input, Tooltip } from "antd"; -import { InfoCircleOutlined, ToolOutlined } from "@ant-design/icons"; +import { InfoCircleOutlined } from "@ant-design/icons"; import { FormInstance } from "antd/es/form"; import { AUTH_TYPE } from "./types"; import OpenAPIQuickPicker, { OpenAPIRegistryEntry, OpenAPIKeyTool } from "./OpenAPIQuickPicker"; @@ -10,25 +10,26 @@ interface OpenAPIFormSectionProps { accessToken: string | null; /** Called when a preset is selected so the parent can sync its formValues state. */ onValuesChange: (updates: Record) => void; + /** Called when key tools change (from registry preset selection). */ + onKeyToolsChange?: (tools: OpenAPIKeyTool[]) => void; } /** * Encapsulates all OpenAPI-specific form fields: * - popular API quick-picker (logos) * - spec URL input - * - curated key tools preview (8 tools from registry, expandable) */ const OpenAPIFormSection: React.FC = ({ form, accessToken, onValuesChange, + onKeyToolsChange, }) => { const [selectedPreset, setSelectedPreset] = useState(null); - const [keyTools, setKeyTools] = useState([]); const handlePresetSelect = (entry: OpenAPIRegistryEntry) => { setSelectedPreset(entry.name); - setKeyTools(entry.key_tools ?? []); + onKeyToolsChange?.(entry.key_tools ?? []); const updates = { spec_path: entry.spec_url, auth_type: AUTH_TYPE.OAUTH2, @@ -66,54 +67,9 @@ const OpenAPIFormSection: React.FC = ({ className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500" /> - - {keyTools.length > 0 && ( - - )} ); }; -interface KeyToolsPreviewProps { - tools: OpenAPIKeyTool[]; -} - -const KeyToolsPreview: React.FC = ({ tools }) => { - const [expanded, setExpanded] = useState(false); - const shown = expanded ? tools : tools.slice(0, 4); - - return ( -
-
- - - Key tools from this API - -
- -
- {shown.map((tool) => ( - - - {tool.name} - - - ))} -
- - {tools.length > 4 && ( - - )} -
- ); -}; - export default OpenAPIFormSection; +export type { OpenAPIKeyTool }; diff --git a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx index 582d9c2a8b5..501f4f7fd7c 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx @@ -10,7 +10,7 @@ import MCPConnectionStatus from "./mcp_connection_status"; import MCPToolConfiguration from "./mcp_tool_configuration"; import StdioConfiguration from "./StdioConfiguration"; import MCPPermissionManagement from "./MCPPermissionManagement"; -import OpenAPIFormSection from "./OpenAPIFormSection"; +import OpenAPIFormSection, { OpenAPIKeyTool } from "./OpenAPIFormSection"; import { isAdminRole } from "@/utils/roles"; import { validateMCPServerUrl, validateMCPServerName } from "./utils"; import NotificationsManager from "../molecules/notifications_manager"; @@ -58,6 +58,7 @@ const CreateMCPServer: React.FC = ({ const [toolNameToDisplayName, setToolNameToDisplayName] = useState>({}); const [toolNameToDescription, setToolNameToDescription] = useState>({}); const [transportType, setTransportType] = useState(""); + const [keyTools, setKeyTools] = useState([]); const [searchValue, setSearchValue] = useState(""); const [oauthAccessToken, setOauthAccessToken] = useState(null); const authType = formValues.auth_type as string | undefined; @@ -612,6 +613,7 @@ const CreateMCPServer: React.FC = ({ onValuesChange={(updates) => setFormValues((prev) => ({ ...prev, ...updates })) } + onKeyToolsChange={setKeyTools} /> )} @@ -794,6 +796,7 @@ const CreateMCPServer: React.FC = ({ toolNameToDescription={toolNameToDescription} onToolNameToDisplayNameChange={setToolNameToDisplayName} onToolNameToDescriptionChange={setToolNameToDescription} + keyTools={keyTools} /> 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 87f14021f46..60aeb2a6b30 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 @@ -1,9 +1,14 @@ import React, { useEffect, useRef, useState } from "react"; import { Card, Title, Text } from "@tremor/react"; import { ToolOutlined, CheckCircleOutlined, SearchOutlined, EditOutlined } from "@ant-design/icons"; -import { Badge, Spin, Checkbox, Input } from "antd"; +import { Badge, Spin, Checkbox, Input, Tooltip } from "antd"; import { useTestMCPConnection } from "../../hooks/useTestMCPConnection"; +interface KeyTool { + name: string; + description: string; +} + interface MCPToolConfigurationProps { accessToken: string | null; oauthAccessToken?: string | null; @@ -15,6 +20,8 @@ interface MCPToolConfigurationProps { toolNameToDescription: Record; onToolNameToDisplayNameChange: (map: Record) => void; onToolNameToDescriptionChange: (map: Record) => void; + /** Curated key tools from the OpenAPI registry preset (shown before spec loads). */ + keyTools?: KeyTool[]; } const MCPToolConfiguration: React.FC = ({ @@ -28,6 +35,7 @@ const MCPToolConfiguration: React.FC = ({ toolNameToDescription, onToolNameToDisplayNameChange, onToolNameToDescriptionChange, + keyTools, }) => { const previousToolsRef = useRef([]); const [toolSearchTerm, setToolSearchTerm] = useState(""); @@ -173,10 +181,15 @@ const MCPToolConfiguration: React.FC = ({ {isLoadingTools && (
- Loading tools... + Loading tools from spec...
)} + {/* Key tools preview — shown while loading or when spec hasn't loaded yet */} + {keyTools && keyTools.length > 0 && (isLoadingTools || (!isLoadingTools && !toolsError && tools.length === 0)) && ( + + )} + {/* Error state */} {toolsError && !isLoadingTools && (
@@ -188,7 +201,7 @@ const MCPToolConfiguration: React.FC = ({ )} {/* No tools state */} - {!isLoadingTools && !toolsError && tools.length === 0 && canFetchTools && ( + {!isLoadingTools && !toolsError && tools.length === 0 && canFetchTools && (!keyTools || keyTools.length === 0) && (
No tools available for configuration @@ -364,4 +377,33 @@ const MCPToolConfiguration: React.FC = ({ ); }; +const KeyToolsPreview: React.FC<{ tools: KeyTool[] }> = ({ tools }) => { + const [expanded, setExpanded] = useState(false); + const shown = expanded ? tools : tools.slice(0, 4); + + return ( +
+

Key tools from this API (preview — all tools load from the spec)

+
+ {shown.map((tool) => ( + + + {tool.name} + + + ))} +
+ {tools.length > 4 && ( + + )} +
+ ); +}; + export default MCPToolConfiguration;