UNPKG

touchdesigner-mcp-server

Version:
99 lines (98 loc) 3.47 kB
import { TOOL_DEFINITIONS, } from "../toolDefinitions.js"; const MODULE_ROOT = "servers/touchdesigner"; /** snake_case tool name -> camelCase function name (e.g. get_td_info -> getTdInfo). */ function toFunctionName(toolName) { return toolName.replace(/_(.)/g, (_, char) => char.toUpperCase()); } /** * Builds the `describe_td_tools` manifest from the tool table. Parameter * metadata is introspected from each tool's Zod schema, so it always reflects * the schema that is actually registered (sourced from the OpenAPI spec). */ export function buildToolMetadata(definitions = TOOL_DEFINITIONS) { return definitions.map((definition) => { const functionName = toFunctionName(definition.name); return { category: definition.category, description: definition.description, example: definition.example, functionName, modulePath: `${MODULE_ROOT}/${functionName}.ts`, notes: definition.notes, parameters: deriveParameters(definition.schema), returns: definition.returns, tool: definition.name, }; }); } /** Introspects a Zod object schema into flat parameter metadata. */ export function deriveParameters(schema) { return Object.entries(schema.shape).map(([name, field]) => { const { base, description, required } = unwrap(field); return { description, name, required, type: renderType(base), }; }); } /** Peels optional/default/nullable wrappers to reach the base type. */ function unwrap(field) { let node = field; let description = node.description; let required = true; while (node.def) { if (description === undefined && node.description) { description = node.description; } const type = node.def.type; if (type === "optional" || type === "default" || type === "prefault" || type === "nullish") { required = false; } if ((type === "optional" || type === "default" || type === "prefault" || type === "nullable" || type === "nullish") && node.def.innerType) { node = node.def.innerType; continue; } break; } return { base: node, description: description ?? node.description, required }; } /** Renders a base Zod type as a TypeScript-flavored type string. */ function renderType(node) { const def = node.def; switch (def?.type) { case "enum": return Object.values(def.entries ?? {}) .map((value) => `'${value}'`) .join(" | "); case "string": return "string"; case "number": case "int": return "number"; case "boolean": return "boolean"; case "array": return `Array<${def.element ? renderType(def.element) : "unknown"}>`; case "record": return `Record<${def.keyType ? renderType(def.keyType) : "string"}, ${def.valueType ? renderType(def.valueType) : "unknown"}>`; case "union": return (def.options ?? []).map(renderType).join(" | "); case "unknown": case "any": return "unknown"; case "object": return "object"; default: return def?.type ?? "unknown"; } }