This commit is contained in:
Your Name committed 2026-10-11 06:43:08 +07:00
1 parent 9237c0eded
commit f5893c3fad
16 files changed
+1230 -114

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
import { readFileSync } from "node:fs";
import { isAbsolute } from "node:path";
export type TargetProfile = {
id: string;
displayName: string;
kind: "local" | "staging" | "production";
baseUrl: string;
usernameEnv: string;
passwordEnv: string;
};
export type TargetRegistry = {
profiles: TargetProfile[];
defaultProfileId: string;
};
const envNamePattern = /^[A-Z_][A-Z0-9_]*$/;
const profileIdPattern = /^[a-z][a-z0-9_-]*$/;
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function validateBaseUrl(value: unknown): string {
if (typeof value !== "string") throw new Error("Target profile baseUrl must be a URL string.");
let url: URL;
try { url = new URL(value); } catch { throw new Error("Target profile baseUrl is invalid."); }
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
throw new Error("Target profile baseUrl must use HTTPS, except HTTP loopback.");
}
if (url.username || url.password || value.includes("?") || value.includes("#") || !url.hostname) {
throw new Error("Target profile baseUrl cannot include credentials, query, or fragment.");
}
return url.toString().replace(/\/+$/, "");
}
/** Private registry stores references to secret environment variables, never values. */
export function loadTargetRegistry(env: NodeJS.ProcessEnv = process.env): TargetRegistry | null {
const file = env.MCP_TARGET_PROFILES_FILE;
if (!file) {
if (env.MCP_DEFAULT_TARGET_PROFILE) throw new Error("MCP_DEFAULT_TARGET_PROFILE requires MCP_TARGET_PROFILES_FILE.");
return null;
}
if (!isAbsolute(file)) throw new Error("MCP_TARGET_PROFILES_FILE must be an absolute path.");
let raw: unknown;
try { raw = JSON.parse(readFileSync(file, "utf8")); }
catch { throw new Error("MCP target profile registry could not be read as JSON."); }
if (!isRecord(raw) || Object.keys(raw).some((key) => key !== "profiles") || !Array.isArray(raw.profiles) || raw.profiles.length === 0) {
throw new Error("MCP target profile registry must contain a non-empty profiles array only.");
}
const ids = new Set<string>();
const credentialNames = new Set<string>();
const urls = new Set<string>();
const profiles = raw.profiles.map((entry: unknown): TargetProfile => {
if (!isRecord(entry) || Object.keys(entry).some((key) => !["id", "displayName", "kind", "baseUrl", "usernameEnv", "passwordEnv"].includes(key))) {
throw new Error("Target profile contains unsupported fields; literal credentials are not allowed.");
}
const { id, displayName, kind, baseUrl, usernameEnv, passwordEnv } = entry;
if (typeof id !== "string" || !profileIdPattern.test(id) || ids.has(id)) throw new Error("Target profile ID is invalid or duplicated.");
if (typeof displayName !== "string" || !displayName.trim()) throw new Error("Target profile displayName is required.");
if (kind !== "local" && kind !== "staging" && kind !== "production") throw new Error("Target profile kind must be local, staging, or production.");
if (typeof usernameEnv !== "string" || !envNamePattern.test(usernameEnv) || typeof passwordEnv !== "string" || !envNamePattern.test(passwordEnv) || usernameEnv === passwordEnv) {
throw new Error("Target profile credential environment variable names are invalid.");
}
if (credentialNames.has(usernameEnv) || credentialNames.has(passwordEnv)) throw new Error("Target profiles must use distinct credential environment variables.");
if (!env[usernameEnv] || !env[passwordEnv]) throw new Error(`Target profile ${id} is missing credential environment variables.`);
const normalizedUrl = validateBaseUrl(baseUrl);
if (urls.has(normalizedUrl)) throw new Error("Target profile baseUrl is duplicated.");
ids.add(id);
credentialNames.add(usernameEnv);
credentialNames.add(passwordEnv);
urls.add(normalizedUrl);
return { id, displayName, kind, baseUrl: normalizedUrl, usernameEnv, passwordEnv };
});
const defaultProfileId = env.MCP_DEFAULT_TARGET_PROFILE;
if (!defaultProfileId || !ids.has(defaultProfileId)) throw new Error("MCP_DEFAULT_TARGET_PROFILE must identify a configured target profile.");
return { profiles, defaultProfileId };
}