From 313093a8a0602a5f4d8b59d75eb71aa6613c3af3 Mon Sep 17 00:00:00 2001 From: yassin Date: Thu, 17 Sep 2026 22:36:00 +0000 Subject: [PATCH] fix(ui): gate MCP live connections tab to proxy admin tier roles Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../mcp-servers/_components/mcp_servers.tsx | 6 +++--- ui/litellm-dashboard/src/utils/roles.test.ts | 17 +++++++++++++++++ ui/litellm-dashboard/src/utils/roles.ts | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.tsx index 8a1f8aa9206..00d79022103 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.tsx @@ -1,4 +1,4 @@ -import { isAdminRole } from "@/utils/roles"; +import { isAdminRole, isProxyAdminTierRole } from "@/utils/roles"; import { CircleHelp, Search } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -561,7 +561,7 @@ const MCPServers: React.FC = ({ accessToken, userRole, userID }) Submitted MCPs )} - {isAdminRole(userRole) && ( + {isProxyAdminTierRole(userRole) && ( Live Connections @@ -753,7 +753,7 @@ const MCPServers: React.FC = ({ accessToken, userRole, userID }) )} - {isAdminRole(userRole) && ( + {isProxyAdminTierRole(userRole) && ( diff --git a/ui/litellm-dashboard/src/utils/roles.test.ts b/ui/litellm-dashboard/src/utils/roles.test.ts index 0170d01d8e6..821da09257b 100644 --- a/ui/litellm-dashboard/src/utils/roles.test.ts +++ b/ui/litellm-dashboard/src/utils/roles.test.ts @@ -8,6 +8,7 @@ import { isOrgAdminForAnyOrg, isOrgAdminSessionRole, isProxyAdminRole, + isProxyAdminTierRole, isUserTeamAdminForAnyTeam, isUserTeamAdminForSingleTeam, isViewOnlySessionRole, @@ -58,6 +59,22 @@ describe("roles", () => { }); }); + describe("isProxyAdminTierRole", () => { + it("should return true for proxy admin and proxy admin viewer roles", () => { + expect(isProxyAdminTierRole("proxy_admin")).toBe(true); + expect(isProxyAdminTierRole("Admin")).toBe(true); + expect(isProxyAdminTierRole("proxy_admin_viewer")).toBe(true); + expect(isProxyAdminTierRole("Admin Viewer")).toBe(true); + }); + + it("should return false for org admin and non-admin roles", () => { + expect(isProxyAdminTierRole("org_admin")).toBe(false); + expect(isProxyAdminTierRole("Internal User")).toBe(false); + expect(isProxyAdminTierRole("Internal Viewer")).toBe(false); + expect(isProxyAdminTierRole("")).toBe(false); + }); + }); + describe("isUserTeamAdminForSingleTeam", () => { it("should return true when user is team admin", () => { const members_with_roles = [ diff --git a/ui/litellm-dashboard/src/utils/roles.ts b/ui/litellm-dashboard/src/utils/roles.ts index 62a5f02cc39..85ac5333072 100644 --- a/ui/litellm-dashboard/src/utils/roles.ts +++ b/ui/litellm-dashboard/src/utils/roles.ts @@ -32,6 +32,9 @@ export const isProxyAdminRole = (role: string): boolean => { return role === "proxy_admin" || role === "Admin"; }; +export const proxyAdminTierRoles = ["Admin", "Admin Viewer", "proxy_admin", "proxy_admin_viewer"]; +export const isProxyAdminTierRole = (role: string): boolean => proxyAdminTierRoles.includes(role); + export const isUserTeamAdminForAnyTeam = (teams: Team[] | null, userID: string): boolean => { if (teams == null) { return false;