diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx index 65656a053ce..3b3269b87cc 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx @@ -396,6 +396,46 @@ describe("CreateMCPServer", () => { expect(payload.credentials).toEqual({ auth_value: "my-secret-key" }); }); + it("creates an Authorization (raw header) server with the header value sent verbatim", async () => { + await selectHttpTransport(); + + fireEvent.change(getServerNameInput(), { target: { value: "Raw_Auth_Server" } }); + fireEvent.change(screen.getByPlaceholderText("https://your-mcp-server.com"), { + target: { value: "https://example.com/mcp" }, + }); + + await selectOption("Authentication", "Authorization (raw header)"); + + fireEvent.change(await screen.findByPlaceholderText("Enter token or secret"), { + target: { value: "ApiKey raw-key-123" }, + }); + + vi.mocked(networking.createMCPServer).mockResolvedValue({ + server_id: "new-server-2", + server_name: "Raw_Auth_Server", + alias: "Raw_Auth_Server", + url: "https://example.com/mcp", + transport: "http", + auth_type: "authorization", + created_at: "2024-01-01T00:00:00Z", + created_by: "user-1", + updated_at: "2024-01-01T00:00:00Z", + updated_by: "user-1", + }); + + await act(async () => { + fireEvent.click(screen.getByRole("button", { name: "Add MCP Server" })); + }); + + await waitFor(() => { + expect(networking.createMCPServer).toHaveBeenCalledTimes(1); + }); + + const [, payload] = vi.mocked(networking.createMCPServer).mock.calls[0]; + expect(payload.auth_type).toBe("authorization"); + expect(payload.credentials).toEqual({ auth_value: "ApiKey raw-key-123" }); + }); + it("does not write the browser-authorized token into form.credentials for true_passthrough", async () => { await selectHttpTransport(); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createServerPayload.ts b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createServerPayload.ts index 30c4c502c42..5536b4b1bc4 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createServerPayload.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createServerPayload.ts @@ -15,6 +15,7 @@ export const AUTH_TYPES_REQUIRING_AUTH_VALUE = [ AUTH_TYPE.BEARER_TOKEN, AUTH_TYPE.TOKEN, AUTH_TYPE.BASIC, + AUTH_TYPE.AUTHORIZATION, ]; export const AUTH_TYPES_REQUIRING_CREDENTIALS = [ diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/editServerPayload.differential.cases.ts b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/editServerPayload.differential.cases.ts index 4219113918b..e9f32b5c4db 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/editServerPayload.differential.cases.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/editServerPayload.differential.cases.ts @@ -82,6 +82,7 @@ const AUTH_TYPES = [ "bearer_token", "token", "basic", + "authorization", "oauth2", "oauth2_token_exchange", "oauth2_id_jag", diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.integration.test.tsx index 9f91c06e9e5..15b09961a84 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.integration.test.tsx @@ -135,6 +135,11 @@ const CASES: readonly Case[] = [ server: { ...BASE, auth_type: "basic", credentials: CREDS }, expected: { ...EXPECTED_BASE, auth_type: "basic", credentials: { auth_value: "secret-value" } }, }, + { + label: "authorization sends only auth_value under credentials", + server: { ...BASE, auth_type: "authorization", credentials: CREDS }, + expected: { ...EXPECTED_BASE, auth_type: "authorization", credentials: { auth_value: "secret-value" } }, + }, { label: "oauth2 m2m mounts token_url and omits the interactive endpoints entirely", server: { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx index f35e3ab3d3a..57985fd8cbb 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx @@ -51,6 +51,7 @@ import OAuthFormFields from "./OAuthFormFields"; import MCPLogoSelector from "./MCPLogoSelector"; import EnvVarsSection from "./EnvVarsSection"; import { validateMCPServerUrl, validateMCPServerName, normalizeToolOverrideMap } from "./utils"; +import { AUTH_TYPES_REQUIRING_AUTH_VALUE } from "./createServerPayload"; import { EditServerFormValues, buildEditServerPayload, editPayloadErrorMessage } from "./editServerPayload"; import { DUPLICATE_IDENTIFIER_MESSAGE, findDuplicateMcpServer, mcpSubmitErrorReason } from "./duplicateServerCheck"; import { toast } from "@/lib/toast"; @@ -94,7 +95,6 @@ interface MCPServerEditProps { stdioEnabled?: boolean; } -const AUTH_TYPES_REQUIRING_AUTH_VALUE = [AUTH_TYPE.API_KEY, AUTH_TYPE.BEARER_TOKEN, AUTH_TYPE.TOKEN, AUTH_TYPE.BASIC]; export const EDIT_OAUTH_UI_STATE_KEY = "litellm-mcp-oauth-edit-state"; const MCPServerEdit: React.FC = ({ diff --git a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx index 22fd64f10d8..61c81c030c5 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx @@ -38,6 +38,7 @@ export const AUTH_TYPE = { BEARER_TOKEN: "bearer_token", TOKEN: "token", BASIC: "basic", + AUTHORIZATION: "authorization", OAUTH2: "oauth2", OAUTH2_TOKEN_EXCHANGE: "oauth2_token_exchange", OAUTH2_ID_JAG: "oauth2_id_jag", @@ -52,6 +53,7 @@ export const AUTH_TYPE_ITEMS = [ { value: AUTH_TYPE.BEARER_TOKEN, label: "Bearer Token" }, { value: AUTH_TYPE.TOKEN, label: "Token" }, { value: AUTH_TYPE.BASIC, label: "Basic Auth" }, + { value: AUTH_TYPE.AUTHORIZATION, label: "Authorization (raw header)" }, { value: AUTH_TYPE.OAUTH2, label: "OAuth" }, { value: AUTH_TYPE.OAUTH2_TOKEN_EXCHANGE, label: "OAuth Token Exchange (OBO)" }, { value: AUTH_TYPE.OAUTH2_ID_JAG, label: "ID-JAG (Okta Cross App Access)" },