diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 6ae9acbea2f..9d066e44922 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -61,6 +61,7 @@ "src/components/guardrails/content_filter/CategoryTable.tsx", "src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx", "src/components/prompts/variable_textarea.tsx", + "src/components/chat/MCPCredentialsTab.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/chat/MCPCredentialsTab.tsx b/ui/litellm-dashboard/src/components/chat/MCPCredentialsTab.tsx index e2d879b22a8..9d772e5c4a8 100644 --- a/ui/litellm-dashboard/src/components/chat/MCPCredentialsTab.tsx +++ b/ui/litellm-dashboard/src/components/chat/MCPCredentialsTab.tsx @@ -8,10 +8,18 @@ */ import React, { useCallback, useEffect, useState } from "react"; -import { Spin } from "antd"; +import { Badge } from "@/components/ui/badge"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { cn } from "@/lib/utils"; +import { Link as LinkIcon, Loader2, Trash2 } from "lucide-react"; import MessageManager from "@/components/molecules/message_manager"; -import { DeleteOutlined, LinkOutlined } from "@ant-design/icons"; -import { Badge, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "@tremor/react"; import { deleteMCPOAuthUserCredential, listMCPUserCredentials, @@ -58,7 +66,9 @@ function expiryLabel(isoString: string | null | undefined): string { } const MCPCredentialsTab: React.FC = ({ accessToken }) => { - const [credentials, setCredentials] = useState([]); + const [credentials, setCredentials] = useState( + [], + ); const [loading, setLoading] = useState(true); const [revoking, setRevoking] = useState>(new Set()); @@ -70,7 +80,9 @@ const MCPCredentialsTab: React.FC = ({ accessToken }) => { .finally(() => setLoading(false)); }, [accessToken]); - useEffect(() => { load(); }, [load]); + useEffect(() => { + load(); + }, [load]); const handleRevoke = async (serverId: string) => { setRevoking((prev) => new Set(prev).add(serverId)); @@ -80,7 +92,11 @@ const MCPCredentialsTab: React.FC = ({ accessToken }) => { } catch { MessageManager.error("Failed to revoke connection. Please try again."); } finally { - setRevoking((prev) => { const n = new Set(prev); n.delete(serverId); return n; }); + setRevoking((prev) => { + const n = new Set(prev); + n.delete(serverId); + return n; + }); } }; @@ -89,44 +105,42 @@ const MCPCredentialsTab: React.FC = ({ accessToken }) => { return (
- {/* Header */}
-

App Credentials

-

+

+ App Credentials +

+

Your stored OAuth connections — used automatically in chat.

{loading ? (
- +
) : credentials.length === 0 ? ( -
- +
+ No connections yet.
- Go to Apps and click Connect to authorize an MCP server. + Go to Apps and click Connect to + authorize an MCP server.
) : ( -
+
- + - - App - - + App + Connected - - - Status - - + + Status + Actions - + - + {credentials.map((cred) => { const name = displayName(cred); @@ -136,27 +150,50 @@ const MCPCredentialsTab: React.FC = ({ accessToken }) => { const isExpired = exp === "Expired"; return ( - - - {name} + + + + {name} + - - {connected || "—"} + + + {connected || "—"} + - - + + {exp} - +