mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
refactor(mcp/ui): share normalizeEnvVars helper between create and edit forms
This commit is contained in:
parent
ca1e837532
commit
c9cc963101
3 changed files with 29 additions and 49 deletions
|
|
@ -15,7 +15,7 @@ import OpenAPIFormSection, { OpenAPIKeyTool } from "./OpenAPIFormSection";
|
|||
import MCPLogoSelector from "./MCPLogoSelector";
|
||||
import EnvVarsSection from "./EnvVarsSection";
|
||||
import { isAdminRole } from "@/utils/roles";
|
||||
import { validateMCPServerUrl, validateMCPServerName } from "./utils";
|
||||
import { validateMCPServerUrl, validateMCPServerName, normalizeEnvVars } from "./utils";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow";
|
||||
import { useTestMCPConnection } from "@/hooks/useTestMCPConnection";
|
||||
|
|
@ -49,31 +49,6 @@ const reduceStaticHeaders = (list: unknown): Record<string, string> => {
|
|||
}, {});
|
||||
};
|
||||
|
||||
type EnvVarEntry = { name: string; value: string; scope: "global" | "user"; description?: string };
|
||||
|
||||
/** Normalize the env_vars form list into the payload shape the backend expects.
|
||||
* Drops empty rows and any with invalid identifiers. */
|
||||
const normalizeEnvVars = (list: unknown): EnvVarEntry[] => {
|
||||
if (!Array.isArray(list)) return [];
|
||||
const seen = new Set<string>();
|
||||
const out: EnvVarEntry[] = [];
|
||||
for (const entry of list) {
|
||||
if (!entry || typeof entry !== "object") continue;
|
||||
const name = String((entry as Record<string, unknown>).name ?? "").trim();
|
||||
if (!name || seen.has(name)) continue;
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) continue;
|
||||
const scope = (entry as Record<string, unknown>).scope === "user" ? "user" : "global";
|
||||
out.push({
|
||||
name,
|
||||
value: scope === "user" ? "" : String((entry as Record<string, unknown>).value ?? ""),
|
||||
scope,
|
||||
description: ((entry as Record<string, unknown>).description as string | undefined) || undefined,
|
||||
});
|
||||
seen.add(name);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
||||
userID,
|
||||
userRole,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import MCPToolConfiguration from "./mcp_tool_configuration";
|
|||
import StdioConfiguration from "./StdioConfiguration";
|
||||
import MCPLogoSelector from "./MCPLogoSelector";
|
||||
import EnvVarsSection from "./EnvVarsSection";
|
||||
import { validateMCPServerUrl, validateMCPServerName } from "./utils";
|
||||
import { validateMCPServerUrl, validateMCPServerName, normalizeEnvVars } from "./utils";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow";
|
||||
import { getSecureItem, setSecureItem } from "@/utils/secureStorage";
|
||||
|
|
@ -431,28 +431,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
}, {})
|
||||
: ({} as Record<string, string>);
|
||||
|
||||
const envVars = Array.isArray(envVarsList)
|
||||
? envVarsList.reduce(
|
||||
(acc: Array<{ name: string; value: string; scope: "global" | "user"; description?: string }>, entry: Record<string, unknown>) => {
|
||||
const name = String(entry?.name ?? "").trim();
|
||||
if (!name || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
||||
return acc;
|
||||
}
|
||||
if (acc.some((existing) => existing.name === name)) {
|
||||
return acc;
|
||||
}
|
||||
const scope = entry?.scope === "user" ? "user" : "global";
|
||||
acc.push({
|
||||
name,
|
||||
value: scope === "user" ? "" : String(entry?.value ?? ""),
|
||||
scope,
|
||||
description: (entry?.description as string | undefined) || undefined,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
)
|
||||
: [];
|
||||
const envVars = normalizeEnvVars(envVarsList);
|
||||
|
||||
const credentialsPayload =
|
||||
credentialValues && typeof credentialValues === "object"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { MCPEnvVar, MCPEnvVarScope } from "./types";
|
||||
|
||||
export const extractMCPToken = (url: string): { token: string | null; baseUrl: string } => {
|
||||
try {
|
||||
const mcpIndex = url.indexOf("/mcp/");
|
||||
|
|
@ -51,3 +53,27 @@ export const validateMCPServerName = (value: string) => {
|
|||
? Promise.reject("Cannot contain '-' (hyphen) or spaces. Please use '_' (underscore) instead.")
|
||||
: Promise.resolve();
|
||||
};
|
||||
|
||||
// Normalize the env_vars form list into the payload shape the backend expects.
|
||||
// Drops empty rows, invalid identifiers, and duplicate names; user-scoped entries never carry a value.
|
||||
export const normalizeEnvVars = (list: unknown): MCPEnvVar[] => {
|
||||
if (!Array.isArray(list)) return [];
|
||||
const seen = new Set<string>();
|
||||
const out: MCPEnvVar[] = [];
|
||||
for (const entry of list) {
|
||||
if (!entry || typeof entry !== "object") continue;
|
||||
const record = entry as Record<string, unknown>;
|
||||
const name = String(record.name ?? "").trim();
|
||||
if (!name || seen.has(name)) continue;
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) continue;
|
||||
const scope: MCPEnvVarScope = record.scope === "user" ? "user" : "global";
|
||||
out.push({
|
||||
name,
|
||||
value: scope === "user" ? "" : String(record.value ?? ""),
|
||||
scope,
|
||||
description: (record.description as string | undefined) || undefined,
|
||||
});
|
||||
seen.add(name);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue