touchdesigner-mcp-server 1.3.0 → 1.4.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/README.ja.md +33 -310
- package/README.md +40 -313
- package/dist/cli.js +132 -16
- package/dist/core/compatibility.js +236 -0
- package/dist/core/logger.js +21 -1
- package/dist/core/version.js +21 -1
- package/dist/features/tools/presenter/operationFormatter.js +17 -10
- package/dist/server/touchDesignerServer.js +21 -2
- package/dist/tdClient/touchDesignerClient.js +203 -83
- package/dist/transport/config.js +75 -0
- package/dist/transport/expressHttpManager.js +235 -0
- package/dist/transport/factory.js +198 -0
- package/dist/transport/index.js +12 -0
- package/dist/transport/sessionManager.js +276 -0
- package/dist/transport/transportRegistry.js +272 -0
- package/dist/transport/validator.js +78 -0
- package/package.json +17 -7
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { MIN_COMPATIBLE_API_VERSION } from "./version.js";
|
|
3
|
+
export const COMPATIBILITY_POLICY_TYPES = {
|
|
4
|
+
BELOW_MIN_VERSION: "belowMinVersion",
|
|
5
|
+
COMPATIBLE: "compatible",
|
|
6
|
+
MAJOR_MISMATCH: "majorMismatch",
|
|
7
|
+
NEWER_MINOR: "newerMinor",
|
|
8
|
+
NO_VERSION: "noVersion",
|
|
9
|
+
OLDER_MINOR: "olderMinor",
|
|
10
|
+
PATCH_DIFF: "patchDiff",
|
|
11
|
+
};
|
|
12
|
+
export const COMPATIBILITY_POLICY_ERROR_LEVELS = {
|
|
13
|
+
ALLOW: "info",
|
|
14
|
+
ERROR: "error",
|
|
15
|
+
WARNING: "warning",
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Compatibility policy configuration
|
|
19
|
+
*/
|
|
20
|
+
const COMPATIBILITY_POLICY = {
|
|
21
|
+
/**
|
|
22
|
+
* Behavior when no version information is available
|
|
23
|
+
* - 'error': Stop processing with error
|
|
24
|
+
*/
|
|
25
|
+
[COMPATIBILITY_POLICY_TYPES.NO_VERSION]: {
|
|
26
|
+
compatible: false,
|
|
27
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.ERROR,
|
|
28
|
+
message: generateNoVersionMessage,
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Behavior when API server version is below minimum required version
|
|
32
|
+
* - 'error': Stop processing with error
|
|
33
|
+
*/
|
|
34
|
+
[COMPATIBILITY_POLICY_TYPES.BELOW_MIN_VERSION]: {
|
|
35
|
+
compatible: false,
|
|
36
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.ERROR,
|
|
37
|
+
message: generateMinVersionMessage,
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* Behavior when MAJOR versions differ
|
|
41
|
+
* - 'error': Stop processing with error
|
|
42
|
+
*/
|
|
43
|
+
[COMPATIBILITY_POLICY_TYPES.MAJOR_MISMATCH]: {
|
|
44
|
+
compatible: false,
|
|
45
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.ERROR,
|
|
46
|
+
message: generateMajorMismatchMessage,
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Behavior when MCP server has newer MINOR version than API server
|
|
50
|
+
* - 'warning': Continue with warning only
|
|
51
|
+
*/
|
|
52
|
+
[COMPATIBILITY_POLICY_TYPES.NEWER_MINOR]: {
|
|
53
|
+
compatible: true,
|
|
54
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.WARNING,
|
|
55
|
+
message: generateNewerMinorMessage,
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* Behavior when API server has newer MINOR version than MCP server
|
|
59
|
+
* - 'warning': Continue with warning
|
|
60
|
+
*/
|
|
61
|
+
[COMPATIBILITY_POLICY_TYPES.OLDER_MINOR]: {
|
|
62
|
+
compatible: true,
|
|
63
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.WARNING,
|
|
64
|
+
message: generateOlderMinorMessage,
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Behavior when PATCH versions differ
|
|
68
|
+
* - 'warning': Continue with warning
|
|
69
|
+
*/
|
|
70
|
+
[COMPATIBILITY_POLICY_TYPES.PATCH_DIFF]: {
|
|
71
|
+
compatible: true,
|
|
72
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.WARNING,
|
|
73
|
+
message: generatePatchDiffMessage,
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Behavior when versions are fully compatible
|
|
77
|
+
* - 'allow': Allow without logging
|
|
78
|
+
*/
|
|
79
|
+
[COMPATIBILITY_POLICY_TYPES.COMPATIBLE]: {
|
|
80
|
+
compatible: true,
|
|
81
|
+
level: COMPATIBILITY_POLICY_ERROR_LEVELS.ALLOW,
|
|
82
|
+
message: generateFullyCompatibleMessage,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
export const getCompatibilityPolicyType = (params) => {
|
|
86
|
+
const mcpSemVer = semver.coerce(params.mcpVersion);
|
|
87
|
+
const apiSemVer = semver.coerce(params.apiVersion);
|
|
88
|
+
if (!mcpSemVer || !apiSemVer) {
|
|
89
|
+
return COMPATIBILITY_POLICY_TYPES.NO_VERSION;
|
|
90
|
+
}
|
|
91
|
+
if (semver.lt(apiSemVer, MIN_COMPATIBLE_API_VERSION)) {
|
|
92
|
+
return COMPATIBILITY_POLICY_TYPES.BELOW_MIN_VERSION;
|
|
93
|
+
}
|
|
94
|
+
if (mcpSemVer.major !== apiSemVer.major) {
|
|
95
|
+
return COMPATIBILITY_POLICY_TYPES.MAJOR_MISMATCH;
|
|
96
|
+
}
|
|
97
|
+
if (mcpSemVer.minor > apiSemVer.minor) {
|
|
98
|
+
return COMPATIBILITY_POLICY_TYPES.NEWER_MINOR;
|
|
99
|
+
}
|
|
100
|
+
if (mcpSemVer.minor < apiSemVer.minor) {
|
|
101
|
+
return COMPATIBILITY_POLICY_TYPES.OLDER_MINOR;
|
|
102
|
+
}
|
|
103
|
+
if (mcpSemVer.patch !== apiSemVer.patch) {
|
|
104
|
+
return COMPATIBILITY_POLICY_TYPES.PATCH_DIFF;
|
|
105
|
+
}
|
|
106
|
+
return COMPATIBILITY_POLICY_TYPES.COMPATIBLE;
|
|
107
|
+
};
|
|
108
|
+
export const getCompatibilityPolicy = (type) => {
|
|
109
|
+
return COMPATIBILITY_POLICY[type];
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Update guide template
|
|
113
|
+
*/
|
|
114
|
+
const updateGuide = `
|
|
115
|
+
Update Guide:
|
|
116
|
+
1. Download the latest release: https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest
|
|
117
|
+
2. Replace TouchDesigner components:
|
|
118
|
+
- Delete the existing touchdesigner-mcp-td folder
|
|
119
|
+
- Extract and import the new mcp_webserver_base.tox
|
|
120
|
+
3. Restart TouchDesigner and the MCP client (e.g., Claude Desktop)
|
|
121
|
+
|
|
122
|
+
For more details, see: https://github.com/8beeeaaat/touchdesigner-mcp#troubleshooting-version-compatibility
|
|
123
|
+
`.trim();
|
|
124
|
+
/**
|
|
125
|
+
* Generate error message for unknown version information
|
|
126
|
+
*/
|
|
127
|
+
export function generateNoVersionMessage(args) {
|
|
128
|
+
return `
|
|
129
|
+
🚨 Version Information Missing
|
|
130
|
+
|
|
131
|
+
MCP Server: ${args.mcpVersion || "Unknown"}
|
|
132
|
+
API Server: ${args.apiVersion || "Unknown"}
|
|
133
|
+
|
|
134
|
+
Version information is required to ensure compatibility between the MCP server and TouchDesigner components.
|
|
135
|
+
Please ensure both components are updated to compatible versions.
|
|
136
|
+
|
|
137
|
+
${updateGuide}
|
|
138
|
+
`.trim();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generate error message for MAJOR version mismatch
|
|
142
|
+
*/
|
|
143
|
+
export function generateMajorMismatchMessage(args) {
|
|
144
|
+
return `
|
|
145
|
+
🚨 Version Incompatibility Detected
|
|
146
|
+
|
|
147
|
+
MCP Server: ${args.mcpVersion}
|
|
148
|
+
API Server: ${args.apiVersion}
|
|
149
|
+
|
|
150
|
+
MAJOR version mismatch indicates breaking changes.
|
|
151
|
+
Both components must be updated to compatible versions.
|
|
152
|
+
|
|
153
|
+
${updateGuide}
|
|
154
|
+
`.trim();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Generate error message when API version is below minimum compatible version
|
|
158
|
+
*/
|
|
159
|
+
export function generateMinVersionMessage(args) {
|
|
160
|
+
return `
|
|
161
|
+
⚠️ TouchDesigner API Server Update Required
|
|
162
|
+
|
|
163
|
+
Current: ${args.apiVersion}
|
|
164
|
+
Required: ${args.minRequired}+
|
|
165
|
+
|
|
166
|
+
Your TouchDesigner components are outdated and may not support all features.
|
|
167
|
+
|
|
168
|
+
${updateGuide}
|
|
169
|
+
`.trim();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generate warning message when MCP server has newer MINOR version
|
|
173
|
+
*/
|
|
174
|
+
export function generateNewerMinorMessage(args) {
|
|
175
|
+
return `
|
|
176
|
+
💡 Update Recommended
|
|
177
|
+
|
|
178
|
+
MCP Server: ${args.mcpVersion}
|
|
179
|
+
API Server: ${args.apiVersion}
|
|
180
|
+
|
|
181
|
+
The MCP server has newer features that may not work with your TouchDesigner components.
|
|
182
|
+
Consider updating for the best experience.
|
|
183
|
+
|
|
184
|
+
${updateGuide}
|
|
185
|
+
`.trim();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Generate warning message when API server has newer MINOR version
|
|
189
|
+
*/
|
|
190
|
+
export function generateOlderMinorMessage(args) {
|
|
191
|
+
return `
|
|
192
|
+
💡 Update Recommended
|
|
193
|
+
|
|
194
|
+
MCP Server: ${args.mcpVersion}
|
|
195
|
+
API Server: ${args.apiVersion}
|
|
196
|
+
|
|
197
|
+
Your TouchDesigner components have features that may not be supported by the MCP server.
|
|
198
|
+
Consider updating the MCP server for the best experience.
|
|
199
|
+
|
|
200
|
+
${updateGuide}
|
|
201
|
+
`.trim();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Generate warning message when PATCH versions differ
|
|
205
|
+
*/
|
|
206
|
+
export function generatePatchDiffMessage(args) {
|
|
207
|
+
return `
|
|
208
|
+
💡 Patch Version Mismatch
|
|
209
|
+
|
|
210
|
+
MCP Server: ${args.mcpVersion}
|
|
211
|
+
API Server: ${args.apiVersion}
|
|
212
|
+
|
|
213
|
+
The MCP server and TouchDesigner components have different PATCH versions.
|
|
214
|
+
While generally compatible, updating both to the latest versions is recommended.
|
|
215
|
+
|
|
216
|
+
${updateGuide}
|
|
217
|
+
`.trim();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Generate info message when versions are fully compatible
|
|
221
|
+
*
|
|
222
|
+
* @param mcpVersion MCP server version
|
|
223
|
+
* @param apiVersion TouchDesigner API server version
|
|
224
|
+
* @returns Info message
|
|
225
|
+
*/
|
|
226
|
+
export function generateFullyCompatibleMessage(args) {
|
|
227
|
+
return `
|
|
228
|
+
✅ Versions Fully Compatible
|
|
229
|
+
|
|
230
|
+
MCP Server: ${args.mcpVersion}
|
|
231
|
+
API Server: ${args.apiVersion}
|
|
232
|
+
|
|
233
|
+
Your MCP server and TouchDesigner components are fully compatible.
|
|
234
|
+
No action is needed.
|
|
235
|
+
`.trim();
|
|
236
|
+
}
|
package/dist/core/logger.js
CHANGED
|
@@ -14,10 +14,30 @@ export class McpLogger {
|
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
catch (error) {
|
|
17
|
+
// Only swallow the expected "Not connected" error during startup/shutdown
|
|
17
18
|
if (error instanceof Error && error.message === "Not connected") {
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
// For all other errors, log detailed information to help diagnose logging system failures
|
|
22
|
+
console.error("CRITICAL: Failed to send log to MCP server. Logging system may be compromised.", {
|
|
23
|
+
error: error instanceof Error ? error.message : String(error),
|
|
24
|
+
originalLogger: args.logger,
|
|
25
|
+
originalLogLevel: args.level,
|
|
26
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
27
|
+
});
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Console Logger implementation for standalone use (e.g., HTTP mode setup)
|
|
33
|
+
* Outputs to stderr to avoid interfering with stdio transport
|
|
34
|
+
*/
|
|
35
|
+
export class ConsoleLogger {
|
|
36
|
+
sendLog(args) {
|
|
37
|
+
const timestamp = new Date().toISOString();
|
|
38
|
+
const level = args.level?.toUpperCase() || "INFO";
|
|
39
|
+
const logger = args.logger || "unknown";
|
|
40
|
+
const data = args.data;
|
|
41
|
+
console.error(`[${timestamp}] [${level}] [${logger}] ${data}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/core/version.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
const requirePackage = createRequire(import.meta.url);
|
|
3
3
|
const packageJson = requirePackage("../../package.json");
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Current MCP server version
|
|
6
|
+
*/
|
|
7
|
+
export const getMcpServerVersion = () => packageJson.version ?? "0.0.0";
|
|
8
|
+
export const MCP_SERVER_VERSION = getMcpServerVersion();
|
|
9
|
+
/**
|
|
10
|
+
* Minimum compatible TouchDesigner API Server version required by the MCP server
|
|
11
|
+
*
|
|
12
|
+
* Loaded from package.json's mcpCompatibility.minApiVersion field.
|
|
13
|
+
* Falls back to the current package version if undefined.
|
|
14
|
+
*
|
|
15
|
+
* API Server must be at or above this version.
|
|
16
|
+
* - MAJOR mismatch: Error
|
|
17
|
+
* - MINOR/PATCH differences: Warning or allow
|
|
18
|
+
*
|
|
19
|
+
* Update when:
|
|
20
|
+
* - Introducing breaking API changes
|
|
21
|
+
* - Making incompatible changes to OpenAPI schema
|
|
22
|
+
*/
|
|
23
|
+
export const getMinCompatibleApiVersion = () => packageJson.mcpCompatibility?.minApiVersion ?? MCP_SERVER_VERSION;
|
|
24
|
+
export const MIN_COMPATIBLE_API_VERSION = getMinCompatibleApiVersion();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MCP_SERVER_VERSION } from "../../../core/version.js";
|
|
1
2
|
import { finalizeFormattedText, mergeFormatterOptions, } from "./responseFormatter.js";
|
|
2
3
|
export function formatTdInfo(data, options) {
|
|
3
4
|
const opts = mergeFormatterOptions(options);
|
|
@@ -6,17 +7,23 @@ export function formatTdInfo(data, options) {
|
|
|
6
7
|
context: { title: "TouchDesigner Info" },
|
|
7
8
|
});
|
|
8
9
|
}
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
:
|
|
10
|
+
const structured = {
|
|
11
|
+
"API Server Version": data.mcpApiVersion,
|
|
12
|
+
"MCP Server Version": MCP_SERVER_VERSION,
|
|
13
|
+
"Operating System": data.osName
|
|
14
|
+
? `${data.osName} ${data.osVersion ?? ""}`.trim()
|
|
15
|
+
: "Unknown",
|
|
16
|
+
"TouchDesigner Version": data.version,
|
|
17
|
+
};
|
|
18
|
+
const text = Object.entries(structured)
|
|
19
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
20
|
+
.join("\n");
|
|
16
21
|
return finalizeFormattedText(text.trim(), opts, {
|
|
17
|
-
context: {
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
context: {
|
|
23
|
+
title: "TouchDesigner Info",
|
|
24
|
+
},
|
|
25
|
+
structured,
|
|
26
|
+
template: "detailedPayload",
|
|
20
27
|
});
|
|
21
28
|
}
|
|
22
29
|
export function formatCreateNodeResult(data, options) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { McpLogger } from "../core/logger.js";
|
|
3
|
-
import {
|
|
3
|
+
import { MCP_SERVER_VERSION } from "../core/version.js";
|
|
4
4
|
import { registerPrompts } from "../features/prompts/index.js";
|
|
5
5
|
import { registerTools } from "../features/tools/index.js";
|
|
6
6
|
import { createTouchDesignerClient } from "../tdClient/index.js";
|
|
@@ -19,7 +19,7 @@ export class TouchDesignerServer {
|
|
|
19
19
|
constructor() {
|
|
20
20
|
this.server = new McpServer({
|
|
21
21
|
name: "TouchDesigner",
|
|
22
|
-
version:
|
|
22
|
+
version: MCP_SERVER_VERSION,
|
|
23
23
|
}, {
|
|
24
24
|
capabilities: {
|
|
25
25
|
logging: {},
|
|
@@ -32,6 +32,25 @@ export class TouchDesignerServer {
|
|
|
32
32
|
this.connectionManager = new ConnectionManager(this.server, this.logger);
|
|
33
33
|
this.registerAllFeatures();
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a new TouchDesignerServer instance
|
|
37
|
+
*
|
|
38
|
+
* Factory method for creating server instances in multi-session scenarios.
|
|
39
|
+
* Each session should have its own server instance to maintain independent MCP protocol state.
|
|
40
|
+
*
|
|
41
|
+
* @returns McpServer instance ready for connection to a transport
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // In TransportRegistry
|
|
46
|
+
* const serverFactory = () => TouchDesignerServer.create();
|
|
47
|
+
* const transport = await registry.getOrCreate(sessionId, body, serverFactory);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
static create() {
|
|
51
|
+
const instance = new TouchDesignerServer();
|
|
52
|
+
return instance.server;
|
|
53
|
+
}
|
|
35
54
|
/**
|
|
36
55
|
* Connect to MCP transport
|
|
37
56
|
*/
|