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 b992313d4a8..82ed4a14810 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,6 +2,7 @@ import React, { useState, useEffect } from "react"; import { Form, Select, Button as AntdButton, Tooltip, Input, InputNumber } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { Button, TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { AUTH_TYPE, OAUTH_FLOW, @@ -46,6 +47,7 @@ const MCPServerEdit: React.FC = ({ onSuccess, availableAccessGroups, }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [costConfig, setCostConfig] = useState({}); const [tools, setTools] = useState([]); @@ -161,7 +163,7 @@ const MCPServerEdit: React.FC = ({ form.setFieldsValue({ credentials }); NotificationsManager.success( - "OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.", + t("mcpTools.mcpServerEdit.oauthAuthSuccess"), ); } }, @@ -355,7 +357,7 @@ const MCPServerEdit: React.FC = ({ : null); if (!token) { setTools([]); - setToolsError("Authenticate with this server in the Tools tab to load and configure its tools."); + setToolsError(t("mcpTools.mcpServerEdit.authenticateToLoadTools")); return; } customHeaders = buildMcpPassthroughAuthHeader(mcpServer.alias, token); @@ -373,11 +375,11 @@ const MCPServerEdit: React.FC = ({ setTools(toolsResponse.tools); } else { setTools([]); - setToolsError(toolsResponse.message || "Failed to load tools"); + setToolsError(toolsResponse.message || t("mcpTools.mcpServerEdit.failedToLoadTools")); } } catch (error) { setTools([]); - setToolsError(error instanceof Error ? error.message : "Failed to load tools"); + setToolsError(error instanceof Error ? error.message : t("mcpTools.mcpServerEdit.failedToLoadTools")); } finally { setIsLoadingTools(false); } @@ -406,7 +408,7 @@ const MCPServerEdit: React.FC = ({
{searchValue} - create new group + {t("mcpTools.mcpServerEdit.createNewGroup")}
), }); @@ -539,11 +541,11 @@ const MCPServerEdit: React.FC = ({ }; if (!stdioFields.command) { - NotificationsManager.fromBackend("Stdio configuration must include a command"); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.stdioMissingCommand")); return; } } catch { - NotificationsManager.fromBackend("Invalid JSON in stdio configuration"); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.invalidJsonStdio")); return; } } else { @@ -560,7 +562,7 @@ const MCPServerEdit: React.FC = ({ }, {}); } } catch { - NotificationsManager.fromBackend("Invalid JSON in stdio env configuration"); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.invalidJsonStdioEnv")); return; } } @@ -570,7 +572,7 @@ const MCPServerEdit: React.FC = ({ const parsedCommand = rawCommand ? String(rawCommand).trim() : ""; if (!parsedCommand) { - NotificationsManager.fromBackend("Stdio transport requires a command"); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.stdioRequiresCommand")); return; } @@ -593,7 +595,7 @@ const MCPServerEdit: React.FC = ({ try { tokenValidation = JSON.parse(rawTokenValidationJson); } catch { - NotificationsManager.fromBackend("Invalid JSON in Token Validation Rules"); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.invalidJsonTokenValidation")); return; } } @@ -711,30 +713,30 @@ const MCPServerEdit: React.FC = ({ } catch (error: unknown) { const message = error instanceof Error ? error.message : ""; NotificationsManager.fromBackend( - "MCP Server updated, but failed to persist OAuth token" + (message ? `: ${message}` : ""), + t("mcpTools.mcpServerEdit.oauthTokenPersistFailed", { message: message || "" }), ); return; } } - NotificationsManager.success("MCP Server updated successfully"); + NotificationsManager.success(t("mcpTools.mcpServerEdit.updateSuccess")); onSuccess(updated); } catch (error: any) { - NotificationsManager.fromBackend("Failed to update MCP Server" + (error?.message ? `: ${error.message}` : "")); + NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.updateFailed", { message: error?.message || "" })); } }; return ( - Server Configuration - Cost Configuration + {t("mcpTools.mcpServerEdit.tabServerConfig")} + {t("mcpTools.mcpServerEdit.tabCostConfig")}
= ({ = ({ className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500" /> - + - + {/* URL field - only for HTTP/SSE */} {isMCPTransport && ( validateMCPServerUrl(value) }, ]} > @@ -793,14 +795,14 @@ const MCPServerEdit: React.FC = ({ - OpenAPI Spec URL - + {t("mcpTools.mcpServerEdit.specUrlLabel")} + } name="spec_path" - rules={[{ required: true, message: "Please enter an OpenAPI spec URL" }]} + rules={[{ required: true, message: t("mcpTools.mcpServerEdit.specUrlRequired") }]} > = ({ {/* Authentication - for HTTP, SSE, and OpenAPI */} {!isStdioTransport && ( - + )} @@ -827,14 +829,13 @@ const MCPServerEdit: React.FC = ({ {isStdioTransport && (

- Configure the stdio transport used to launch the MCP server process. You can either fill in the fields - below or paste a JSON configuration. + {t("mcpTools.mcpServerEdit.stdioDesc")}

= ({ /> - + @@ -967,8 +968,8 @@ const MCPServerEdit: React.FC = ({ - Authorization URL Override (optional) - + {t("mcpTools.mcpServerEdit.authorizationUrlLabel")} + @@ -983,8 +984,8 @@ const MCPServerEdit: React.FC = ({ - Token URL Override (optional) - + {t("mcpTools.mcpServerEdit.tokenUrlLabel")} + @@ -999,8 +1000,8 @@ const MCPServerEdit: React.FC = ({ - Registration URL Override (optional) - + {t("mcpTools.mcpServerEdit.registrationUrlLabel")} + @@ -1017,8 +1018,8 @@ const MCPServerEdit: React.FC = ({ - Token Validation Rules (optional) - + {t("mcpTools.mcpServerEdit.tokenValidationLabel")} + @@ -1032,7 +1033,7 @@ const MCPServerEdit: React.FC = ({ JSON.parse(value); return Promise.resolve(); } catch { - return Promise.reject(new Error("Must be valid JSON")); + return Promise.reject(new Error(t("mcpTools.mcpServerEdit.tokenValidationMustBeJson"))); } }, }, @@ -1047,22 +1048,21 @@ const MCPServerEdit: React.FC = ({ - Token Storage TTL (seconds, optional) - + {t("mcpTools.mcpServerEdit.tokenStorageTtlLabel")} + } name="token_storage_ttl_seconds" > - + )}

- Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication - value. + {t("mcpTools.mcpServerEdit.oauthFlowDesc")}

{oauthError &&

{oauthError}

} {oauthStatus === "success" && oauthTokenResponse?.access_token && (

- Token fetched. Expires in {oauthTokenResponse.expires_in ?? "?"} seconds. + {t("mcpTools.mcpServerEdit.oauthTokenFetched", { seconds: oauthTokenResponse.expires_in ?? "?" })}

)}
@@ -1088,21 +1088,21 @@ const MCPServerEdit: React.FC = ({ {!isStdioTransport && isAwsSigV4AuthType && ( <>

- For MCP servers hosted on AWS Bedrock AgentCore.{" "} + {t("mcpTools.mcpServerEdit.awsSigv4Desc")}{" "} - View docs → + {t("mcpTools.mcpServerEdit.awsSigv4ViewDocs")} →

- AWS Region - + {t("mcpTools.mcpServerEdit.awsRegionLabel")} + @@ -1111,7 +1111,7 @@ const MCPServerEdit: React.FC = ({ rules={[]} > diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 09ccc70b0d0..4b192d61b44 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -3568,6 +3568,85 @@ "copyResultFailed": "Failed to copy result", "toolNameCopied": "Tool name copied to clipboard", "copyToolNameFailed": "Failed to copy tool name" + }, + "mcpServerEdit": { + "oauthAuthSuccess": "OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.", + "authenticateToLoadTools": "Authenticate with this server in the Tools tab to load and configure its tools.", + "failedToLoadTools": "Failed to load tools", + "createNewGroup": "create new group", + "stdioMissingCommand": "Stdio configuration must include a command", + "invalidJsonStdio": "Invalid JSON in stdio configuration", + "invalidJsonStdioEnv": "Invalid JSON in stdio env configuration", + "stdioRequiresCommand": "Stdio transport requires a command", + "invalidJsonTokenValidation": "Invalid JSON in Token Validation Rules", + "oauthTokenPersistFailed": "MCP Server updated, but failed to persist OAuth token{{message}}", + "updateSuccess": "MCP Server updated successfully", + "updateFailed": "Failed to update MCP Server{{message}}", + "tabServerConfig": "Server Configuration", + "tabCostConfig": "Cost Configuration", + "serverNameLabel": "MCP Server Name", + "aliasLabel": "Alias", + "transportLabel": "Transport Type", + "transportHttp": "Streamable HTTP (Recommended)", + "transportSse": "Server-Sent Events (SSE)", + "transportStdio": "Standard Input/Output (stdio)", + "transportOpenapi": "OpenAPI Spec", + "serverUrlLabel": "MCP Server URL", + "serverUrlRequired": "Please enter a server URL", + "specUrlLabel": "OpenAPI Spec URL", + "specUrlTooltip": "URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.", + "specUrlRequired": "Please enter an OpenAPI spec URL", + "authLabel": "Authentication", + "authNone": "None", + "authApiKey": "API Key", + "authBearerToken": "Bearer Token", + "authToken": "Token", + "authBasic": "Basic Auth", + "authOauth": "OAuth", + "authAwsSigv4": "AWS SigV4 (Bedrock AgentCore MCPs)", + "stdioDesc": "Configure the stdio transport used to launch the MCP server process. You can either fill in the fields below or paste a JSON configuration.", + "stdioCommandLabel": "Command", + "stdioCommandRequired": "Please enter a command for stdio transport", + "stdioArgsLabel": "Args", + "stdioArgsPlaceholder": "Add args (press enter or comma)", + "stdioEnvLabel": "Environment (JSON object)", + "stdioEnvMustBeObject": "Env must be a JSON object", + "stdioEnvInvalidJson": "Please enter valid JSON", + "authValueLabel": "Authentication Value", + "authValueTooltip": "Token, password, or header value to send with each request for the selected auth type.", + "authValueEmpty": "Authentication value cannot be empty", + "authValuePlaceholder": "Enter token or secret (leave blank to keep existing)", + "oauthClientIdLabel": "OAuth Client ID (optional)", + "oauthClientIdTooltip": "Provide only if your MCP server cannot handle dynamic client registration.", + "oauthClientIdPlaceholder": "Enter OAuth client ID (leave blank to keep existing)", + "oauthClientSecretLabel": "OAuth Client Secret (optional)", + "oauthClientSecretTooltip": "Provide only if your MCP server cannot handle dynamic client registration.", + "oauthClientSecretPlaceholder": "Enter OAuth client secret (leave blank to keep existing)", + "oauthScopesLabel": "OAuth Scopes (optional)", + "oauthScopesTooltip": "Add scopes to override the default scope list used for this MCP server.", + "oauthScopesPlaceholder": "Add scopes", + "authorizationUrlLabel": "Authorization URL Override (optional)", + "authorizationUrlTooltip": "Optional override for the authorization endpoint.", + "tokenUrlLabel": "Token URL Override (optional)", + "tokenUrlTooltip": "Optional override for the token endpoint.", + "registrationUrlLabel": "Registration URL Override (optional)", + "registrationUrlTooltip": "Optional override for the dynamic client registration endpoint.", + "tokenValidationLabel": "Token Validation Rules (optional)", + "tokenValidationTooltip": "JSON object of key-value rules checked against the OAuth token response before storing. Supports dot-notation for nested fields (e.g. {\"organization\": \"my-org\", \"team.id\": \"123\"}). Tokens that fail validation are rejected with HTTP 403.", + "tokenValidationMustBeJson": "Must be valid JSON", + "tokenStorageTtlLabel": "Token Storage TTL (seconds, optional)", + "tokenStorageTtlTooltip": "How long to cache each user's OAuth access token in Redis before evicting it (regardless of the token's own expires_in). Leave blank to derive the TTL from the token's expires_in, or fall back to the 12-hour default.", + "tokenStorageTtlPlaceholder": "e.g. 3600", + "oauthFlowDesc": "Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication value.", + "oauthWaiting": "Waiting for authorization...", + "oauthExchanging": "Exchanging authorization code...", + "oauthAuthorize": "Authorize & Fetch Token", + "oauthTokenFetched": "Token fetched. Expires in {{seconds}} seconds.", + "awsSigv4Desc": "For MCP servers hosted on AWS Bedrock AgentCore.", + "awsSigv4ViewDocs": "View docs", + "awsRegionLabel": "AWS Region", + "awsRegionTooltip": "AWS region for SigV4 signing (e.g., us-east-1)", + "awsRegionPlaceholder": "us-east-1 (leave blank to keep existing)" } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index f33a4dd1ecd..233bbd1e6b5 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -3568,6 +3568,85 @@ "copyResultFailed": "复制结果失败", "toolNameCopied": "工具名称已复制到剪贴板", "copyToolNameFailed": "复制工具名称失败" + }, + "mcpServerEdit": { + "oauthAuthSuccess": "OAuth 授权成功!请点击「更新 MCP 服务器」以保存凭据。", + "authenticateToLoadTools": "请在「工具」选项卡中对此服务器进行身份验证,以加载和配置其工具。", + "failedToLoadTools": "加载工具失败", + "createNewGroup": "新建分组", + "stdioMissingCommand": "stdio 配置必须包含命令", + "invalidJsonStdio": "stdio 配置中的 JSON 无效", + "invalidJsonStdioEnv": "stdio 环境变量配置中的 JSON 无效", + "stdioRequiresCommand": "stdio 传输需要一个命令", + "invalidJsonTokenValidation": "Token 验证规则中的 JSON 无效", + "oauthTokenPersistFailed": "MCP 服务器已更新,但 OAuth Token 持久化失败{{message}}", + "updateSuccess": "MCP 服务器更新成功", + "updateFailed": "MCP 服务器更新失败{{message}}", + "tabServerConfig": "服务器配置", + "tabCostConfig": "成本配置", + "serverNameLabel": "MCP 服务器名称", + "aliasLabel": "别名", + "transportLabel": "传输类型", + "transportHttp": "Streamable HTTP(推荐)", + "transportSse": "Server-Sent Events(SSE)", + "transportStdio": "标准输入/输出(stdio)", + "transportOpenapi": "OpenAPI Spec", + "serverUrlLabel": "MCP 服务器 URL", + "serverUrlRequired": "请输入服务器 URL", + "specUrlLabel": "OpenAPI Spec URL", + "specUrlTooltip": "OpenAPI 规范的 URL(JSON 或 YAML 格式)。MCP 工具将根据规范中定义的 API 端点自动生成。", + "specUrlRequired": "请输入 OpenAPI Spec URL", + "authLabel": "身份验证", + "authNone": "无", + "authApiKey": "API 密钥", + "authBearerToken": "Bearer Token", + "authToken": "Token", + "authBasic": "Basic Auth", + "authOauth": "OAuth", + "authAwsSigv4": "AWS SigV4(Bedrock AgentCore MCPs)", + "stdioDesc": "配置用于启动 MCP 服务器进程的 stdio 传输。您可以填写以下字段或粘贴 JSON 配置。", + "stdioCommandLabel": "命令", + "stdioCommandRequired": "请输入 stdio 传输的命令", + "stdioArgsLabel": "参数", + "stdioArgsPlaceholder": "添加参数(按回车或逗号分隔)", + "stdioEnvLabel": "环境变量(JSON 对象)", + "stdioEnvMustBeObject": "环境变量必须是 JSON 对象", + "stdioEnvInvalidJson": "请输入有效的 JSON", + "authValueLabel": "身份验证值", + "authValueTooltip": "针对所选身份验证类型,随每次请求发送的 Token、密码或请求头值。", + "authValueEmpty": "身份验证值不能为空", + "authValuePlaceholder": "输入 Token 或密钥(留空则保留现有值)", + "oauthClientIdLabel": "OAuth Client ID(可选)", + "oauthClientIdTooltip": "仅在您的 MCP 服务器无法处理动态客户端注册时提供。", + "oauthClientIdPlaceholder": "输入 OAuth Client ID(留空则保留现有值)", + "oauthClientSecretLabel": "OAuth Client Secret(可选)", + "oauthClientSecretTooltip": "仅在您的 MCP 服务器无法处理动态客户端注册时提供。", + "oauthClientSecretPlaceholder": "输入 OAuth Client Secret(留空则保留现有值)", + "oauthScopesLabel": "OAuth Scopes(可选)", + "oauthScopesTooltip": "添加 Scope 以覆盖此 MCP 服务器默认使用的 Scope 列表。", + "oauthScopesPlaceholder": "添加 Scope", + "authorizationUrlLabel": "授权 URL 覆盖(可选)", + "authorizationUrlTooltip": "授权端点的可选覆盖地址。", + "tokenUrlLabel": "Token URL 覆盖(可选)", + "tokenUrlTooltip": "Token 端点的可选覆盖地址。", + "registrationUrlLabel": "注册 URL 覆盖(可选)", + "registrationUrlTooltip": "动态客户端注册端点的可选覆盖地址。", + "tokenValidationLabel": "Token 验证规则(可选)", + "tokenValidationTooltip": "在存储前与 OAuth Token 响应进行核对的键值规则 JSON 对象。支持点分隔符访问嵌套字段(如 {\"organization\": \"my-org\", \"team.id\": \"123\"})。验证不通过的 Token 将被 HTTP 403 拒绝。", + "tokenValidationMustBeJson": "必须是有效的 JSON", + "tokenStorageTtlLabel": "Token 存储 TTL(秒,可选)", + "tokenStorageTtlTooltip": "在 Redis 中缓存每个用户 OAuth 访问 Token 的时长(与 Token 自身的 expires_in 无关)。留空则从 Token 的 expires_in 推导 TTL,或回退到默认的 12 小时。", + "tokenStorageTtlPlaceholder": "例如 3600", + "oauthFlowDesc": "使用 OAuth 获取新的访问 Token,并将其作为身份验证值临时保存在会话中。", + "oauthWaiting": "等待授权中……", + "oauthExchanging": "正在交换授权码……", + "oauthAuthorize": "授权并获取 Token", + "oauthTokenFetched": "Token 已获取,将在 {{seconds}} 秒后过期。", + "awsSigv4Desc": "适用于托管在 AWS Bedrock AgentCore 上的 MCP 服务器。", + "awsSigv4ViewDocs": "查看文档", + "awsRegionLabel": "AWS 区域", + "awsRegionTooltip": "用于 SigV4 签名的 AWS 区域(例如 us-east-1)", + "awsRegionPlaceholder": "us-east-1(留空则保留现有值)" } } }