diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 194af4895fe..bb4a678b541 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -19553,7 +19553,8 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "gpt-4.1-2025-04-14": { "cache_read_input_token_cost": 5e-07, @@ -19587,7 +19588,8 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "gpt-4.1-mini": { "cache_read_input_token_cost": 1e-07, @@ -19624,7 +19626,8 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "gpt-4.1-mini-2025-04-14": { "cache_read_input_token_cost": 1e-07, @@ -19658,7 +19661,8 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "gpt-4.1-nano": { "cache_read_input_token_cost": 2.5e-08, @@ -20866,6 +20870,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21505,6 +21510,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21605,6 +21611,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21640,6 +21647,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21672,6 +21680,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true }, @@ -21707,6 +21716,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21742,6 +21752,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true }, @@ -21777,6 +21788,7 @@ "supports_system_messages": false, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21818,6 +21830,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21859,6 +21872,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21897,6 +21911,7 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -21934,6 +21949,7 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": false }, @@ -25721,7 +25737,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o3-2025-04-16": { "cache_read_input_token_cost": 5e-07, @@ -25753,7 +25770,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o3-deep-research": { "cache_read_input_token_cost": 2.5e-06, @@ -25786,7 +25804,8 @@ "supports_response_schema": true, "supports_system_messages": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o3-deep-research-2025-06-26": { "cache_read_input_token_cost": 2.5e-06, @@ -25819,7 +25838,8 @@ "supports_response_schema": true, "supports_system_messages": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o3-mini": { "cache_read_input_token_cost": 5.5e-07, @@ -25883,7 +25903,8 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o3-pro-2025-06-10": { "input_cost_per_token": 2e-05, @@ -25913,7 +25934,8 @@ "supports_reasoning": true, "supports_response_schema": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o4-mini": { "cache_read_input_token_cost": 2.75e-07, @@ -25938,7 +25960,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o4-mini-2025-04-16": { "cache_read_input_token_cost": 2.75e-07, @@ -25957,7 +25980,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o4-mini-deep-research": { "cache_read_input_token_cost": 5e-07, @@ -25990,7 +26014,8 @@ "supports_response_schema": true, "supports_system_messages": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "o4-mini-deep-research-2025-06-26": { "cache_read_input_token_cost": 5e-07, @@ -26023,7 +26048,8 @@ "supports_response_schema": true, "supports_system_messages": true, "supports_tool_choice": true, - "supports_vision": true + "supports_vision": true, + "supports_web_search": true }, "oci/meta.llama-3.1-405b-instruct": { "input_cost_per_token": 1.068e-05, diff --git a/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.tsx b/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.tsx index f3a387c02bd..f6d728f7882 100644 --- a/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.tsx +++ b/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.tsx @@ -1,10 +1,10 @@ "use client"; import React, { useEffect, useState } from "react"; -import { Switch, Spin, Input, Button } from "antd"; -import { SearchOutlined, ArrowLeftOutlined, RightOutlined } from "@ant-design/icons"; +import { Spin, Input, Button, Skeleton } from "antd"; +import { SearchOutlined, ArrowLeftOutlined, RightOutlined, ToolOutlined } from "@ant-design/icons"; import { fetchMCPServers, listMCPTools } from "../networking"; -import { AUTH_TYPE, MCPServer } from "../mcp_tools/types"; +import { AUTH_TYPE, MCPServer, MCPTool, handleTransport } from "../mcp_tools/types"; import { message } from "antd"; interface Props { @@ -33,33 +33,65 @@ const MCPAppsPanel: React.FC = ({ accessToken, selectedServers, onChange const [activeTab, setActiveTab] = useState("all"); const [togglingOn, setTogglingOn] = useState>(new Set()); const [detailServer, setDetailServer] = useState(null); + const [detailTools, setDetailTools] = useState([]); + const [loadingTools, setLoadingTools] = useState(false); + // tool counts per server name, preloaded in background + const [toolCounts, setToolCounts] = useState>({}); + const [loadingCounts, setLoadingCounts] = useState(false); + + const nameOf = (s: MCPServer) => s.server_name ?? s.alias ?? s.server_id; useEffect(() => { let cancelled = false; setLoading(true); + + // 1. Load servers first — show the list immediately fetchMCPServers(accessToken) - .then((data) => { + .then((serverData) => { if (cancelled) return; - const list: MCPServer[] = Array.isArray(data) ? data : (data?.data ?? []); + const list: MCPServer[] = Array.isArray(serverData) ? serverData : (serverData?.data ?? []); setServers(list); + setLoading(false); + + // 2. Fetch tools per server in parallel — each resolves independently and updates counts one by one + setLoadingCounts(true); + let remaining = list.length; + if (remaining === 0) { setLoadingCounts(false); return; } + list.forEach((s) => { + listMCPTools(accessToken, s.server_id) + .then((toolsData) => { + if (cancelled) return; + const tools: MCPTool[] = Array.isArray(toolsData?.tools) ? toolsData.tools : []; + const sname = nameOf(s); + setToolCounts((prev) => ({ ...prev, [sname]: tools.length })); + }) + .catch(() => {}) + .finally(() => { + if (cancelled) return; + remaining -= 1; + if (remaining === 0) setLoadingCounts(false); + }); + }); }) .catch(() => { - if (!cancelled) setServers([]); - }) - .finally(() => { - if (!cancelled) setLoading(false); + if (!cancelled) { + setServers([]); + setLoading(false); + } }); return () => { cancelled = true; }; }, [accessToken]); - const handleToggle = async (serverName: string, checked: boolean) => { + const handleToggle = async (serverName: string, checked: boolean, serverId?: string) => { if (!checked) { onChange(selectedServers.filter((s) => s !== serverName)); return; } setTogglingOn((prev) => new Set(prev).add(serverName)); try { - const result = await listMCPTools(accessToken, serverName); + // Use UUID if available, fall back to name (for connectivity check only) + const idToFetch = serverId ?? serverName; + const result = await listMCPTools(accessToken, idToFetch); if (result?.error) { message.warning(`Could not load tools for ${serverName}`); return; @@ -76,7 +108,29 @@ const MCPAppsPanel: React.FC = ({ accessToken, selectedServers, onChange } }; - const nameOf = (s: MCPServer) => s.server_name ?? s.alias ?? s.server_id; + // Fetch tools for the detail view — server_id must be the UUID + useEffect(() => { + if (!detailServer) { + setDetailTools([]); + return; + } + let cancelled = false; + setLoadingTools(true); + listMCPTools(accessToken, detailServer.server_id) + .then((result) => { + if (cancelled) return; + // API returns { tools: [...], error: null } + const tools: MCPTool[] = Array.isArray(result?.tools) ? result.tools : []; + setDetailTools(tools); + }) + .catch(() => { + if (!cancelled) setDetailTools([]); + }) + .finally(() => { + if (!cancelled) setLoadingTools(false); + }); + return () => { cancelled = true; }; + }, [detailServer, accessToken]); const filtered = servers.filter((s) => { const name = nameOf(s); @@ -89,6 +143,9 @@ const MCPAppsPanel: React.FC = ({ accessToken, selectedServers, onChange const connectedCount = servers.filter((s) => selectedServers.includes(nameOf(s))).length; + // Total tools available across all servers (based on preloaded counts) + const totalTools = Object.values(toolCounts).reduce((sum, n) => sum + n, 0); + // ── Detail view ── if (detailServer) { const name = nameOf(detailServer); @@ -128,7 +185,7 @@ const MCPAppsPanel: React.FC = ({ accessToken, selectedServers, onChange