Skip to main content
Glama

Home Assistant MCP Server

schema-utils.ts4.88 kB
import convert from "json-schema-to-zod"; import { z } from "zod"; import fs from "fs"; // Define types for JSON Schema type JsonSchemaType = { type: string; properties?: Record<string, JsonSchemaProperty>; required?: string[]; description?: string; minimum?: number; maximum?: number; enum?: string[]; items?: JsonSchemaProperty; minItems?: number; maxItems?: number; default?: unknown; }; type JsonSchemaProperty = JsonSchemaType; export function pathSchemaToZod(path: string): z.ZodTypeAny { const jsonSchema = JSON.parse(fs.readFileSync(path, "utf8")); return jsonSchemaToZod(jsonSchema); } /** * Convert a JSON schema to a Zod schema * @param jsonSchema The JSON schema to convert * @returns The generated Zod schema */ export function jsonSchemaToZod(jsonSchema: object): z.ZodTypeAny { try { // Convert the JSON schema to Zod schema code const zodSchemaCode = convert(jsonSchema); // Evaluate the Zod schema code to get the actual Zod schema // This is a safe use of eval since we're controlling the input // and the output is a Zod schema const zodSchema = new Function("z", `return ${zodSchemaCode}`)(z); return zodSchema; } catch (error) { console.error("Error converting JSON schema to Zod:", error); throw error; } } /** * Parse and validate data against a JSON schema using Zod * @param jsonSchema The JSON schema to validate against * @param data The data to validate * @returns The validated data * @throws If the data is invalid */ export function parseWithJsonSchema<T>(jsonSchema: object, data: unknown): T { const zodSchema = jsonSchemaToZod(jsonSchema); return zodSchema.parse(data) as T; } /** * Extract a JSON schema from a Zod schema object * This is a simplified implementation that handles common Zod schema types * @param zodSchemaObj An object containing Zod schema properties * @returns A JSON schema representation */ export function zodToJsonSchema( zodSchemaObj: Record<string, z.ZodTypeAny>, ): JsonSchemaType { const properties: Record<string, JsonSchemaProperty> = {}; const required: string[] = []; // Process each property in the Zod schema object for (const [key, zodType] of Object.entries(zodSchemaObj)) { const property = extractJsonSchemaProperty(zodType); // Add description if available const description = zodType.description; if (description) { property.description = description; } // Check if the property is required if (!isOptional(zodType)) { required.push(key); } properties[key] = property; } return { type: "object", properties, ...(required.length > 0 ? { required } : {}), }; } /** * Extract JSON schema property from a Zod type * @param zodType The Zod type to extract from * @returns The JSON schema property */ function extractJsonSchemaProperty(zodType: z.ZodTypeAny): JsonSchemaProperty { // Handle string if (zodType instanceof z.ZodString) { return { type: "string" }; } // Handle number if (zodType instanceof z.ZodNumber) { const schema: JsonSchemaProperty = { type: "number" }; // Add min/max constraints if defined type ZodCheck = { kind: string; value: number }; const checks = (zodType._def.checks || []) as ZodCheck[]; for (const check of checks) { if (check.kind === "min") { schema.minimum = check.value; } else if (check.kind === "max") { schema.maximum = check.value; } } return schema; } // Handle boolean if (zodType instanceof z.ZodBoolean) { return { type: "boolean" }; } // Handle enum if (zodType instanceof z.ZodEnum) { return { type: "string", enum: zodType._def.values, }; } // Handle array if (zodType instanceof z.ZodArray) { const itemSchema = extractJsonSchemaProperty(zodType._def.type); const schema: JsonSchemaProperty = { type: "array", items: itemSchema, }; // Add length constraints if defined if (zodType._def.exactLength !== null) { schema.minItems = zodType._def.exactLength?.value; schema.maxItems = zodType._def.exactLength?.value; } return schema; } // Handle optional types if (zodType instanceof z.ZodOptional) { return extractJsonSchemaProperty(zodType._def.innerType); } // Handle default values if (zodType instanceof z.ZodDefault) { const schema = extractJsonSchemaProperty(zodType._def.innerType); schema.default = zodType._def.defaultValue(); return schema; } // Fallback for unsupported types return { type: "object" }; } /** * Check if a Zod type is optional * @param zodType The Zod type to check * @returns True if the type is optional */ function isOptional(zodType: z.ZodTypeAny): boolean { return zodType instanceof z.ZodOptional || zodType instanceof z.ZodDefault; }

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/oleander/home-assistant-mcp-server'

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