Skip to main content
Glama
operationFormatter.ts5.4 kB
import { MCP_SERVER_VERSION } from "../../../core/version.js"; import type { CreateNode200ResponseData, DeleteNode200ResponseData, ExecNodeMethod200ResponseData, GetTdInfo200ResponseData, UpdateNode200ResponseData, } from "../../../gen/endpoints/TouchDesignerAPI.js"; import type { FormatterOptions } from "./responseFormatter.js"; import { finalizeFormattedText, mergeFormatterOptions, } from "./responseFormatter.js"; type FormatterOpts = Pick<FormatterOptions, "detailLevel" | "responseFormat">; export function formatTdInfo( data: GetTdInfo200ResponseData, options?: FormatterOpts, ): string { const opts = mergeFormatterOptions(options); if (!data) { return finalizeFormattedText("TouchDesigner info not available.", opts, { context: { title: "TouchDesigner Info" }, }); } const structured = { "API Server Version": data.mcpApiVersion, "MCP Server Version": MCP_SERVER_VERSION, "Operating System": data.osName ? `${data.osName} ${data.osVersion ?? ""}`.trim() : "Unknown", "TouchDesigner Version": data.version, }; const text = Object.entries(structured) .map(([key, value]) => `${key}: ${value}`) .join("\n"); return finalizeFormattedText(text.trim(), opts, { context: { title: "TouchDesigner Info", }, structured, template: "detailedPayload", }); } export function formatCreateNodeResult( data: CreateNode200ResponseData, options?: FormatterOpts, ): string { const opts = mergeFormatterOptions(options); const node = data?.result; if (!node) { return finalizeFormattedText( "Node created but no metadata returned.", opts, { context: { title: "Create Node" }, structured: data, }, ); } const name = node.name ?? "(unknown)"; const path = node.path ?? "(path unknown)"; const opType = node.opType ?? "unknown"; const base = `✓ Created node '${name}' (${opType}) at ${path}`; const propCount = Object.keys(node.properties ?? {}).length; const text = opts.detailLevel === "minimal" ? base : `${base}\nProperties detected: ${propCount}`; return finalizeFormattedText(text, opts, { context: { opType, path, title: "Create Node" }, structured: data, template: opts.detailLevel === "detailed" ? "detailedPayload" : "default", }); } export function formatUpdateNodeResult( data: UpdateNode200ResponseData, options?: FormatterOpts, ): string { const opts = mergeFormatterOptions(options); const updatedCount = data?.updated?.length ?? 0; const failedCount = data?.failed?.length ?? 0; const base = `✓ Updated ${updatedCount} parameter(s)`; const text = opts.detailLevel === "minimal" ? base : `${base}${failedCount ? `, ${failedCount} failed` : ""}`; const context = { failed: data?.failed, message: data?.message, title: "Update Node", updated: data?.updated, }; return finalizeFormattedText(text, opts, { context, structured: data, template: opts.detailLevel === "detailed" ? "detailedPayload" : "default", }); } export function formatDeleteNodeResult( data: DeleteNode200ResponseData, options?: FormatterOpts, ): string { const opts = mergeFormatterOptions(options); const deleted = data?.deleted ?? false; const name = data?.node?.name ?? "node"; const path = data?.node?.path ?? "(path unknown)"; const text = deleted ? `🗑️ Deleted '${name}' at ${path}` : `Deletion status unknown for '${name}' at ${path}`; return finalizeFormattedText(text, opts, { context: { deleted, path, title: "Delete Node" }, structured: data, template: opts.detailLevel === "detailed" ? "detailedPayload" : "default", }); } export function formatExecNodeMethodResult( data: ExecNodeMethod200ResponseData | { result?: unknown } | null | undefined, context: { nodePath: string; method: string; args?: unknown[]; kwargs?: Record<string, unknown>; }, options?: FormatterOpts, ): string { const opts = mergeFormatterOptions(options); const callSignature = buildCallSignature(context); const resultPreview = summarizeValue(data?.result); const text = `${callSignature}\nResult: ${resultPreview}`; return finalizeFormattedText(text, opts, { context: { callSignature, title: "Execute Node Method" }, structured: { ...context, result: data?.result }, template: opts.detailLevel === "detailed" ? "detailedPayload" : "default", }); } function buildCallSignature(params: { nodePath: string; method: string; args?: unknown[]; kwargs?: Record<string, unknown>; }): string { const argPart = params.args ?? []; const kwPart = params.kwargs ? Object.entries(params.kwargs).map( ([key, value]) => `${key}=${JSON.stringify(value)}`, ) : []; const joinedArgs = [...argPart.map(stringifyValue), ...kwPart].join(", "); return `op('${params.nodePath}').${params.method}(${joinedArgs})`; } function summarizeValue(value: unknown): string { if (value === undefined) return "(no result)"; if (value === null) return "null"; if (typeof value === "string") return value.length > 120 ? `${value.slice(0, 117)}...` : value; if (typeof value === "number" || typeof value === "boolean") return String(value); if (Array.isArray(value)) return `Array[${value.length}]`; if (typeof value === "object") return `Object{${Object.keys(value).length} keys}`; return String(value); } function stringifyValue(value: unknown): string { if (typeof value === "string") return `'${value}'`; return JSON.stringify(value); }

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/8beeeaaat/touchdesigner-mcp'

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