mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
Fix MCP connect docs base URL
This commit is contained in:
parent
aa1180c0c9
commit
7ad1b5c32c
6 changed files with 120 additions and 3 deletions
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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(
|
||||
<MCPConnect
|
||||
proxySettings={{
|
||||
LITELLM_UI_API_DOC_BASE_URL: apiDocBaseUrl,
|
||||
PROXY_BASE_URL: proxyBaseUrl,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.textContent).toContain(`${apiDocBaseUrl}/mcp`);
|
||||
expect(container.textContent).toContain(`${apiDocBaseUrl}/v1/responses`);
|
||||
expect(container.textContent).not.toContain(`${proxyBaseUrl}/mcp`);
|
||||
});
|
||||
});
|
||||
|
|
@ -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<FeatureCardProps> = ({
|
|||
|
||||
interface MCPConnectProps {
|
||||
currentServerAccessGroups?: string[];
|
||||
proxySettings?: MCPConnectProxySettings;
|
||||
}
|
||||
|
||||
const MCPConnect: React.FC<MCPConnectProps> = ({ currentServerAccessGroups = [] }) => {
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const MCPConnect: React.FC<MCPConnectProps> = ({ currentServerAccessGroups = [], proxySettings }) => {
|
||||
const proxyBaseUrl = resolveMCPConnectBaseUrl(proxySettings, getProxyBaseUrl());
|
||||
const [copiedStates, setCopiedStates] = useState<Record<string, boolean>>({});
|
||||
const [serverHeaders, setServerHeaders] = useState<Record<string, string[]>>({
|
||||
openai: [],
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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<MCPServerProps> = ({ 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<MCPServerProps> = ({ accessToken, userRole, userID })
|
|||
<MCPToolsetsTab accessToken={accessToken} userRole={userRole} />
|
||||
</TabsContent>
|
||||
<TabsContent value="connect">
|
||||
<MCPConnect />
|
||||
<MCPConnect proxySettings={proxySettings} />
|
||||
</TabsContent>
|
||||
{isAdminRole(userRole) && (
|
||||
<TabsContent value="semantic-filter">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue