diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx index 3ee5676235a..93fa99291fc 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx @@ -9,6 +9,7 @@ import MCPServerEdit, { EDIT_OAUTH_UI_STATE_KEY } from "./mcp_server_edit"; import { getSecureItem } from "@/utils/secureStorage"; import MCPServerCostDisplay from "./mcp_server_cost_display"; import { getMaskedAndFullUrl } from "./utils"; +import { getProxyBaseUrl } from "@/components/networking"; import { copyToClipboard as utilCopyToClipboard } from "@/utils/dataUtils"; import { CheckIcon, CopyIcon } from "lucide-react"; import { Button as AntdButton } from "antd"; @@ -55,12 +56,12 @@ export const MCPServerView: React.FC = ({ initialTabIndex = 0, }) => { // Open the editing Settings tab on first render when returning from the edit OAuth - // redirect, so the "token fetched" feedback shows where the user left off (Settings=2). + // redirect, so the "token fetched" feedback shows where the user left off (Settings=3). const returningFromEditOAuth = isReturningFromEditOAuth(isProxyAdmin, mcpServer.server_id); const [editing, setEditing] = useState(isEditing || returningFromEditOAuth); const [showFullUrl, setShowFullUrl] = useState(false); const [copiedStates, setCopiedStates] = useState>({}); - const [selectedTabIndex, setSelectedTabIndex] = useState(returningFromEditOAuth ? 2 : initialTabIndex); + const [selectedTabIndex, setSelectedTabIndex] = useState(returningFromEditOAuth ? 3 : initialTabIndex); const handleSuccess = (updated: MCPServer) => { setEditing(false); @@ -70,6 +71,10 @@ export const MCPServerView: React.FC = ({ const urlValue = mcpServer.url ?? ""; const { maskedUrl, hasToken } = urlValue ? getMaskedAndFullUrl(urlValue) : { maskedUrl: "—", hasToken: false }; + const coworkServerIdentifier = mcpServer.alias || mcpServer.server_name || mcpServer.server_id; + const coworkUrl = `${getProxyBaseUrl()}/${coworkServerIdentifier}/mcp`; + const isUpstreamDelegated = mcpServer.delegate_auth_to_upstream === true; + const renderUrlWithToggle = (url: string | null | undefined, showFull: boolean) => { if (!url) return "—"; if (!hasToken) return url; @@ -151,6 +156,7 @@ export const MCPServerView: React.FC = ({ {[ Overview, MCP Tools, + Integrations, ...(isProxyAdmin ? [Settings] : []), ]} @@ -219,6 +225,45 @@ export const MCPServerView: React.FC = ({ /> + {/* Integrations Panel */} + + + Claude Cowork + + Add this MCP server to Claude Cowork by pasting the URL below into the connector setup. + + +
+ Server URL +
+ {coworkUrl} + : } + onClick={() => copyToClipboard(coworkUrl, "mcp-cowork-url")} + className={`transition-all duration-200 ${ + copiedStates["mcp-cowork-url"] + ? "text-green-600 bg-green-50 border-green-200" + : "text-gray-400 hover:text-gray-600 hover:bg-gray-100" + }`} + /> +
+
+ + {isUpstreamDelegated && ( +
+ OAuth: Dynamic Client Registration + + This server delegates authentication upstream, so Claude Cowork completes the OAuth flow directly + with the provider through Dynamic Client Registration. Leave the auth fields empty; no LiteLLM key + header is needed. + +
+ )} +
+
+ {/* Settings Panel */}