diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 0bdf5a6375b..c7111b5ee79 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -67,6 +67,7 @@ "src/components/guardrails/GuardrailTestResults.tsx", "src/components/guardrails/GuardrailTestPlayground.tsx", "src/components/vector_store_management/S3VectorsConfig.tsx", + "src/components/mcp_tools/mcp_server_cost_config.tsx", "src/components/prompts/prompt_editor_view/PromptEditorHeader.tsx", "src/components/prompts/prompt_editor_view/VersionHistorySidePanel.tsx", "src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.tsx", diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_cost_config.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_cost_config.tsx index 3f3986d5a2e..f242f8ee4fa 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_cost_config.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_cost_config.tsx @@ -1,16 +1,71 @@ import React from "react"; -import { Tooltip, InputNumber, Collapse, Badge } from "antd"; -import { InfoCircleOutlined, DollarOutlined, ToolOutlined } from "@ant-design/icons"; -import { Card, Title, Text } from "@tremor/react"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { Badge } from "@/components/ui/badge"; +import { Card } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { DollarSign, Info, Wrench } from "lucide-react"; import { MCPServerCostInfo } from "./types"; interface MCPServerCostConfigProps { value?: MCPServerCostInfo; onChange?: (value: MCPServerCostInfo) => void; - tools?: any[]; // Receive tools from connection component + // eslint-disable-next-line @typescript-eslint/no-explicit-any + tools?: any[]; disabled?: boolean; } +const InfoTip: React.FC<{ children: React.ReactNode }> = ({ children }) => ( + + + + + + {children} + + +); + +const MoneyInput: React.FC<{ + value?: number | null; + onChange: (v: number | null) => void; + placeholder?: string; + disabled?: boolean; + className?: string; +}> = ({ value, onChange, placeholder, disabled, className }) => ( +
+ $ + { + const raw = e.target.value; + if (raw === "") { + onChange(null); + return; + } + const n = Number(raw); + onChange(isNaN(n) ? null : n); + }} + placeholder={placeholder} + disabled={disabled} + className="border-0 rounded-none shadow-none" + /> +
+); + const MCPServerCostConfig: React.FC = ({ value = {}, onChange, @@ -18,136 +73,139 @@ const MCPServerCostConfig: React.FC = ({ disabled = false, }) => { const handleDefaultCostChange = (defaultCost: number | null) => { - const updated = { + onChange?.({ ...value, default_cost_per_query: defaultCost, - }; - onChange?.(updated); + }); }; const handleToolCostChange = (toolName: string, cost: number | null) => { - const updated = { + onChange?.({ ...value, tool_name_to_cost_per_query: { ...value.tool_name_to_cost_per_query, [toolName]: cost, }, - }; - onChange?.(updated); + }); }; return ( - +
- - Cost Configuration - - - + +

Cost Configuration

+ + Configure costs for this MCP server's tool calls. Set a + default rate and per-tool overrides. +
-
{tools.length > 0 && (
-
- ), - children: ( -
- {tools.map((tool, index) => ( -
-
- {tool.name} - {tool.description && ( - {tool.description} - )} -
-
- handleToolCostChange(tool.name, cost)} - disabled={disabled} - style={{ width: "120px" }} - addonBefore="$" - /> -
+ + + +
+ + Available Tools + + {tools.length} + +
+
+ +
+ {tools.map((tool, index) => ( +
+
+ + {tool.name} + + {tool.description && ( + + {tool.description} + + )}
- ))} -
- ), - }, - ]} - /> +
+ + handleToolCostChange(tool.name, cost) + } + placeholder="Use default" + disabled={disabled} + className="w-[160px]" + /> +
+
+ ))} +
+ + +
)}
{(value.default_cost_per_query || - (value.tool_name_to_cost_per_query && Object.keys(value.tool_name_to_cost_per_query).length > 0)) && ( -
- Cost Summary: + (value.tool_name_to_cost_per_query && + Object.keys(value.tool_name_to_cost_per_query).length > 0)) && ( +
+

+ Cost Summary: +

{value.default_cost_per_query && ( - - • Default cost: ${value.default_cost_per_query.toFixed(4)} per query - +

+ • Default cost: $ + {value.default_cost_per_query.toFixed(4)} per query +

)} {value.tool_name_to_cost_per_query && Object.entries(value.tool_name_to_cost_per_query).map( ([toolName, cost]) => cost !== null && cost !== undefined && ( - +

• {toolName}: ${cost.toFixed(4)} per query - +

), )}