From 9bd94ee96fbdddc5220da88eb7eecc727245bb9e Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Sat, 25 Apr 2026 16:01:58 -0700 Subject: [PATCH] feat(mcp): add OAuth2ConnectButton for per-row PKCE connect flow --- .../mcp_tools/OAuth2ConnectButton.tsx | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 ui/litellm-dashboard/src/components/mcp_tools/OAuth2ConnectButton.tsx diff --git a/ui/litellm-dashboard/src/components/mcp_tools/OAuth2ConnectButton.tsx b/ui/litellm-dashboard/src/components/mcp_tools/OAuth2ConnectButton.tsx new file mode 100644 index 00000000000..650545b68bb --- /dev/null +++ b/ui/litellm-dashboard/src/components/mcp_tools/OAuth2ConnectButton.tsx @@ -0,0 +1,62 @@ +"use client"; + +import React, { useCallback } from "react"; +import { CheckOutlined } from "@ant-design/icons"; +import { useUserMcpOAuthFlow } from "@/hooks/useUserMcpOAuthFlow"; +import { MCPServer } from "./types"; + +interface OAuth2ConnectButtonProps { + server: MCPServer; + accessToken: string; + onSuccess: () => void; +} + +/** + * Renders the appropriate credential UI for an OAuth2 MCP server in the catalog table: + * - Not connected → blue "Connect" button (starts PKCE redirect flow) + * - Connected + internal user → green badge + "Disconnect" link + * - Connected + admin → green badge + "Reconnect" link + */ +const OAuth2ConnectButton: React.FC = ({ + server, + accessToken, + onSuccess, +}) => { + const { startOAuthFlow, status } = useUserMcpOAuthFlow({ + accessToken, + serverId: server.server_id, + serverAlias: server.server_name ?? server.alias ?? undefined, + onSuccess, + }); + + const loading = status === "authorizing" || status === "exchanging"; + + if (server.has_user_credential) { + return ( +
+ + Connected + + +
+ ); + } + + return ( + + ); +}; + +export default OAuth2ConnectButton;