Skip to main content
Glama
schema-generator.ts3.9 kB
import type { NormalizedOperation } from '../types/index.js'; import type { JSONSchema, ProxyMetadata } from '../types/mcp-tool.js'; /** * Generate JSON Schema for tool input from operation parameters and body */ export function generateInputSchema(operation: NormalizedOperation): JSONSchema { const properties: Record<string, JSONSchema> = {}; const required: string[] = []; // Add parameters (path, query, header) for (const param of operation.parameters) { properties[param.name] = { ...param.schema, description: param.description ?? param.schema.description, }; if (param.required) { required.push(param.name); } } // Add request body properties if (operation.requestBody) { const bodySchema = operation.requestBody.schema; if (bodySchema.type === 'object' && bodySchema.properties) { // Flatten object body properties into input schema for (const [key, value] of Object.entries(bodySchema.properties)) { // Avoid overwriting existing params if (!(key in properties)) { properties[key] = value; } } // Add required body properties if (bodySchema.required) { for (const reqProp of bodySchema.required) { if (!required.includes(reqProp)) { required.push(reqProp); } } } } else { // Non-object body: wrap in "body" property properties['body'] = { ...bodySchema, description: operation.requestBody.description ?? bodySchema.description ?? 'Request body', }; if (operation.requestBody.required) { required.push('body'); } } } return { type: 'object', properties, required: required.length > 0 ? required : undefined, }; } /** * Generate proxy metadata for executing the operation */ export function generateProxyMetadata(operation: NormalizedOperation): ProxyMetadata { const pathParams: string[] = []; const queryParams: string[] = []; const headerParams: string[] = []; const bodyParams: string[] = []; // Categorize parameters by location for (const param of operation.parameters) { switch (param.in) { case 'path': pathParams.push(param.name); break; case 'query': queryParams.push(param.name); break; case 'header': headerParams.push(param.name); break; } } // Extract body params if (operation.requestBody) { const bodySchema = operation.requestBody.schema; if (bodySchema.type === 'object' && bodySchema.properties) { bodyParams.push(...Object.keys(bodySchema.properties)); } else { // Non-object body wrapped in "body" property bodyParams.push('body'); } } return { method: operation.method, path: operation.path, pathParams, queryParams, headerParams, contentType: operation.requestBody?.contentType, bodySchema: operation.requestBody?.schema, bodyParams, tags: operation.tags, }; } /** * Extract body params that should be excluded from path/query/header */ export function getBodyOnlyParams(proxy: ProxyMetadata): Set<string> { const nonBodyParams = new Set([ ...proxy.pathParams, ...proxy.queryParams, ...proxy.headerParams, ]); return new Set(proxy.bodyParams.filter((p) => !nonBodyParams.has(p))); } /** * Validate that input schema is valid JSON Schema */ export function validateInputSchema(schema: JSONSchema): string[] { const errors: string[] = []; if (schema.type !== 'object') { errors.push('Input schema must be an object type'); } if (schema.properties) { for (const [name, prop] of Object.entries(schema.properties)) { if (!prop.type && !prop.oneOf && !prop.anyOf && !prop.allOf) { errors.push(`Property "${name}" is missing type definition`); } } } return errors; }

Latest Blog Posts

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/procoders/openapi-mcp-ts'

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