cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

38 lines
1.1 KiB
TypeScript

import * as z from "zod";
export const McpTransportSchema = z.enum(["streamable_http", "sse", "stdio"]);
export type McpTransport = z.infer<typeof McpTransportSchema>;
export function isLocalMcpHost(hostname: string): boolean {
return (
hostname === "localhost" ||
hostname === "127.0.0.1" ||
hostname === "[::1]" ||
hostname === "::1"
);
}
export const McpRemoteEndpointSchema = z
.string()
.max(2048)
.url()
.refine((value) => {
try {
if (value.endsWith("#")) return false;
const url = new URL(value);
if (url.username || url.password || url.hash) return false;
if (url.protocol === "https:") return true;
return url.protocol === "http:" && isLocalMcpHost(url.hostname);
} catch {
return false;
}
}, "MCP remote endpoint must be an HTTPS URL without credentials or a fragment (HTTP is allowed only for localhost)");
export const McpHeadersSchema = z
.record(z.string().regex(/^[A-Za-z0-9-]+$/), z.string().max(4096))
.superRefine((value, ctx) => {
if (Object.keys(value).length > 32) {
ctx.addIssue({ code: "custom", message: "At most 32 headers are allowed" });
}
});