mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): i18n for MCP server edit form
This commit is contained in:
parent
4faf76ef3f
commit
359cc2920d
3 changed files with 239 additions and 81 deletions
|
|
@ -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<MCPServerEditProps> = ({
|
|||
onSuccess,
|
||||
availableAccessGroups,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const [costConfig, setCostConfig] = useState<MCPServerCostInfo>({});
|
||||
const [tools, setTools] = useState<any[]>([]);
|
||||
|
|
@ -161,7 +163,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
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<MCPServerEditProps> = ({
|
|||
: 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<MCPServerEditProps> = ({
|
|||
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<MCPServerEditProps> = ({
|
|||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
|
||||
<span className="font-medium">{searchValue}</span>
|
||||
<span className="text-gray-400 text-xs ml-1">create new group</span>
|
||||
<span className="text-gray-400 text-xs ml-1">{t("mcpTools.mcpServerEdit.createNewGroup")}</span>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
|
@ -539,11 +541,11 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
};
|
||||
|
||||
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<MCPServerEditProps> = ({
|
|||
}, {});
|
||||
}
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Invalid JSON in stdio env configuration");
|
||||
NotificationsManager.fromBackend(t("mcpTools.mcpServerEdit.invalidJsonStdioEnv"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -570,7 +572,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
|
||||
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<MCPServerEditProps> = ({
|
|||
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<MCPServerEditProps> = ({
|
|||
} 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 (
|
||||
<TabGroup>
|
||||
<TabList className="grid w-full grid-cols-2">
|
||||
<Tab>Server Configuration</Tab>
|
||||
<Tab>Cost Configuration</Tab>
|
||||
<Tab>{t("mcpTools.mcpServerEdit.tabServerConfig")}</Tab>
|
||||
<Tab>{t("mcpTools.mcpServerEdit.tabCostConfig")}</Tab>
|
||||
</TabList>
|
||||
<TabPanels className="mt-6">
|
||||
<TabPanel>
|
||||
<Form form={form} onFinish={handleSave} initialValues={initialValues} layout="vertical">
|
||||
<Form.Item
|
||||
label="MCP Server Name"
|
||||
label={t("mcpTools.mcpServerEdit.serverNameLabel")}
|
||||
name="server_name"
|
||||
rules={[
|
||||
{
|
||||
|
|
@ -745,7 +747,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Input className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Alias"
|
||||
label={t("mcpTools.mcpServerEdit.aliasLabel")}
|
||||
name="alias"
|
||||
rules={[
|
||||
{
|
||||
|
|
@ -758,26 +760,26 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Description" name="description">
|
||||
<Form.Item label={t("common.description")} name="description">
|
||||
<Input className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500" />
|
||||
</Form.Item>
|
||||
<MCPLogoSelector value={logoUrl} onChange={setLogoUrl} />
|
||||
<Form.Item label="Transport Type" name="transport" rules={[{ required: true }]}>
|
||||
<Form.Item label={t("mcpTools.mcpServerEdit.transportLabel")} name="transport" rules={[{ required: true }]}>
|
||||
<Select onChange={handleTransportChange}>
|
||||
<Select.Option value="http">Streamable HTTP (Recommended)</Select.Option>
|
||||
<Select.Option value="sse">Server-Sent Events (SSE)</Select.Option>
|
||||
<Select.Option value="stdio">Standard Input/Output (stdio)</Select.Option>
|
||||
<Select.Option value={TRANSPORT.OPENAPI}>OpenAPI Spec</Select.Option>
|
||||
<Select.Option value="http">{t("mcpTools.mcpServerEdit.transportHttp")}</Select.Option>
|
||||
<Select.Option value="sse">{t("mcpTools.mcpServerEdit.transportSse")}</Select.Option>
|
||||
<Select.Option value="stdio">{t("mcpTools.mcpServerEdit.transportStdio")}</Select.Option>
|
||||
<Select.Option value={TRANSPORT.OPENAPI}>{t("mcpTools.mcpServerEdit.transportOpenapi")}</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
{/* URL field - only for HTTP/SSE */}
|
||||
{isMCPTransport && (
|
||||
<Form.Item
|
||||
label="MCP Server URL"
|
||||
label={t("mcpTools.mcpServerEdit.serverUrlLabel")}
|
||||
name="url"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter a server URL" },
|
||||
{ required: true, message: t("mcpTools.mcpServerEdit.serverUrlRequired") },
|
||||
{ validator: (_, value) => validateMCPServerUrl(value) },
|
||||
]}
|
||||
>
|
||||
|
|
@ -793,14 +795,14 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
OpenAPI Spec URL
|
||||
<Tooltip title="URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.">
|
||||
{t("mcpTools.mcpServerEdit.specUrlLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.specUrlTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
name="spec_path"
|
||||
rules={[{ required: true, message: "Please enter an OpenAPI spec URL" }]}
|
||||
rules={[{ required: true, message: t("mcpTools.mcpServerEdit.specUrlRequired") }]}
|
||||
>
|
||||
<Input
|
||||
placeholder="https://petstore3.swagger.io/api/v3/openapi.json"
|
||||
|
|
@ -811,15 +813,15 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
|
||||
{/* Authentication - for HTTP, SSE, and OpenAPI */}
|
||||
{!isStdioTransport && (
|
||||
<Form.Item label="Authentication" name="auth_type" rules={[{ required: true }]}>
|
||||
<Form.Item label={t("mcpTools.mcpServerEdit.authLabel")} name="auth_type" rules={[{ required: true }]}>
|
||||
<Select>
|
||||
<Select.Option value="none">None</Select.Option>
|
||||
<Select.Option value="api_key">API Key</Select.Option>
|
||||
<Select.Option value="bearer_token">Bearer Token</Select.Option>
|
||||
<Select.Option value="token">Token</Select.Option>
|
||||
<Select.Option value="basic">Basic Auth</Select.Option>
|
||||
<Select.Option value="oauth2">OAuth</Select.Option>
|
||||
<Select.Option value="aws_sigv4">AWS SigV4 (Bedrock AgentCore MCPs)</Select.Option>
|
||||
<Select.Option value="none">{t("mcpTools.mcpServerEdit.authNone")}</Select.Option>
|
||||
<Select.Option value="api_key">{t("mcpTools.mcpServerEdit.authApiKey")}</Select.Option>
|
||||
<Select.Option value="bearer_token">{t("mcpTools.mcpServerEdit.authBearerToken")}</Select.Option>
|
||||
<Select.Option value="token">{t("mcpTools.mcpServerEdit.authToken")}</Select.Option>
|
||||
<Select.Option value="basic">{t("mcpTools.mcpServerEdit.authBasic")}</Select.Option>
|
||||
<Select.Option value="oauth2">{t("mcpTools.mcpServerEdit.authOauth")}</Select.Option>
|
||||
<Select.Option value="aws_sigv4">{t("mcpTools.mcpServerEdit.authAwsSigv4")}</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
)}
|
||||
|
|
@ -827,14 +829,13 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
{isStdioTransport && (
|
||||
<div className="rounded-lg border border-gray-200 p-4 space-y-4">
|
||||
<p className="text-sm text-gray-600">
|
||||
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")}
|
||||
</p>
|
||||
|
||||
<Form.Item
|
||||
label="Command"
|
||||
label={t("mcpTools.mcpServerEdit.stdioCommandLabel")}
|
||||
name="command"
|
||||
rules={[{ required: true, message: "Please enter a command for stdio transport" }]}
|
||||
rules={[{ required: true, message: t("mcpTools.mcpServerEdit.stdioCommandRequired") }]}
|
||||
>
|
||||
<Input
|
||||
placeholder="e.g., npx"
|
||||
|
|
@ -842,18 +843,18 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Args" name="args">
|
||||
<Form.Item label={t("mcpTools.mcpServerEdit.stdioArgsLabel")} name="args">
|
||||
<Select
|
||||
mode="tags"
|
||||
size="large"
|
||||
tokenSeparators={[","]}
|
||||
placeholder="Add args (press enter or comma)"
|
||||
placeholder={t("mcpTools.mcpServerEdit.stdioArgsPlaceholder")}
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Environment (JSON object)"
|
||||
label={t("mcpTools.mcpServerEdit.stdioEnvLabel")}
|
||||
name="env_json"
|
||||
rules={[
|
||||
{
|
||||
|
|
@ -864,9 +865,9 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error("Env must be a JSON object"));
|
||||
return Promise.reject(new Error(t("mcpTools.mcpServerEdit.stdioEnvMustBeObject")));
|
||||
} catch {
|
||||
return Promise.reject(new Error("Please enter valid JSON"));
|
||||
return Promise.reject(new Error(t("mcpTools.mcpServerEdit.stdioEnvInvalidJson")));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -888,8 +889,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Authentication Value
|
||||
<Tooltip title="Token, password, or header value to send with each request for the selected auth type.">
|
||||
{t("mcpTools.mcpServerEdit.authValueLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.authValueTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -899,13 +900,13 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
{
|
||||
validator: (_, value) =>
|
||||
value && typeof value === "string" && value.trim() === ""
|
||||
? Promise.reject(new Error("Authentication value cannot be empty"))
|
||||
? Promise.reject(new Error(t("mcpTools.mcpServerEdit.authValueEmpty")))
|
||||
: Promise.resolve(),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder="Enter token or secret (leave blank to keep existing)"
|
||||
placeholder={t("mcpTools.mcpServerEdit.authValuePlaceholder")}
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
|
@ -916,8 +917,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
OAuth Client ID (optional)
|
||||
<Tooltip title="Provide only if your MCP server cannot handle dynamic client registration.">
|
||||
{t("mcpTools.mcpServerEdit.oauthClientIdLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.oauthClientIdTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -925,15 +926,15 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
name={["credentials", "client_id"]}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder="Enter OAuth client ID (leave blank to keep existing)"
|
||||
placeholder={t("mcpTools.mcpServerEdit.oauthClientIdPlaceholder")}
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
OAuth Client Secret (optional)
|
||||
<Tooltip title="Provide only if your MCP server cannot handle dynamic client registration.">
|
||||
{t("mcpTools.mcpServerEdit.oauthClientSecretLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.oauthClientSecretTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -941,15 +942,15 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
name={["credentials", "client_secret"]}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder="Enter OAuth client secret (leave blank to keep existing)"
|
||||
placeholder={t("mcpTools.mcpServerEdit.oauthClientSecretPlaceholder")}
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
OAuth Scopes (optional)
|
||||
<Tooltip title="Add scopes to override the default scope list used for this MCP server.">
|
||||
{t("mcpTools.mcpServerEdit.oauthScopesLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.oauthScopesTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -959,7 +960,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Select
|
||||
mode="tags"
|
||||
tokenSeparators={[","]}
|
||||
placeholder="Add scopes"
|
||||
placeholder={t("mcpTools.mcpServerEdit.oauthScopesPlaceholder")}
|
||||
className="rounded-lg"
|
||||
size="large"
|
||||
/>
|
||||
|
|
@ -967,8 +968,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Authorization URL Override (optional)
|
||||
<Tooltip title="Optional override for the authorization endpoint.">
|
||||
{t("mcpTools.mcpServerEdit.authorizationUrlLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.authorizationUrlTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -983,8 +984,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Token URL Override (optional)
|
||||
<Tooltip title="Optional override for the token endpoint.">
|
||||
{t("mcpTools.mcpServerEdit.tokenUrlLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.tokenUrlTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -999,8 +1000,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Registration URL Override (optional)
|
||||
<Tooltip title="Optional override for the dynamic client registration endpoint.">
|
||||
{t("mcpTools.mcpServerEdit.registrationUrlLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.registrationUrlTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -1017,8 +1018,8 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Token Validation Rules (optional)
|
||||
<Tooltip title='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.'>
|
||||
{t("mcpTools.mcpServerEdit.tokenValidationLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.tokenValidationTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -1032,7 +1033,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
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<MCPServerEditProps> = ({
|
|||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Token Storage TTL (seconds, optional)
|
||||
<Tooltip title="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.">
|
||||
{t("mcpTools.mcpServerEdit.tokenStorageTtlLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.tokenStorageTtlTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
name="token_storage_ttl_seconds"
|
||||
>
|
||||
<InputNumber min={1} placeholder="e.g. 3600" style={{ width: "100%" }} className="rounded-lg" />
|
||||
<InputNumber min={1} placeholder={t("mcpTools.mcpServerEdit.tokenStorageTtlPlaceholder")} style={{ width: "100%" }} className="rounded-lg" />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
<div className="rounded-lg border border-dashed border-gray-300 p-4 space-y-2">
|
||||
<p className="text-sm text-gray-600">
|
||||
Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication
|
||||
value.
|
||||
{t("mcpTools.mcpServerEdit.oauthFlowDesc")}
|
||||
</p>
|
||||
<Button
|
||||
variant="secondary"
|
||||
|
|
@ -1070,15 +1070,15 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
disabled={oauthStatus === "authorizing" || oauthStatus === "exchanging"}
|
||||
>
|
||||
{oauthStatus === "authorizing"
|
||||
? "Waiting for authorization..."
|
||||
? t("mcpTools.mcpServerEdit.oauthWaiting")
|
||||
: oauthStatus === "exchanging"
|
||||
? "Exchanging authorization code..."
|
||||
: "Authorize & Fetch Token"}
|
||||
? t("mcpTools.mcpServerEdit.oauthExchanging")
|
||||
: t("mcpTools.mcpServerEdit.oauthAuthorize")}
|
||||
</Button>
|
||||
{oauthError && <p className="text-sm text-red-500">{oauthError}</p>}
|
||||
{oauthStatus === "success" && oauthTokenResponse?.access_token && (
|
||||
<p className="text-sm text-green-600">
|
||||
Token fetched. Expires in {oauthTokenResponse.expires_in ?? "?"} seconds.
|
||||
{t("mcpTools.mcpServerEdit.oauthTokenFetched", { seconds: oauthTokenResponse.expires_in ?? "?" })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -1088,21 +1088,21 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
{!isStdioTransport && isAwsSigV4AuthType && (
|
||||
<>
|
||||
<p className="text-sm text-gray-500 mb-2">
|
||||
For MCP servers hosted on AWS Bedrock AgentCore.{" "}
|
||||
{t("mcpTools.mcpServerEdit.awsSigv4Desc")}{" "}
|
||||
<a
|
||||
href="https://docs.litellm.ai/docs/mcp_aws_sigv4"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-700"
|
||||
>
|
||||
View docs →
|
||||
{t("mcpTools.mcpServerEdit.awsSigv4ViewDocs")} →
|
||||
</a>
|
||||
</p>
|
||||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
AWS Region
|
||||
<Tooltip title="AWS region for SigV4 signing (e.g., us-east-1)">
|
||||
{t("mcpTools.mcpServerEdit.awsRegionLabel")}
|
||||
<Tooltip title={t("mcpTools.mcpServerEdit.awsRegionTooltip")}>
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -1111,7 +1111,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
rules={[]}
|
||||
>
|
||||
<Input
|
||||
placeholder="us-east-1 (leave blank to keep existing)"
|
||||
placeholder={t("mcpTools.mcpServerEdit.awsRegionPlaceholder")}
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(留空则保留现有值)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue