From a722d954934ebc03050d5a5202a12e4041dcec80 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Sat, 21 Mar 2026 19:01:03 -0700 Subject: [PATCH] feat(mcp): show toolsets section in MCPServerPermissions read view --- .../permissions/MCPServerPermissions.tsx | 128 ++++++++++++++---- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/ui/litellm-dashboard/src/components/permissions/MCPServerPermissions.tsx b/ui/litellm-dashboard/src/components/permissions/MCPServerPermissions.tsx index 962fc00670a..649e8efdf4a 100644 --- a/ui/litellm-dashboard/src/components/permissions/MCPServerPermissions.tsx +++ b/ui/litellm-dashboard/src/components/permissions/MCPServerPermissions.tsx @@ -2,25 +2,28 @@ import React, { useState, useEffect } from "react"; import { Text, Badge } from "@tremor/react"; import { ServerIcon, ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/outline"; import { Tooltip } from "antd"; -import { fetchMCPServers } from "../networking"; -import { MCPServer } from "../mcp_tools/types"; +import { fetchMCPServers, fetchMCPToolsets } from "../networking"; +import { MCPServer, MCPToolset } from "../mcp_tools/types"; interface MCPServerPermissionsProps { mcpServers: string[]; mcpAccessGroups?: string[]; mcpToolPermissions?: Record; + mcpToolsets?: string[]; accessToken?: string | null; } -export function MCPServerPermissions({ - mcpServers, - mcpAccessGroups = [], +export function MCPServerPermissions({ + mcpServers, + mcpAccessGroups = [], mcpToolPermissions = {}, - accessToken + mcpToolsets = [], + accessToken }: MCPServerPermissionsProps) { const [mcpServerDetails, setMCPServerDetails] = useState([]); - const [accessGroupNames, setAccessGroupNames] = useState([]); + const [toolsetDetails, setToolsetDetails] = useState([]); const [expandedServers, setExpandedServers] = useState>(new Set()); + const [expandedToolsets, setExpandedToolsets] = useState>(new Set()); const toggleServerExpansion = (serverId: string) => { setExpandedServers((prev) => { @@ -34,6 +37,18 @@ export function MCPServerPermissions({ }); }; + const toggleToolsetExpansion = (toolsetId: string) => { + setExpandedToolsets((prev) => { + const newSet = new Set(prev); + if (newSet.has(toolsetId)) { + newSet.delete(toolsetId); + } else { + newSet.add(toolsetId); + } + return newSet; + }); + }; + // Fetch MCP server details when component mounts useEffect(() => { const fetchMCPServerDetails = async () => { @@ -53,20 +68,23 @@ export function MCPServerPermissions({ fetchMCPServerDetails(); }, [accessToken, mcpServers.length]); - // Fetch MCP access group names + // Fetch toolset details useEffect(() => { - const fetchGroups = async () => { - if (accessToken && mcpAccessGroups.length > 0) { + const fetchToolsets = async () => { + if (accessToken && mcpToolsets.length > 0) { try { - const groups = await import("../networking").then((m) => m.fetchMCPAccessGroups(accessToken)); - setAccessGroupNames(Array.isArray(groups) ? groups : groups.data || []); + const all = await fetchMCPToolsets(accessToken); + const filtered = Array.isArray(all) + ? all.filter((t: MCPToolset) => mcpToolsets.includes(t.toolset_id)) + : []; + setToolsetDetails(filtered); } catch (error) { - console.error("Error fetching MCP access groups:", error); + console.error("Error fetching toolsets:", error); } } }; - fetchGroups(); - }, [accessToken, mcpAccessGroups.length]); + fetchToolsets(); + }, [accessToken, mcpToolsets.length]); // Function to get display name for MCP server const getMCPServerDisplayName = (serverId: string) => { @@ -78,17 +96,12 @@ export function MCPServerPermissions({ return serverId; }; - // Function to get display name for access group - const getAccessGroupDisplayName = (group: string) => { - return group; - }; - // Merge servers and access groups into one list const mergedItems = [ ...mcpServers.map((server) => ({ type: "server", value: server })), ...mcpAccessGroups.map((group) => ({ type: "accessGroup", value: group })), ]; - const totalCount = mergedItems.length; + const totalCount = mergedItems.length + mcpToolsets.length; return (
@@ -99,21 +112,21 @@ export function MCPServerPermissions({ {totalCount}
- + {totalCount > 0 ? (
{mergedItems.map((item, index) => { const toolsForServer = item.type === "server" ? mcpToolPermissions[item.value] : undefined; const hasToolRestrictions = toolsForServer && toolsForServer.length > 0; const isExpanded = expandedServers.has(item.value); - + return (
-
hasToolRestrictions && toggleServerExpansion(item.value)} className={`flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 transition-all ${ - hasToolRestrictions - ? 'cursor-pointer hover:bg-gray-50 hover:border-gray-300' + hasToolRestrictions + ? 'cursor-pointer hover:bg-gray-50 hover:border-gray-300' : 'bg-white' }`} > @@ -128,14 +141,14 @@ export function MCPServerPermissions({ ) : (
- {getAccessGroupDisplayName(item.value)} + {item.value} Group
)}
- + {hasToolRestrictions && (
{toolsForServer.length} @@ -148,7 +161,7 @@ export function MCPServerPermissions({
)}
- + {/* Show tool permissions if expanded */} {hasToolRestrictions && isExpanded && (
@@ -167,11 +180,66 @@ export function MCPServerPermissions({
); })} + + {/* Toolsets section */} + {mcpToolsets.length > 0 && mcpToolsets.map((toolsetId, index) => { + const detail = toolsetDetails.find((t) => t.toolset_id === toolsetId); + const isExpanded = expandedToolsets.has(toolsetId); + const toolCount = detail?.tools.length ?? 0; + + return ( +
+
toolCount > 0 && toggleToolsetExpansion(toolsetId)} + className={`flex items-center gap-3 py-2 px-3 rounded-lg border border-purple-200 transition-all ${ + toolCount > 0 ? 'cursor-pointer hover:bg-purple-50 hover:border-purple-300' : 'bg-white' + }`} + > +
+ + + {detail?.toolset_name ?? toolsetId} + + + Toolset + +
+ {toolCount > 0 && ( +
+ {toolCount} + {toolCount === 1 ? "tool" : "tools"} + {isExpanded ? ( + + ) : ( + + )} +
+ )} +
+ + {toolCount > 0 && isExpanded && detail && ( +
+
+ {detail.tools.map((tool, toolIndex) => ( + + {tool.server_id.slice(0, 6)}… + {tool.tool_name} + + ))} +
+
+ )} +
+ ); + })}
) : (
- No MCP servers or access groups configured + No MCP servers, access groups, or toolsets configured
)}