Skip to main content
Glama

VeChain MCP Server

utils.ts5.67 kB
import z, { type ZodTypeAny } from "zod"; type JsonSchema = any; function jsonSchemaPropToZod(schema: JsonSchema): ZodTypeAny { if (!schema) return z.any(); if (Array.isArray(schema.enum)) { const literals = schema.enum.map((v: any) => z.literal(v)); return literals.length === 1 ? literals[0] : z.union(literals as any); } if (schema.const !== undefined) { return z.literal(schema.const); } switch (schema.type) { case "string": { let s = z.string(); if (typeof schema.minLength === "number") s = s.min(schema.minLength); if (typeof schema.maxLength === "number") s = s.max(schema.maxLength); if (typeof schema.pattern === "string") { try { const rx = new RegExp(schema.pattern); s = s.regex(rx); } catch { // ignore invalid regex } } return s; } case "number": { let n = z.number(); if (typeof schema.minimum === "number") n = n.min(schema.minimum); if (typeof schema.maximum === "number") n = n.max(schema.maximum); return n; } case "integer": { let n = z.number().int(); if (typeof schema.minimum === "number") n = n.min(schema.minimum); if (typeof schema.maximum === "number") n = n.max(schema.maximum); return n; } case "boolean": return z.boolean(); case "array": { const itemSchema = schema.items ? jsonSchemaPropToZod(schema.items) : z.any(); let arr = z.array(itemSchema); if (typeof schema.minItems === "number") arr = arr.min(schema.minItems); if (typeof schema.maxItems === "number") arr = arr.max(schema.maxItems); return arr; } case "object": { const props = schema.properties ?? {}; const required: string[] = Array.isArray(schema.required) ? schema.required : []; const shape: Record<string, ZodTypeAny> = {}; for (const [k, v] of Object.entries(props)) { const child = jsonSchemaPropToZod(v); shape[k] = required.includes(k) ? child : child.optional(); } let obj = z.object(shape).passthrough(); if (schema.additionalProperties === true) { obj = obj.extend({}); } else if (typeof schema.additionalProperties === "object") { obj = obj.passthrough(); } else { obj = obj.passthrough(); } return obj; } default: if (schema.properties) { return jsonSchemaPropToZod({ type: "object", ...schema }); } return z.any(); } } export function jsonSchemaToZodRoot(schema: JsonSchema): ZodTypeAny { if (!schema) return z.object({}); if (typeof (schema as any)?._parse === "function" || typeof (schema as any)?.parse === "function") { return schema; } if (schema.type === "object" || schema.properties) { const props = schema.properties ?? {}; const required: string[] = Array.isArray(schema.required) ? schema.required : []; const shape: Record<string, ZodTypeAny> = {}; for (const [key, propSchema] of Object.entries(props)) { if ( propSchema && typeof propSchema === 'object' && 'type' in propSchema && 'additionalProperties' in propSchema && 'properties' in propSchema && propSchema.type === "object" && propSchema.additionalProperties === true && (!propSchema.properties || Object.keys(propSchema.properties).length === 0) ) { shape[key] = z.record(z.any()); if (!required.includes(key)) shape[key] = shape[key].optional(); continue; } const propZod = jsonSchemaPropToZod(propSchema); shape[key] = required.includes(key) ? propZod : propZod.optional(); } let root = z.object(shape); if (schema.additionalProperties === true) { root = root.strip(); } else { root = root.strip(); } return root; } return z.object({}); } export function buildToolZodMap(listOfTools: Array<any>): Map<string, ZodTypeAny> { const m = new Map<string, ZodTypeAny>(); for (const t of listOfTools) { try { const raw = t?.inputSchema ?? t; const zodSchema = jsonSchemaToZodRoot(raw); const finalSchema = zodSchema._def?.typeName?.startsWith?.("ZodObject") ? zodSchema : z.object({}); m.set(t.name, finalSchema); } catch (e) { m.set(t.name, z.object({})); } } return m; } export function parseToolInput(toolSchemaMap: Map<string, ZodTypeAny>, toolName: string, input: any) { const schema = toolSchemaMap.get(toolName); if (!schema) { return {}; } try { const parsed = schema.parse(input ?? {}); return parsed; } catch (err) { if (err instanceof z.ZodError) { const details = err.errors.map(e => { const path = e.path.length ? e.path.join(".") : "<root>"; return `${path}: ${e.message}`; }).join("; "); throw new Error(`Input validation failed for tool "${toolName}": ${details}`); } throw err; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/leandrogavidia/vechain-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server