touchdesigner-mcp-server 1.4.7 → 1.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,22 +1,10 @@
1
1
  import { z } from "zod";
2
- import { REFERENCE_COMMENT, TOOL_NAMES } from "../../../core/constants.js";
2
+ import { TOOL_NAMES } from "../../../core/constants.js";
3
3
  import { handleToolError } from "../../../core/errorHandling.js";
4
- import { CreateNodeBody, DeleteNodeQueryParams, ExecNodeMethodBody, ExecPythonScriptBody, GetModuleHelpQueryParams, GetNodeDetailQueryParams, GetNodeErrorsQueryParams, GetNodesQueryParams, GetTdPythonClassDetailsParams, UpdateNodeBody, } from "../../../gen/mcp/touchDesignerAPI.zod.js";
5
- import { getTouchDesignerToolMetadata } from "../metadata/touchDesignerToolMetadata.js";
6
- import { formatClassDetails, formatClassList, formatCreateNodeResult, formatDeleteNodeResult, formatExecNodeMethodResult, formatModuleHelp, formatNodeDetails, formatNodeErrors, formatNodeList, formatScriptResult, formatTdInfo, formatToolMetadata, formatUpdateNodeResult, } from "../presenter/index.js";
7
- import { detailOnlyFormattingSchema, formattingOptionsSchema, } from "../types.js";
8
- const execPythonScriptToolSchema = ExecPythonScriptBody.extend(detailOnlyFormattingSchema.shape);
9
- const tdInfoToolSchema = detailOnlyFormattingSchema;
10
- const getNodesToolSchema = GetNodesQueryParams.extend(formattingOptionsSchema.shape);
11
- const getNodeDetailToolSchema = GetNodeDetailQueryParams.extend(formattingOptionsSchema.shape);
12
- const getNodeErrorsToolSchema = GetNodeErrorsQueryParams.extend(formattingOptionsSchema.shape);
13
- const createNodeToolSchema = CreateNodeBody.extend(detailOnlyFormattingSchema.shape);
14
- const updateNodeToolSchema = UpdateNodeBody.extend(detailOnlyFormattingSchema.shape);
15
- const deleteNodeToolSchema = DeleteNodeQueryParams.extend(detailOnlyFormattingSchema.shape);
16
- const classListToolSchema = formattingOptionsSchema;
17
- const classDetailToolSchema = GetTdPythonClassDetailsParams.extend(formattingOptionsSchema.shape);
18
- const moduleHelpToolSchema = GetModuleHelpQueryParams.extend(detailOnlyFormattingSchema.shape);
19
- const execNodeMethodToolSchema = ExecNodeMethodBody.extend(detailOnlyFormattingSchema.shape);
4
+ import { buildToolMetadata, } from "../metadata/touchDesignerToolMetadata.js";
5
+ import { formatToolMetadata } from "../presenter/index.js";
6
+ import { TOOL_DEFINITIONS } from "../toolDefinitions.js";
7
+ import { detailOnlyFormattingSchema } from "../types.js";
20
8
  const describeToolsSchema = detailOnlyFormattingSchema.extend({
21
9
  filter: z
22
10
  .string()
@@ -25,7 +13,21 @@ const describeToolsSchema = detailOnlyFormattingSchema.extend({
25
13
  .optional(),
26
14
  });
27
15
  export function registerTdTools(server, logger, tdClient) {
28
- const toolMetadataEntries = getTouchDesignerToolMetadata();
16
+ // Register every TouchDesigner operation from the single source of truth.
17
+ for (const definition of TOOL_DEFINITIONS) {
18
+ server.tool(definition.name, definition.description, definition.schema.strict().shape, async (params = {}) => {
19
+ try {
20
+ const text = await definition.run({ logger, params, tdClient });
21
+ return createToolResult(tdClient, text);
22
+ }
23
+ catch (error) {
24
+ return handleToolError(error, logger, definition.name, definition.errorComment);
25
+ }
26
+ });
27
+ }
28
+ // `describe_td_tools` is the meta tool: it documents the tools above rather
29
+ // than calling TouchDesigner, so it is registered on its own.
30
+ const toolMetadataEntries = buildToolMetadata(TOOL_DEFINITIONS);
29
31
  server.tool(TOOL_NAMES.DESCRIBE_TD_TOOLS, "Generate a filesystem-oriented manifest of available TouchDesigner tools", describeToolsSchema.strict().shape, async (params = {}) => {
30
32
  try {
31
33
  const { detailLevel, responseFormat, filter } = params;
@@ -38,12 +40,7 @@ export function registerTdTools(server, logger, tdClient) {
38
40
  ? `No TouchDesigner tools matched filter "${filter}".`
39
41
  : "No TouchDesigner tools are registered.";
40
42
  return {
41
- content: [
42
- {
43
- text: message,
44
- type: "text",
45
- },
46
- ],
43
+ content: [{ text: message, type: "text" }],
47
44
  };
48
45
  }
49
46
  const formattedText = formatToolMetadata(filteredEntries, {
@@ -52,247 +49,17 @@ export function registerTdTools(server, logger, tdClient) {
52
49
  responseFormat,
53
50
  });
54
51
  return {
55
- content: [
56
- {
57
- text: formattedText,
58
- type: "text",
59
- },
60
- ],
52
+ content: [{ text: formattedText, type: "text" }],
61
53
  };
62
54
  }
63
55
  catch (error) {
64
56
  return handleToolError(error, logger, TOOL_NAMES.DESCRIBE_TD_TOOLS);
65
57
  }
66
58
  });
67
- server.tool(TOOL_NAMES.GET_TD_INFO, "Get server information from TouchDesigner", tdInfoToolSchema.strict().shape, async (params = {}) => {
68
- try {
69
- const { detailLevel, responseFormat } = params;
70
- const result = await tdClient.getTdInfo();
71
- if (!result.success) {
72
- throw result.error;
73
- }
74
- const formattedText = formatTdInfo(result.data, {
75
- detailLevel: detailLevel ?? "summary",
76
- responseFormat,
77
- });
78
- return createToolResult(tdClient, formattedText);
79
- }
80
- catch (error) {
81
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_INFO);
82
- }
83
- });
84
- server.tool(TOOL_NAMES.EXECUTE_PYTHON_SCRIPT, "Execute a Python script in TouchDesigner (detailLevel=minimal|summary|detailed, responseFormat=json|yaml|markdown)", execPythonScriptToolSchema.strict().shape, async (params) => {
85
- try {
86
- const { detailLevel, responseFormat, ...scriptParams } = params;
87
- logger.sendLog({
88
- data: `Executing script: ${scriptParams.script}`,
89
- level: "debug",
90
- });
91
- const result = await tdClient.execPythonScript(scriptParams);
92
- if (!result.success) {
93
- throw result.error;
94
- }
95
- // Use formatter for token-optimized response
96
- const formattedText = formatScriptResult(result, scriptParams.script, {
97
- detailLevel: detailLevel ?? "summary",
98
- responseFormat,
99
- });
100
- return createToolResult(tdClient, formattedText);
101
- }
102
- catch (error) {
103
- return handleToolError(error, logger, TOOL_NAMES.EXECUTE_PYTHON_SCRIPT);
104
- }
105
- });
106
- server.tool(TOOL_NAMES.CREATE_TD_NODE, "Create a new node in TouchDesigner", createNodeToolSchema.strict().shape, async (params) => {
107
- try {
108
- const { detailLevel, responseFormat, ...createParams } = params;
109
- const result = await tdClient.createNode(createParams);
110
- if (!result.success) {
111
- throw result.error;
112
- }
113
- const formattedText = formatCreateNodeResult(result.data, {
114
- detailLevel: detailLevel ?? "summary",
115
- responseFormat,
116
- });
117
- return createToolResult(tdClient, formattedText);
118
- }
119
- catch (error) {
120
- return handleToolError(error, logger, TOOL_NAMES.CREATE_TD_NODE, REFERENCE_COMMENT);
121
- }
122
- });
123
- server.tool(TOOL_NAMES.DELETE_TD_NODE, "Delete an existing node in TouchDesigner", deleteNodeToolSchema.strict().shape, async (params) => {
124
- try {
125
- const { detailLevel, responseFormat, ...deleteParams } = params;
126
- const result = await tdClient.deleteNode(deleteParams);
127
- if (!result.success) {
128
- throw result.error;
129
- }
130
- const formattedText = formatDeleteNodeResult(result.data, {
131
- detailLevel: detailLevel ?? "summary",
132
- responseFormat,
133
- });
134
- return createToolResult(tdClient, formattedText);
135
- }
136
- catch (error) {
137
- return handleToolError(error, logger, TOOL_NAMES.DELETE_TD_NODE, REFERENCE_COMMENT);
138
- }
139
- });
140
- server.tool(TOOL_NAMES.GET_TD_NODES, "List nodes under a path with token-optimized output (detailLevel+limit supported)", getNodesToolSchema.strict().shape, async (params) => {
141
- try {
142
- const { detailLevel, limit, responseFormat, ...queryParams } = params;
143
- const result = await tdClient.getNodes(queryParams);
144
- if (!result.success) {
145
- throw result.error;
146
- }
147
- // Use formatter for token-optimized response
148
- const fallbackMode = queryParams.includeProperties
149
- ? "detailed"
150
- : "summary";
151
- const formattedText = formatNodeList(result.data, {
152
- detailLevel: detailLevel ?? fallbackMode,
153
- limit,
154
- responseFormat,
155
- });
156
- return createToolResult(tdClient, formattedText);
157
- }
158
- catch (error) {
159
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODES, REFERENCE_COMMENT);
160
- }
161
- });
162
- server.tool(TOOL_NAMES.GET_TD_NODE_PARAMETERS, "Get node parameters with concise/detailed formatting (detailLevel+limit supported)", getNodeDetailToolSchema.strict().shape, async (params) => {
163
- try {
164
- const { detailLevel, limit, responseFormat, ...queryParams } = params;
165
- const result = await tdClient.getNodeDetail(queryParams);
166
- if (!result.success) {
167
- throw result.error;
168
- }
169
- // Use formatter for token-optimized response
170
- const formattedText = formatNodeDetails(result.data, {
171
- detailLevel: detailLevel ?? "summary",
172
- limit,
173
- responseFormat,
174
- });
175
- return createToolResult(tdClient, formattedText);
176
- }
177
- catch (error) {
178
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODE_PARAMETERS, REFERENCE_COMMENT);
179
- }
180
- });
181
- server.tool(TOOL_NAMES.GET_TD_NODE_ERRORS, "Check node and descendant errors reported by TouchDesigner", getNodeErrorsToolSchema.strict().shape, async (params) => {
182
- try {
183
- const { detailLevel, limit, responseFormat, ...queryParams } = params;
184
- const result = await tdClient.getNodeErrors(queryParams);
185
- if (!result.success) {
186
- throw result.error;
187
- }
188
- const formattedText = formatNodeErrors(result.data, {
189
- detailLevel: detailLevel ?? "summary",
190
- limit,
191
- responseFormat,
192
- });
193
- return createToolResult(tdClient, formattedText);
194
- }
195
- catch (error) {
196
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_NODE_ERRORS, REFERENCE_COMMENT);
197
- }
198
- });
199
- server.tool(TOOL_NAMES.UPDATE_TD_NODE_PARAMETERS, "Update parameters of a specific node in TouchDesigner", updateNodeToolSchema.strict().shape, async (params) => {
200
- try {
201
- const { detailLevel, responseFormat, ...updateParams } = params;
202
- const result = await tdClient.updateNode(updateParams);
203
- if (!result.success) {
204
- throw result.error;
205
- }
206
- const formattedText = formatUpdateNodeResult(result.data, {
207
- detailLevel: detailLevel ?? "summary",
208
- responseFormat,
209
- });
210
- return createToolResult(tdClient, formattedText);
211
- }
212
- catch (error) {
213
- return handleToolError(error, logger, TOOL_NAMES.UPDATE_TD_NODE_PARAMETERS, REFERENCE_COMMENT);
214
- }
215
- });
216
- server.tool(TOOL_NAMES.EXECUTE_NODE_METHOD, "Execute a method on a specific node in TouchDesigner", execNodeMethodToolSchema.strict().shape, async (params) => {
217
- try {
218
- const { detailLevel, responseFormat, ...execParams } = params;
219
- const { nodePath, method, args, kwargs } = execParams;
220
- const result = await tdClient.execNodeMethod(execParams);
221
- if (!result.success) {
222
- throw result.error;
223
- }
224
- const formattedText = formatExecNodeMethodResult(result.data, { args, kwargs, method, nodePath }, { detailLevel: detailLevel ?? "summary", responseFormat });
225
- return createToolResult(tdClient, formattedText);
226
- }
227
- catch (error) {
228
- logger.sendLog({
229
- data: error,
230
- level: "error",
231
- });
232
- return handleToolError(error, logger, TOOL_NAMES.EXECUTE_NODE_METHOD, REFERENCE_COMMENT);
233
- }
234
- });
235
- server.tool(TOOL_NAMES.GET_TD_CLASSES, "List TouchDesigner Python classes/modules (detailLevel+limit supported)", classListToolSchema.strict().shape, async (params = {}) => {
236
- try {
237
- const result = await tdClient.getClasses();
238
- if (!result.success) {
239
- throw result.error;
240
- }
241
- // Use formatter for token-optimized response
242
- const formattedText = formatClassList(result.data, {
243
- detailLevel: params.detailLevel ?? "summary",
244
- limit: params.limit ?? 50,
245
- responseFormat: params.responseFormat,
246
- });
247
- return createToolResult(tdClient, formattedText);
248
- }
249
- catch (error) {
250
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_CLASSES, REFERENCE_COMMENT);
251
- }
252
- });
253
- server.tool(TOOL_NAMES.GET_TD_CLASS_DETAILS, "Get information about a TouchDesigner class/module (detailLevel+limit supported)", classDetailToolSchema.strict().shape, async (params) => {
254
- try {
255
- const { className, detailLevel, limit, responseFormat } = params;
256
- const result = await tdClient.getClassDetails(className);
257
- if (!result.success) {
258
- throw result.error;
259
- }
260
- // Use formatter for token-optimized response
261
- const formattedText = formatClassDetails(result.data, {
262
- detailLevel: detailLevel ?? "summary",
263
- limit: limit ?? 30,
264
- responseFormat,
265
- });
266
- return createToolResult(tdClient, formattedText);
267
- }
268
- catch (error) {
269
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_CLASS_DETAILS, REFERENCE_COMMENT);
270
- }
271
- });
272
- server.tool(TOOL_NAMES.GET_TD_MODULE_HELP, "Retrieve Python help() text for a TouchDesigner module or class", moduleHelpToolSchema.strict().shape, async (params) => {
273
- try {
274
- const { detailLevel, moduleName, responseFormat } = params;
275
- const result = await tdClient.getModuleHelp({ moduleName });
276
- if (!result.success) {
277
- throw result.error;
278
- }
279
- const formattedText = formatModuleHelp(result.data, {
280
- detailLevel: detailLevel ?? "summary",
281
- responseFormat,
282
- });
283
- return createToolResult(tdClient, formattedText);
284
- }
285
- catch (error) {
286
- return handleToolError(error, logger, TOOL_NAMES.GET_TD_MODULE_HELP);
287
- }
288
- });
289
59
  }
290
60
  const createToolResult = (tdClient, text) => {
291
61
  const content = [
292
- {
293
- text,
294
- type: "text",
295
- },
62
+ { text, type: "text" },
296
63
  ];
297
64
  const additionalContents = tdClient.getAdditionalToolResultContents();
298
65
  if (additionalContents) {