touchdesigner-mcp-server 0.2.13 → 0.3.0
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.
- package/dist/features/tools/handlers/tdTools.js +7 -2
- package/dist/gen/endpoints/TouchDesignerAPI.js +1 -1
- package/dist/gen/mcp/touchDesignerAPI.zod.js +4 -2
- package/dist/server/touchDesignerServer.js +1 -1
- package/package.json +1 -1
- package/td/modules/mcp/controllers/api_controller.py +7 -2
- package/td/modules/mcp/services/api_service.py +24 -4
- package/td/modules/td_server/openapi_server/controllers/default_controller.py +3 -1
- package/td/modules/td_server/openapi_server/openapi/openapi.yaml +10 -1
- package/td/modules/td_server/openapi_server/test/test_default_controller.py +2 -1
|
@@ -85,17 +85,22 @@ export function registerTdTools(server, logger, tdClient) {
|
|
|
85
85
|
return handleToolError(error, logger, TOOL_NAMES.DELETE_TD_NODE, REFERENCE_COMMENT);
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
-
server.tool(TOOL_NAMES.GET_TD_NODES, "Get all nodes in the parent path", getNodesQueryParams.strict().shape, async (params) => {
|
|
88
|
+
server.tool(TOOL_NAMES.GET_TD_NODES, "Get all nodes in the parent path (lightweight by default for better performance)", getNodesQueryParams.strict().shape, async (params) => {
|
|
89
89
|
try {
|
|
90
90
|
const result = await tdClient.getNodes(params);
|
|
91
91
|
if (!result.success) {
|
|
92
92
|
throw result.error;
|
|
93
93
|
}
|
|
94
|
+
const nodeCount = result.data?.nodes?.length || 0;
|
|
95
|
+
const isLightweight = !params.includeProperties;
|
|
96
|
+
const performanceNote = isLightweight
|
|
97
|
+
? " (lightweight mode - set includeProperties=true for full node details)"
|
|
98
|
+
: " (full mode with properties)";
|
|
94
99
|
return {
|
|
95
100
|
content: [
|
|
96
101
|
{
|
|
97
102
|
type: "text",
|
|
98
|
-
text: `Project nodes retrieved: ${JSON.stringify(result, null, 2)}`,
|
|
103
|
+
text: `Project nodes retrieved (${nodeCount} nodes)${performanceNote}: ${JSON.stringify(result, null, 2)}`,
|
|
99
104
|
},
|
|
100
105
|
],
|
|
101
106
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Do not edit manually.
|
|
4
4
|
* TouchDesigner API
|
|
5
5
|
* OpenAPI schema for generating TouchDesigner API client code
|
|
6
|
-
* OpenAPI spec version: 0.
|
|
6
|
+
* OpenAPI spec version: 0.3.0
|
|
7
7
|
*/
|
|
8
8
|
import { customInstance } from '../../api/customInstance.js';
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Do not edit manually.
|
|
4
4
|
* TouchDesigner API
|
|
5
5
|
* OpenAPI schema for generating TouchDesigner API client code
|
|
6
|
-
* OpenAPI spec version: 0.
|
|
6
|
+
* OpenAPI spec version: 0.3.0
|
|
7
7
|
*/
|
|
8
8
|
import { z as zod } from 'zod';
|
|
9
9
|
/**
|
|
@@ -30,9 +30,11 @@ export const deleteNodeResponse = zod.object({
|
|
|
30
30
|
* @summary Get nodes in the path
|
|
31
31
|
*/
|
|
32
32
|
export const getNodesQueryPatternDefault = "*";
|
|
33
|
+
export const getNodesQueryIncludePropertiesDefault = false;
|
|
33
34
|
export const getNodesQueryParams = zod.object({
|
|
34
35
|
"parentPath": zod.string().describe('Parent path e.g., \"/project1\"'),
|
|
35
|
-
"pattern": zod.string().default(getNodesQueryPatternDefault).describe('Pattern to match against node names e.g., \"null*\"')
|
|
36
|
+
"pattern": zod.string().default(getNodesQueryPatternDefault).describe('Pattern to match against node names e.g., \"null*\"'),
|
|
37
|
+
"includeProperties": zod.boolean().optional().describe('Whether to include full node properties in the response (default false for better performance)')
|
|
36
38
|
});
|
|
37
39
|
export const getNodesResponse = zod.object({
|
|
38
40
|
"success": zod.boolean().describe('Whether the operation was successful'),
|
package/package.json
CHANGED
|
@@ -55,7 +55,7 @@ class ApiServiceProtocol(Protocol):
|
|
|
55
55
|
|
|
56
56
|
def get_td_info(self) -> Result: ...
|
|
57
57
|
|
|
58
|
-
def get_nodes(self, parent_path: str, pattern: Optional[str] = None) -> Result: ...
|
|
58
|
+
def get_nodes(self, parent_path: str, pattern: Optional[str] = None, include_properties: bool = False) -> Result: ...
|
|
59
59
|
|
|
60
60
|
def create_node(
|
|
61
61
|
self,
|
|
@@ -417,6 +417,7 @@ class APIControllerOpenAPI(IController):
|
|
|
417
417
|
self,
|
|
418
418
|
parentPath: str,
|
|
419
419
|
pattern: Optional[str] = None,
|
|
420
|
+
includeProperties: Optional[bool] = None,
|
|
420
421
|
body: Optional[str] = None,
|
|
421
422
|
**kwargs,
|
|
422
423
|
) -> Result:
|
|
@@ -426,11 +427,15 @@ class APIControllerOpenAPI(IController):
|
|
|
426
427
|
Args:
|
|
427
428
|
parentPath: Path of the parent node to get children from
|
|
428
429
|
pattern: Optional pattern to filter nodes by
|
|
430
|
+
includeProperties: Whether to include full node properties (default: False)
|
|
429
431
|
|
|
430
432
|
Returns:
|
|
431
433
|
List of nodes under the specified parent path
|
|
432
434
|
"""
|
|
433
|
-
|
|
435
|
+
# Convert camelCase to snake_case and provide default value
|
|
436
|
+
include_properties = includeProperties if includeProperties is not None else False
|
|
437
|
+
|
|
438
|
+
service_result = self._service.get_nodes(parentPath, pattern, include_properties)
|
|
434
439
|
response_data = GetNodes200Response().from_dict(service_result)
|
|
435
440
|
return response_data.to_dict()
|
|
436
441
|
|
|
@@ -132,12 +132,13 @@ class TouchDesignerApiService(IApiService):
|
|
|
132
132
|
node_info = self._get_node_summary(node)
|
|
133
133
|
return success_result(node_info)
|
|
134
134
|
|
|
135
|
-
def get_nodes(self, parent_path: str, pattern: Optional[str] = None) -> Result:
|
|
135
|
+
def get_nodes(self, parent_path: str, pattern: Optional[str] = None, include_properties: bool = False) -> Result:
|
|
136
136
|
"""Get nodes under the specified parent path, optionally filtered by pattern
|
|
137
137
|
|
|
138
138
|
Args:
|
|
139
139
|
parent_path: Path to the parent node
|
|
140
140
|
pattern: Pattern to filter nodes by name (e.g. "text*" for all nodes starting with "text")
|
|
141
|
+
include_properties: Whether to include full node properties (default False for better performance)
|
|
141
142
|
|
|
142
143
|
Returns:
|
|
143
144
|
Result: Success with list of nodes or error
|
|
@@ -157,7 +158,10 @@ class TouchDesignerApiService(IApiService):
|
|
|
157
158
|
log_message("Calling parent_node.findChildren(depth=1)", LogLevel.DEBUG)
|
|
158
159
|
nodes = parent_node.findChildren(depth=1)
|
|
159
160
|
|
|
160
|
-
|
|
161
|
+
if include_properties:
|
|
162
|
+
node_summaries = [self._get_node_summary(node) for node in nodes]
|
|
163
|
+
else:
|
|
164
|
+
node_summaries = [self._get_node_summary_light(node) for node in nodes]
|
|
161
165
|
|
|
162
166
|
return success_result({"nodes": node_summaries})
|
|
163
167
|
|
|
@@ -357,8 +361,6 @@ class TouchDesignerApiService(IApiService):
|
|
|
357
361
|
if node is None or not node.valid:
|
|
358
362
|
raise error_result(f"Node not found at path: {node_path}")
|
|
359
363
|
|
|
360
|
-
node_detail = self.get_node_detail(node_path)
|
|
361
|
-
current_properties = node_detail.get("data", {})
|
|
362
364
|
updated_properties = []
|
|
363
365
|
failed_properties = []
|
|
364
366
|
|
|
@@ -437,6 +439,24 @@ class TouchDesignerApiService(IApiService):
|
|
|
437
439
|
|
|
438
440
|
return params_dict
|
|
439
441
|
|
|
442
|
+
def _get_node_summary_light(self, node) -> Dict:
|
|
443
|
+
"""Get lightweight information about a node (without properties for better performance)"""
|
|
444
|
+
try:
|
|
445
|
+
node_info = {
|
|
446
|
+
"id": node.id,
|
|
447
|
+
"name": node.name,
|
|
448
|
+
"path": node.path,
|
|
449
|
+
"opType": node.OPType,
|
|
450
|
+
"properties": {}, # Empty properties for lightweight response
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return node_info
|
|
454
|
+
except Exception as e:
|
|
455
|
+
log_message(
|
|
456
|
+
f"Error collecting node information: {str(e)}", LogLevel.WARNING
|
|
457
|
+
)
|
|
458
|
+
return {"name": node.name if hasattr(node, "name") else "unknown"}
|
|
459
|
+
|
|
440
460
|
def _get_node_summary(self, node) -> Dict:
|
|
441
461
|
"""Get detailed information about a node"""
|
|
442
462
|
try:
|
|
@@ -94,7 +94,7 @@ def get_node_detail(node_path): # noqa: E501
|
|
|
94
94
|
return 'do some magic!'
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def get_nodes(parent_path, pattern=None): # noqa: E501
|
|
97
|
+
def get_nodes(parent_path, pattern=None, include_properties=None): # noqa: E501
|
|
98
98
|
"""Get nodes in the path
|
|
99
99
|
|
|
100
100
|
# noqa: E501
|
|
@@ -103,6 +103,8 @@ def get_nodes(parent_path, pattern=None): # noqa: E501
|
|
|
103
103
|
:type parent_path: str
|
|
104
104
|
:param pattern: Pattern to match against node names e.g., \"null*\"
|
|
105
105
|
:type pattern: str
|
|
106
|
+
:param include_properties: Whether to include full node properties in the response (default false for better performance)
|
|
107
|
+
:type include_properties: bool
|
|
106
108
|
|
|
107
109
|
:rtype: Union[GetNodes200Response, Tuple[GetNodes200Response, int], Tuple[GetNodes200Response, int, Dict[str, str]]
|
|
108
110
|
"""
|
|
@@ -2,7 +2,7 @@ openapi: 3.0.0
|
|
|
2
2
|
info:
|
|
3
3
|
description: OpenAPI schema for generating TouchDesigner API client code
|
|
4
4
|
title: TouchDesigner API
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.3.0
|
|
6
6
|
servers:
|
|
7
7
|
- url: "{baseUrl}"
|
|
8
8
|
variables:
|
|
@@ -47,6 +47,15 @@ paths:
|
|
|
47
47
|
default: '*'
|
|
48
48
|
description: "e.g., \"null*\""
|
|
49
49
|
type: string
|
|
50
|
+
- description: Whether to include full node properties in the response (default
|
|
51
|
+
false for better performance)
|
|
52
|
+
in: query
|
|
53
|
+
name: includeProperties
|
|
54
|
+
required: false
|
|
55
|
+
schema:
|
|
56
|
+
default: false
|
|
57
|
+
description: Include node properties in response
|
|
58
|
+
type: boolean
|
|
50
59
|
responses:
|
|
51
60
|
"200":
|
|
52
61
|
content:
|
|
@@ -119,7 +119,8 @@ class TestDefaultController(BaseTestCase):
|
|
|
119
119
|
Get nodes in the path
|
|
120
120
|
"""
|
|
121
121
|
query_string = [('parentPath', 'parent_path_example'),
|
|
122
|
-
('pattern', '*')
|
|
122
|
+
('pattern', '*'),
|
|
123
|
+
('includeProperties', False)]
|
|
123
124
|
headers = {
|
|
124
125
|
'Accept': 'application/json',
|
|
125
126
|
}
|