-
Cost Summary:
+
{t("mcpServers.serverCostDisplay.summaryTitle")}
{hasDefaultCost &&
costConfig?.default_cost_per_query !== undefined &&
costConfig?.default_cost_per_query !== null && (
- • Default cost: ${costConfig.default_cost_per_query.toFixed(4)} per query
+ {t("mcpServers.serverCostDisplay.summaryDefaultCost", {
+ cost: costConfig.default_cost_per_query.toFixed(4),
+ })}
)}
{hasToolCosts && costConfig?.tool_name_to_cost_per_query && (
- • {Object.keys(costConfig.tool_name_to_cost_per_query).length} tool(s) with custom pricing
+ {t("mcpServers.serverCostDisplay.summaryToolCount", {
+ toolCount: Object.keys(costConfig.tool_name_to_cost_per_query).length,
+ })}
)}
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 57985fd8cbb..ee27d23bf8e 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
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
+import { useTranslation } from "react-i18next";
import { MultiSelect } from "@/components/shared/MultiSelect";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { SimpleTooltip } from "@/components/ui/tooltip";
@@ -53,7 +54,7 @@ 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 { DUPLICATE_IDENTIFIER_MESSAGE_KEY, findDuplicateMcpServer, mcpSubmitErrorReason } from "./duplicateServerCheck";
import { toast } from "@/lib/toast";
import { getEditToolPreview } from "./editToolPreview";
import { useMcpOAuthFlow, type McpDcrCredentials } from "@/hooks/useMcpOAuthFlow";
@@ -107,6 +108,7 @@ const MCPServerEdit: React.FC
= ({
existingServers,
stdioEnabled = true,
}) => {
+ const { t } = useTranslation();
const initialStaticHeaders = React.useMemo(() => {
if (!mcpServer.static_headers) {
return [];
@@ -314,9 +316,7 @@ const MCPServerEdit: React.FC = ({
token_type: token.token_type,
};
setToken(mcpServer.server_id, browserHeldToken, userID);
- toast.success(
- "Token held for this browser session. Tools can now be loaded and configured; the token is not saved to LiteLLM.",
- );
+ toast.success(t("mcpServers.serverEdit.toasts.browserTokenHeld"));
return;
}
@@ -336,7 +336,7 @@ const MCPServerEdit: React.FC = ({
// Re-capture after writing credentials so the token is not invalidated by its own credential write.
authorizedIdentityRef.current = getOAuthAuthorizationIdentity(allFieldsValue(form));
- toast.success("OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.");
+ toast.success(t("mcpServers.serverEdit.toasts.oauthAuthorized"));
},
onBeforeRedirect: persistEditUiState,
flowSource: "edit",
@@ -460,7 +460,7 @@ const MCPServerEdit: React.FC = ({
}
}, [mcpServer]);
- const toolPreview = getEditToolPreview(allFieldsValue(form), initialValues);
+ const toolPreview = getEditToolPreview(allFieldsValue(form), initialValues, t);
const toolPreviewKey = JSON.stringify(toolPreview);
useEffect(() => {
@@ -470,7 +470,7 @@ const MCPServerEdit: React.FC = ({
setIsLoadingTools(false);
if (!accessToken || !mcpServer.server_id) return;
if (toolPreview.kind === "incomplete") {
- setToolsError(toolPreview.message ?? "Complete the URL, authentication, and header settings to load tools.");
+ setToolsError(toolPreview.message ?? t("mcpServers.serverEdit.tools.incompleteSettings"));
return;
}
setIsLoadingTools(true);
@@ -584,12 +584,12 @@ const MCPServerEdit: React.FC = ({
setTools(toolsResponse.tools);
} else {
setTools([]);
- setToolsError(toolsResponse.message || "Failed to load tools");
+ setToolsError(toolsResponse.message || t("mcpServers.serverEdit.tools.loadFailed"));
}
} catch (error) {
if (!isCurrent()) return true;
setTools([]);
- setToolsError(error instanceof Error ? error.message : "Failed to load tools");
+ setToolsError(error instanceof Error ? error.message : t("mcpServers.serverEdit.tools.loadFailed"));
} finally {
if (isCurrent()) setIsLoadingTools(false);
}
@@ -628,8 +628,8 @@ const MCPServerEdit: React.FC = ({
setTools([]);
setToolsError(
isBrowserHeldTokenMode
- ? "Authorize with the upstream (browser-only, in the Authentication section) to load and configure this server's tools."
- : "Authenticate with this server in the Tools tab to load and configure its tools.",
+ ? t("mcpServers.serverEdit.tools.authorizeUpstream")
+ : t("mcpServers.serverEdit.tools.authenticateInToolsTab"),
);
return;
}
@@ -656,12 +656,12 @@ const MCPServerEdit: React.FC = ({
setTools(toolsResponse.tools);
} else {
setTools([]);
- setToolsError(toolsResponse.message || "Failed to load tools");
+ setToolsError(toolsResponse.message || t("mcpServers.serverEdit.tools.loadFailed"));
}
} catch (error) {
if (!isCurrent()) return;
setTools([]);
- setToolsError(error instanceof Error ? error.message : "Failed to load tools");
+ setToolsError(error instanceof Error ? error.message : t("mcpServers.serverEdit.tools.loadFailed"));
} finally {
if (isCurrent()) setIsLoadingTools(false);
}
@@ -751,8 +751,8 @@ const MCPServerEdit: React.FC = ({
mcpServer.server_id,
);
if (duplicate) {
- form.setError(duplicate.field, { type: "duplicate", message: DUPLICATE_IDENTIFIER_MESSAGE });
- toast.fromError(DUPLICATE_IDENTIFIER_MESSAGE);
+ form.setError(duplicate.field, { type: "duplicate", message: t(DUPLICATE_IDENTIFIER_MESSAGE_KEY) });
+ toast.fromError(t(DUPLICATE_IDENTIFIER_MESSAGE_KEY));
return;
}
try {
@@ -770,7 +770,7 @@ const MCPServerEdit: React.FC = ({
};
const built = buildEditServerPayload(values, uiState);
if (built.kind !== "ok") {
- toast.fromError(editPayloadErrorMessage(built));
+ toast.fromError(editPayloadErrorMessage(built, t));
return;
}
const payload = built.payload;
@@ -807,17 +807,25 @@ const MCPServerEdit: React.FC = ({
}
} catch (error: unknown) {
const message = error instanceof Error ? error.message : "";
- toast.fromError("MCP Server updated, but failed to persist OAuth token" + (message ? `: ${message}` : ""));
+ toast.fromError(
+ message
+ ? t("mcpServers.serverEdit.toasts.persistTokenFailedWithReason", { reason: message })
+ : t("mcpServers.serverEdit.toasts.persistTokenFailed"),
+ );
return;
}
}
- toast.success("MCP Server updated successfully");
+ toast.success(t("mcpServers.serverEdit.toasts.updated"));
setAppMayNotMatchUpstream(false);
onSuccess(updated);
} catch (error: any) {
const reason = mcpSubmitErrorReason(error);
- toast.fromError("Failed to update MCP Server" + (reason ? `: ${reason}` : ""));
+ toast.fromError(
+ reason
+ ? t("mcpServers.serverEdit.toasts.updateFailedWithReason", { reason })
+ : t("mcpServers.serverEdit.toasts.updateFailed"),
+ );
}
};
@@ -825,10 +833,10 @@ const MCPServerEdit: React.FC = ({
- Server Configuration
+ {t("mcpServers.serverEdit.tabs.server")}
- Cost Configuration
+ {t("mcpServers.serverEdit.tabs.cost")}
@@ -836,7 +844,7 @@ const MCPServerEdit: React.FC
= ({