From 2b698e2a9772cc5acdb6e8aa9a259acfb32ea2ee Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Thu, 19 Feb 2026 12:14:24 -0800 Subject: [PATCH] add OpenAPI transport support to edit form with auto-detection --- .../components/mcp_tools/mcp_server_edit.tsx | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx index 29bcb6548ab..88f8a737af2 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { Form, Select, Button as AntdButton, Tooltip, Input } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { Button, TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; -import { AUTH_TYPE, OAUTH_FLOW, MCPServer, MCPServerCostInfo } from "./types"; +import { AUTH_TYPE, OAUTH_FLOW, MCPServer, MCPServerCostInfo, TRANSPORT } from "./types"; import { updateMCPServer, testMCPToolsListRequest } from "../networking"; import MCPServerCostConfig from "./mcp_server_cost_config"; import MCPPermissionManagement from "./MCPPermissionManagement"; @@ -42,6 +42,8 @@ const MCPServerEdit: React.FC = ({ const authType = Form.useWatch("auth_type", form) as string | undefined; const transportType = Form.useWatch("transport", form) as string | undefined; const isStdioTransport = transportType === "stdio"; + const isOpenAPITransport = transportType === TRANSPORT.OPENAPI; + const isMCPTransport = !isStdioTransport && !isOpenAPITransport; const shouldShowAuthValueField = authType ? AUTH_TYPES_REQUIRING_AUTH_VALUE.includes(authType) : false; const isOAuthAuthType = authType === AUTH_TYPE.OAUTH2; const oauthFlowTypeValue = Form.useWatch("oauth_flow_type", form) as string | undefined; @@ -142,13 +144,22 @@ const MCPServerEdit: React.FC = ({ }, [mcpServer.env]); + // If server has spec_path and no url, show it as "openapi" transport in the UI + const effectiveTransport = React.useMemo(() => { + if (mcpServer.spec_path && !mcpServer.url && mcpServer.transport !== "stdio") { + return TRANSPORT.OPENAPI; + } + return mcpServer.transport; + }, [mcpServer]); + const initialValues = React.useMemo( () => ({ ...mcpServer, + transport: effectiveTransport, static_headers: initialStaticHeaders, oauth_flow_type: mcpServer.token_url ? OAUTH_FLOW.M2M : OAUTH_FLOW.INTERACTIVE, }), - [mcpServer, initialStaticHeaders, initialEnvJson], + [mcpServer, effectiveTransport, initialStaticHeaders, initialEnvJson], ); // Initialize cost config from existing server data @@ -231,8 +242,8 @@ const MCPServerEdit: React.FC = ({ const fetchTools = async () => { if (!accessToken) return; - // HTTP/SSE requires a URL; stdio does not. - if (mcpServer.transport !== "stdio" && !mcpServer.url) return; + // HTTP/SSE requires a URL (unless spec_path is set); stdio does not. + if (mcpServer.transport !== "stdio" && !mcpServer.url && !mcpServer.spec_path) return; const isM2M = mcpServer.auth_type === AUTH_TYPE.OAUTH2 && !!mcpServer.token_url; if (mcpServer.auth_type === AUTH_TYPE.OAUTH2 && !isM2M && !oauthAccessToken) { @@ -311,14 +322,24 @@ const MCPServerEdit: React.FC = ({ if (value === "stdio") { form.setFieldsValue({ url: undefined, + spec_path: undefined, auth_type: undefined, credentials: undefined, authorization_url: undefined, token_url: undefined, registration_url: undefined, }); + } else if (value === TRANSPORT.OPENAPI) { + form.setFieldsValue({ + url: undefined, + command: undefined, + args: undefined, + env_json: undefined, + stdio_config: undefined, + }); } else { form.setFieldsValue({ + spec_path: undefined, command: undefined, args: undefined, env_json: undefined, @@ -457,6 +478,11 @@ const MCPServerEdit: React.FC = ({ } } + // Map "openapi" transport to "http" for the backend + if (restValues.transport === TRANSPORT.OPENAPI) { + restValues.transport = "http"; + } + // Prepare the payload with cost configuration and permission fields const mcpInfoServerName = restValues.server_name || @@ -543,14 +569,15 @@ const MCPServerEdit: React.FC = ({ - {/* URL/Auth fields are only applicable for HTTP/SSE */} - {!isStdioTransport && ( + {/* URL field - only for HTTP/SSE */} + {isMCPTransport && ( = ({ )} - {!isStdioTransport && ( + {/* OpenAPI Spec URL - only for OpenAPI transport */} + {isOpenAPITransport && ( - OpenAPI Spec URL (optional) - + OpenAPI Spec URL + } name="spec_path" + rules={[{ required: true, message: "Please enter an OpenAPI spec URL" }]} > )} + {/* Authentication - for HTTP, SSE, and OpenAPI */} {!isStdioTransport && (