touchdesigner-mcp-server 1.1.1 → 1.1.2
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/README.ja.md +75 -26
- package/README.md +74 -25
- package/dist/core/constants.js +1 -0
- package/dist/features/tools/handlers/tdTools.js +162 -50
- package/dist/features/tools/metadata/touchDesignerToolMetadata.js +402 -0
- package/dist/features/tools/presenter/classListFormatter.js +187 -0
- package/dist/features/tools/presenter/index.js +11 -0
- package/dist/features/tools/presenter/markdownRenderer.js +25 -0
- package/dist/features/tools/presenter/nodeDetailsFormatter.js +140 -0
- package/dist/features/tools/presenter/nodeListFormatter.js +124 -0
- package/dist/features/tools/presenter/operationFormatter.js +117 -0
- package/dist/features/tools/presenter/presenter.js +62 -0
- package/dist/features/tools/presenter/responseFormatter.js +66 -0
- package/dist/features/tools/presenter/scriptResultFormatter.js +171 -0
- package/dist/features/tools/presenter/templates/markdown/classDetailsSummary.md +13 -0
- package/dist/features/tools/presenter/templates/markdown/classListSummary.md +7 -0
- package/dist/features/tools/presenter/templates/markdown/default.md +3 -0
- package/dist/features/tools/presenter/templates/markdown/detailedPayload.md +5 -0
- package/dist/features/tools/presenter/templates/markdown/nodeDetailsSummary.md +10 -0
- package/dist/features/tools/presenter/templates/markdown/nodeListSummary.md +8 -0
- package/dist/features/tools/presenter/templates/markdown/scriptSummary.md +15 -0
- package/dist/features/tools/presenter/toolMetadataFormatter.js +118 -0
- package/dist/features/tools/types.js +26 -1
- package/dist/gen/endpoints/TouchDesignerAPI.js +1 -1
- package/dist/gen/mcp/touchDesignerAPI.zod.js +1 -1
- package/dist/server/touchDesignerServer.js +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Node {{nodePath}}
|
|
2
|
+
- Type: `{{type}}` (ID: {{id}})
|
|
3
|
+
- Properties shown: {{displayed}} / {{total}}
|
|
4
|
+
|
|
5
|
+
| Property | Value |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
{{#properties}}| {{name}} | {{{value}}} |
|
|
8
|
+
{{/properties}}
|
|
9
|
+
|
|
10
|
+
{{#truncated}}_💡 {{omittedCount}} more properties omitted._{{/truncated}}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## Nodes in {{{parentPath}}} ({{totalCount}} total)
|
|
2
|
+
{{#groups}}
|
|
3
|
+
### {{type}} ({{count}})
|
|
4
|
+
{{#nodes}}- **{{name}}** — `{{{path}}}`
|
|
5
|
+
{{/nodes}}
|
|
6
|
+
|
|
7
|
+
{{/groups}}
|
|
8
|
+
{{#truncated}}_💡 {{omittedCount}} more node(s) omitted. Use `limit` or `detailLevel=detailed` to view all._{{/truncated}}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Script Result
|
|
2
|
+
- Snippet: `{{{snippet}}}`
|
|
3
|
+
- Return type: {{resultType}}
|
|
4
|
+
{{#hasOutput}}- Output type: {{outputType}}
|
|
5
|
+
{{/hasOutput}}
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
{{{resultPreview}}}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
{{#outputPreview}}
|
|
12
|
+
```text
|
|
13
|
+
{{{outputPreview}}}
|
|
14
|
+
```
|
|
15
|
+
{{/outputPreview}}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { finalizeFormattedText, mergeFormatterOptions, } from "./responseFormatter.js";
|
|
2
|
+
export function formatToolMetadata(entries, options) {
|
|
3
|
+
const { detailLevel, responseFormat } = mergeFormatterOptions(options);
|
|
4
|
+
if (entries.length === 0) {
|
|
5
|
+
return finalizeFormattedText("No tools matched the requested criteria.", { detailLevel, responseFormat }, {
|
|
6
|
+
context: { totalTools: 0, filter: options?.filter },
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
const sortedEntries = [...entries].sort((a, b) => a.modulePath.localeCompare(b.modulePath));
|
|
10
|
+
const structured = sortedEntries.map((entry) => ({
|
|
11
|
+
tool: entry.tool,
|
|
12
|
+
modulePath: entry.modulePath,
|
|
13
|
+
functionName: entry.functionName,
|
|
14
|
+
description: entry.description,
|
|
15
|
+
category: entry.category,
|
|
16
|
+
parameters: entry.parameters,
|
|
17
|
+
returns: entry.returns,
|
|
18
|
+
notes: entry.notes,
|
|
19
|
+
}));
|
|
20
|
+
const text = buildText(sortedEntries, detailLevel);
|
|
21
|
+
return finalizeFormattedText(text, { detailLevel, responseFormat }, {
|
|
22
|
+
structured,
|
|
23
|
+
context: {
|
|
24
|
+
totalTools: sortedEntries.length,
|
|
25
|
+
filter: options?.filter,
|
|
26
|
+
},
|
|
27
|
+
template: detailLevel === "detailed" ? "detailedPayload" : undefined,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function buildText(entries, detailLevel) {
|
|
31
|
+
switch (detailLevel) {
|
|
32
|
+
case "minimal":
|
|
33
|
+
return formatTree(entries);
|
|
34
|
+
case "detailed":
|
|
35
|
+
return formatDetailed(entries);
|
|
36
|
+
default:
|
|
37
|
+
return formatSummary(entries);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function formatTree(entries) {
|
|
41
|
+
const segmentsList = entries.map((entry) => entry.modulePath.replace(/^\.\//, "").split("/"));
|
|
42
|
+
const commonSegments = findCommonDirectorySegments(segmentsList);
|
|
43
|
+
const basePath = commonSegments.length > 0 ? `${commonSegments.join("/")}/` : "./";
|
|
44
|
+
const relativePaths = entries.map((entry, index) => {
|
|
45
|
+
const segments = segmentsList[index];
|
|
46
|
+
const relative = segments.slice(commonSegments.length).join("/");
|
|
47
|
+
const connector = index === entries.length - 1 ? "└──" : "├──";
|
|
48
|
+
return `${connector} ${relative} — ${entry.description}`;
|
|
49
|
+
});
|
|
50
|
+
return ["Filesystem blueprint:", basePath, ...relativePaths].join("\n");
|
|
51
|
+
}
|
|
52
|
+
function formatSummary(entries) {
|
|
53
|
+
return entries
|
|
54
|
+
.map((entry) => {
|
|
55
|
+
const params = entry.parameters.length > 0
|
|
56
|
+
? entry.parameters
|
|
57
|
+
.map((param) => `- ${param.name}${param.required ? "" : "?"} (${param.type})${param.description ? ` — ${param.description}` : ""}`)
|
|
58
|
+
.join("\n")
|
|
59
|
+
: "- (no parameters)";
|
|
60
|
+
return `${entry.functionName} (${entry.modulePath})
|
|
61
|
+
Tool: ${entry.tool}
|
|
62
|
+
Category: ${entry.category}
|
|
63
|
+
Description: ${entry.description}
|
|
64
|
+
Parameters:
|
|
65
|
+
${params}
|
|
66
|
+
Returns: ${entry.returns}`;
|
|
67
|
+
})
|
|
68
|
+
.join("\n\n");
|
|
69
|
+
}
|
|
70
|
+
function formatDetailed(entries) {
|
|
71
|
+
return entries
|
|
72
|
+
.map((entry) => {
|
|
73
|
+
const params = entry.parameters.length > 0
|
|
74
|
+
? entry.parameters
|
|
75
|
+
.map((param) => `- ${param.name}${param.required ? "" : "?"} (${param.type})${param.description ? ` — ${param.description}` : ""}`)
|
|
76
|
+
.join("\n")
|
|
77
|
+
: "- (no parameters)";
|
|
78
|
+
const sections = [
|
|
79
|
+
`### ${entry.functionName} (${entry.tool})`,
|
|
80
|
+
`Module: ${entry.modulePath}`,
|
|
81
|
+
`Category: ${entry.category}`,
|
|
82
|
+
`Description: ${entry.description}`,
|
|
83
|
+
"Parameters:",
|
|
84
|
+
params,
|
|
85
|
+
`Returns: ${entry.returns}`,
|
|
86
|
+
"Example:",
|
|
87
|
+
"```ts",
|
|
88
|
+
entry.example.trim(),
|
|
89
|
+
"```",
|
|
90
|
+
];
|
|
91
|
+
if (entry.notes) {
|
|
92
|
+
sections.push(`Notes: ${entry.notes}`);
|
|
93
|
+
}
|
|
94
|
+
return sections.join("\n");
|
|
95
|
+
})
|
|
96
|
+
.join("\n\n---\n\n");
|
|
97
|
+
}
|
|
98
|
+
function findCommonDirectorySegments(segmentsList) {
|
|
99
|
+
if (segmentsList.length === 0) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const directories = segmentsList.map((parts) => parts.slice(0, Math.max(parts.length - 1, 0)));
|
|
103
|
+
let prefix = directories[0];
|
|
104
|
+
for (let i = 1; i < directories.length; i += 1) {
|
|
105
|
+
const current = directories[i];
|
|
106
|
+
let j = 0;
|
|
107
|
+
while (j < prefix.length &&
|
|
108
|
+
j < current.length &&
|
|
109
|
+
prefix[j] === current[j]) {
|
|
110
|
+
j += 1;
|
|
111
|
+
}
|
|
112
|
+
prefix = prefix.slice(0, j);
|
|
113
|
+
if (prefix.length === 0) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return prefix;
|
|
118
|
+
}
|
|
@@ -1 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Shared Zod schemas for MCP tool formatting parameters.
|
|
4
|
+
* These stay on the TypeScript side only and are not sent to TouchDesigner.
|
|
5
|
+
*/
|
|
6
|
+
export const detailLevelSchema = z
|
|
7
|
+
.enum(["minimal", "summary", "detailed"])
|
|
8
|
+
.describe("Response detail level for tool output (minimal, summary, or detailed)");
|
|
9
|
+
export const limitSchema = z
|
|
10
|
+
.number()
|
|
11
|
+
.int()
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(500)
|
|
14
|
+
.describe("Maximum number of items to include in formatted output");
|
|
15
|
+
export const presenterFormatSchema = z
|
|
16
|
+
.enum(["json", "yaml", "markdown"])
|
|
17
|
+
.describe("Structured output format for formatted responses");
|
|
18
|
+
export const detailOnlyFormattingSchema = z.object({
|
|
19
|
+
detailLevel: detailLevelSchema.optional(),
|
|
20
|
+
responseFormat: presenterFormatSchema.optional(),
|
|
21
|
+
});
|
|
22
|
+
export const formattingOptionsSchema = z.object({
|
|
23
|
+
detailLevel: detailLevelSchema.optional(),
|
|
24
|
+
limit: limitSchema.optional(),
|
|
25
|
+
responseFormat: presenterFormatSchema.optional(),
|
|
26
|
+
});
|
|
@@ -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: 1.1.
|
|
6
|
+
* OpenAPI spec version: 1.1.2
|
|
7
7
|
*/
|
|
8
8
|
import { customInstance } from '../../api/customInstance.js';
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "touchdesigner-mcp-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "MCP server for TouchDesigner",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,23 +29,24 @@
|
|
|
29
29
|
"@types/ws": "^8.18.1",
|
|
30
30
|
"@types/yargs": "^17.0.33",
|
|
31
31
|
"axios": "^1.12.2",
|
|
32
|
+
"mustache": "^4.2.0",
|
|
33
|
+
"yaml": "^2.8.1",
|
|
32
34
|
"zod": "3.25.76"
|
|
33
35
|
},
|
|
34
36
|
"devDependencies": {
|
|
35
37
|
"@biomejs/biome": "2.2.4",
|
|
36
38
|
"@openapitools/openapi-generator-cli": "^2.23.1",
|
|
37
39
|
"@types/jsdom": "^21.1.7",
|
|
40
|
+
"@types/mustache": "^4.2.6",
|
|
38
41
|
"@types/node": "^24.4.0",
|
|
39
42
|
"@vitest/coverage-v8": "^3.2.4",
|
|
40
43
|
"archiver": "^7.0.1",
|
|
41
44
|
"msw": "^2.11.2",
|
|
42
|
-
"mustache": "^4.2.0",
|
|
43
45
|
"npm-run-all": "^4.1.5",
|
|
44
46
|
"orval": "^7.11.2",
|
|
45
47
|
"shx": "^0.4.0",
|
|
46
48
|
"typescript": "^5.9.2",
|
|
47
|
-
"vitest": "^3.2.4"
|
|
48
|
-
"yaml": "^2.8.1"
|
|
49
|
+
"vitest": "^3.2.4"
|
|
49
50
|
},
|
|
50
51
|
"type": "module",
|
|
51
52
|
"exports": {
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
"scripts": {
|
|
62
63
|
"build": "run-s build:*",
|
|
63
64
|
"build:gen": "npm run gen",
|
|
64
|
-
"build:dist": "tsc && shx chmod +x dist/*.js",
|
|
65
|
+
"build:dist": "tsc && shx chmod +x dist/*.js && shx cp -r src/features/tools/presenter/templates dist/features/tools/presenter/",
|
|
65
66
|
"build:dxt": "npx @anthropic-ai/dxt pack dxt/ touchdesigner-mcp.dxt",
|
|
66
67
|
"lint": "run-p lint:*",
|
|
67
68
|
"lint:biome": "biome check",
|