mcp-clickhouse

Official
import type { ErrorObject } from "ajv"; import type { JSONSchema7 } from "json-schema"; import {Ajv} from "ajv"; // Using type assertion to help TypeScript understand the constructor const ajv = new Ajv({ allErrors: true, strict: false, strictSchema: false, strictTypes: false, }); /** * Validates data against a schema and throws an error with details if validation fails */ export function validateWithErrors(data: unknown, schema: JSONSchema7): void { const validate = ajv.compile(schema); const valid = validate(data); if (!valid) { const errors = validate.errors ?.map((e: ErrorObject) => { if (e.keyword === "required") { const property = (e.params as any).missingProperty; // Map property names to expected error messages const errorMap: Record<string, string> = { params: "Request must have params", messages: "Request must have at least one message", content: "Message must have a content object", text: "Text content must have a string text field", data: "Image content must have a base64 data field", mimeType: "Image content must have a mimeType field", type: "Message content must have a type field", title: "Missing required field: title", description: "Missing required field: description", static: "Missing required field: static instruction", dynamic: "Missing required field: dynamic instruction", state: "Missing required field: state", input_type: "Missing required field: input type", output_type: "Missing required field: output type", }; return errorMap[property] || `Missing required field: ${property}`; } if (e.keyword === "minimum" && (e.params as any).limit === 1) { if ((e as any).instancePath === "/params/maxTokens") { return "maxTokens must be a positive number"; } if ((e as any).instancePath === "/params/messages") { return "Request must have at least one message"; } } if (e.keyword === "maximum" && (e.params as any).limit === 1) { if ((e as any).instancePath === "/params/temperature") { return "Temperature must be between 0 and 1"; } if ((e as any).instancePath.includes("Priority")) { return "Priority values must be between 0 and 1"; } } if (e.keyword === "enum") { if ((e as any).instancePath === "/params/includeContext") { return 'includeContext must be one of: "none", "thisServer", or "allServers"'; } if ((e as any).instancePath.includes("/role")) { return 'Message role must be either "user" or "assistant"'; } if ((e as any).instancePath.includes("/type")) { return 'Content type must be either "text" or "image"'; } } if (e.keyword === "type") { if ((e as any).instancePath.includes("/text")) { return "Text content must be a string"; } } if ( e.keyword === "minItems" && (e as any).instancePath === "/params/messages" ) { return "Request must have at least one message"; } return e.message || "Unknown validation error"; }) .join(", "); throw new Error(errors); } } // Schema for validating sampling requests const samplingRequestSchema: JSONSchema7 = { type: "object", required: ["method", "params"], properties: { method: { type: "string", enum: ["sampling/createMessage"] }, params: { type: "object", required: ["messages"], properties: { messages: { type: "array", minItems: 1, items: { type: "object", required: ["role", "content"], properties: { role: { type: "string", enum: ["user", "assistant"] }, content: { oneOf: [ { type: "object", required: ["type", "text"], properties: { type: { type: "string", enum: ["text"] }, text: { type: "string" }, }, additionalProperties: false, }, { type: "object", required: ["type", "data", "mimeType"], properties: { type: { type: "string", enum: ["image"] }, data: { type: "string" }, mimeType: { type: "string" }, }, additionalProperties: false, }, ], }, }, }, }, maxTokens: { type: "number", minimum: 1 }, temperature: { type: "number", minimum: 0, maximum: 1 }, includeContext: { type: "string", enum: ["none", "thisServer", "allServers"], }, modelPreferences: { type: "object", properties: { costPriority: { type: "number", minimum: 0, maximum: 1 }, speedPriority: { type: "number", minimum: 0, maximum: 1 }, intelligencePriority: { type: "number", minimum: 0, maximum: 1 }, }, }, }, }, }, }; /** * Validates a request against a schema */ export function validateRequest(request: unknown): void { validateWithErrors(request, samplingRequestSchema); }