From 19e9a31a525a37c7938c18365eee56d34f022889 Mon Sep 17 00:00:00 2001 From: Tin Chi Lo Date: Tue, 21 Jul 2026 15:51:31 -0700 Subject: [PATCH] feat(ui): add the enterprise-managed authorization (ID-JAG) MCP form arm and auto-connected Apps grid state --- .../_components/IdJagFormFields.tsx | 157 ++++++++++++++++++ .../_components/create_mcp_server.test.tsx | 122 ++++++++++++++ .../_components/create_mcp_server.tsx | 10 +- .../_components/mcp_server_edit.test.tsx | 44 +++++ .../_components/mcp_server_edit.tsx | 10 +- .../src/components/chat/MCPAppsPanel.test.tsx | 93 +++++++++++ .../src/components/chat/MCPAppsPanel.tsx | 127 ++++++++------ .../src/components/mcp_tools/types.test.tsx | 16 ++ .../src/components/mcp_tools/types.tsx | 11 +- 9 files changed, 532 insertions(+), 58 deletions(-) create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/IdJagFormFields.tsx create mode 100644 ui/litellm-dashboard/src/components/chat/MCPAppsPanel.test.tsx diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/IdJagFormFields.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/IdJagFormFields.tsx new file mode 100644 index 00000000000..b43ef32c435 --- /dev/null +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/IdJagFormFields.tsx @@ -0,0 +1,157 @@ +import React, { useState } from "react"; +import { Form, Input, Select, Tooltip } from "antd"; +import { InfoCircleOutlined } from "@ant-design/icons"; + +interface IdJagFormFieldsProps { + isEditing?: boolean; +} + +const fieldClassName = "rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"; + +const FieldLabel: React.FC<{ label: string; tooltip: string }> = ({ label, tooltip }) => ( + + {label} + + + + +); + +const IdJagFormFields: React.FC = ({ isEditing = false }) => { + const placeholderSuffix = isEditing ? " (leave blank to keep existing)" : ""; + const [clientAuthMethod, setClientAuthMethod] = useState<"client_secret" | "private_key_jwt">("client_secret"); + + return ( + <> + + } + name="token_exchange_endpoint" + rules={[{ required: !isEditing, message: "The IdP token exchange endpoint is required for ID-JAG" }]} + > + + + + } + name={["credentials", "id_jag_resource_token_endpoint"]} + > + + + + } + name={["credentials", "client_id"]} + rules={[{ required: !isEditing, message: "Client ID is required for ID-JAG" }]} + > + + + + } + > + + className="rounded-lg" + size="large" + value={clientAuthMethod} + onChange={setClientAuthMethod} + options={[ + { value: "client_secret", label: Client Secret }, + { value: "private_key_jwt", label: Private Key JWT }, + ]} + /> + + {clientAuthMethod === "client_secret" && ( + + } + name={["credentials", "client_secret"]} + rules={[{ required: !isEditing, message: "Client Secret is required for ID-JAG" }]} + > + + + )} + {clientAuthMethod === "private_key_jwt" && ( + <> + + } + name={["credentials", "client_private_key"]} + rules={[{ required: !isEditing, message: "A private key is required for private_key_jwt" }]} + > + + + + } + name={["credentials", "client_private_key_id"]} + > + + + + } + name={["credentials", "client_assertion_signing_alg"]} + > + + + + )} + + } + name="audience" + > + + + } + name={["credentials", "scopes"]} + > + + +