From 7ad1b5c32cbcf6f4b0332d2da560acde05e941e4 Mon Sep 17 00:00:00 2001
From: Yu Cheng <75090715+Gloria72@users.noreply.github.com>
Date: Wed, 5 Aug 2026 16:09:22 -0700
Subject: [PATCH] Fix MCP connect docs base URL
---
.../_components/mcpConnectBaseUrl.test.ts | 52 +++++++++++++++++++
.../_components/mcpConnectBaseUrl.ts | 21 ++++++++
.../_components/mcp_connect.test.tsx | 31 +++++++++++
.../mcp-servers/_components/mcp_connect.tsx | 6 ++-
.../_components/mcp_servers.test.tsx | 9 ++++
.../mcp-servers/_components/mcp_servers.tsx | 4 +-
6 files changed, 120 insertions(+), 3 deletions(-)
create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.test.ts
create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.ts
create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.test.tsx
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.test.ts
new file mode 100644
index 00000000000..dfc5e33557a
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.test.ts
@@ -0,0 +1,52 @@
+import { describe, expect, it } from "vitest";
+import { resolveMCPConnectBaseUrl } from "./mcpConnectBaseUrl";
+
+describe("resolveMCPConnectBaseUrl", () => {
+ const fallbackBaseUrl = "https://runtime.litellm.test";
+
+ it("uses LITELLM_UI_API_DOC_BASE_URL when provided", () => {
+ expect(
+ resolveMCPConnectBaseUrl(
+ {
+ LITELLM_UI_API_DOC_BASE_URL: "https://docs.litellm.test",
+ },
+ fallbackBaseUrl,
+ ),
+ ).toBe("https://docs.litellm.test");
+ });
+
+ it("prefers LITELLM_UI_API_DOC_BASE_URL over PROXY_BASE_URL", () => {
+ expect(
+ resolveMCPConnectBaseUrl(
+ {
+ LITELLM_UI_API_DOC_BASE_URL: "https://docs.litellm.test",
+ PROXY_BASE_URL: "https://proxy.litellm.test",
+ },
+ fallbackBaseUrl,
+ ),
+ ).toBe("https://docs.litellm.test");
+ });
+
+ it("falls back to PROXY_BASE_URL when the docs url is missing", () => {
+ expect(
+ resolveMCPConnectBaseUrl(
+ {
+ PROXY_BASE_URL: "https://proxy.litellm.test",
+ },
+ fallbackBaseUrl,
+ ),
+ ).toBe("https://proxy.litellm.test");
+ });
+
+ it("falls back to the runtime base url when settings are empty", () => {
+ expect(
+ resolveMCPConnectBaseUrl(
+ {
+ LITELLM_UI_API_DOC_BASE_URL: " ",
+ PROXY_BASE_URL: "",
+ },
+ fallbackBaseUrl,
+ ),
+ ).toBe(fallbackBaseUrl);
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.ts b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.ts
new file mode 100644
index 00000000000..5e250c36db8
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcpConnectBaseUrl.ts
@@ -0,0 +1,21 @@
+export interface MCPConnectProxySettings {
+ PROXY_BASE_URL?: string | null;
+ LITELLM_UI_API_DOC_BASE_URL?: string | null;
+}
+
+export function resolveMCPConnectBaseUrl(
+ proxySettings: MCPConnectProxySettings | undefined,
+ fallbackBaseUrl: string,
+): string {
+ const customDocBaseUrl = proxySettings?.LITELLM_UI_API_DOC_BASE_URL;
+ if (customDocBaseUrl && customDocBaseUrl.trim()) {
+ return customDocBaseUrl.trim();
+ }
+
+ const proxyBaseUrl = proxySettings?.PROXY_BASE_URL;
+ if (proxyBaseUrl && proxyBaseUrl.trim()) {
+ return proxyBaseUrl.trim();
+ }
+
+ return fallbackBaseUrl;
+}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.test.tsx
new file mode 100644
index 00000000000..1e770359242
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.test.tsx
@@ -0,0 +1,31 @@
+import { render } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import MCPConnect from "./mcp_connect";
+
+vi.mock("@/components/networking", () => ({
+ getProxyBaseUrl: vi.fn(() => "https://runtime.litellm.test"),
+}));
+
+vi.mock("@/utils/dataUtils", () => ({
+ copyToClipboard: vi.fn(),
+}));
+
+describe("MCPConnect", () => {
+ it("renders connection snippets with the API docs base url when configured", () => {
+ const apiDocBaseUrl = "https://docs.litellm.test";
+ const proxyBaseUrl = "https://proxy.litellm.test";
+
+ const { container } = render(
+ ,
+ );
+
+ expect(container.textContent).toContain(`${apiDocBaseUrl}/mcp`);
+ expect(container.textContent).toContain(`${apiDocBaseUrl}/v1/responses`);
+ expect(container.textContent).not.toContain(`${proxyBaseUrl}/mcp`);
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.tsx
index 7bdfd9c6b8f..9fee32d118b 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connect.tsx
@@ -6,6 +6,7 @@ import { TabPanel, TabPanels, TabGroup, TabList, Tab, Title as TremorTitle, Text
import { CopyIcon, Code, Terminal, Globe, CheckIcon, ExternalLinkIcon, KeyIcon, ServerIcon, Zap } from "lucide-react";
import { getProxyBaseUrl } from "@/components/networking";
import { copyToClipboard as utilCopyToClipboard } from "@/utils/dataUtils";
+import { resolveMCPConnectBaseUrl, type MCPConnectProxySettings } from "./mcpConnectBaseUrl";
const { Title, Text } = Typography;
const { Panel } = Collapse;
@@ -112,10 +113,11 @@ const FeatureCard: React.FC = ({
interface MCPConnectProps {
currentServerAccessGroups?: string[];
+ proxySettings?: MCPConnectProxySettings;
}
-const MCPConnect: React.FC = ({ currentServerAccessGroups = [] }) => {
- const proxyBaseUrl = getProxyBaseUrl();
+const MCPConnect: React.FC = ({ currentServerAccessGroups = [], proxySettings }) => {
+ const proxyBaseUrl = resolveMCPConnectBaseUrl(proxySettings, getProxyBaseUrl());
const [copiedStates, setCopiedStates] = useState>({});
const [serverHeaders, setServerHeaders] = useState>({
openai: [],
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.test.tsx
index f9f3d20ca15..a5cb485fefe 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_servers.test.tsx
@@ -27,6 +27,15 @@ vi.mock("@/components/molecules/notifications_manager", () => ({
},
}));
+vi.mock("@/app/(dashboard)/hooks/proxySettings/useProxySettings", () => ({
+ __esModule: true,
+ default: vi.fn(() => ({
+ PROXY_BASE_URL: "",
+ PROXY_LOGOUT_URL: "",
+ LITELLM_UI_API_DOC_BASE_URL: null,
+ })),
+}));
+
const createQueryClient = () =>
new QueryClient({
defaultOptions: {
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 193246aab3c..a99cc936e9f 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
@@ -20,6 +20,7 @@ import React, { useEffect, useState, useMemo, useCallback } from "react";
import { useQuery } from "@tanstack/react-query";
import { useMCPServers } from "@/app/(dashboard)/hooks/mcpServers/useMCPServers";
import { useMCPServerHealth } from "@/app/(dashboard)/hooks/mcpServers/useMCPServerHealth";
+import useProxySettings from "@/app/(dashboard)/hooks/proxySettings/useProxySettings";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { deleteMCPServer } from "@/components/networking";
import { MCPSubmissionsTab } from "./MCPSubmissionsTab";
@@ -109,6 +110,7 @@ const readToolsOAuthServerId = (): string | null => {
const MCPServers: React.FC = ({ accessToken, userRole, userID }) => {
const { data: mcpServers, isLoading: isLoadingServers, refetch } = useMCPServers();
+ const proxySettings = useProxySettings(accessToken);
// Fetch health status for all servers
const {
@@ -707,7 +709,7 @@ const MCPServers: React.FC = ({ accessToken, userRole, userID })
-
+
{isAdminRole(userRole) && (