touchdesigner-mcp-server 1.3.0 → 1.3.1
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 +29 -3
- package/README.md +31 -5
- package/dist/core/compatibility.js +236 -0
- package/dist/core/logger.js +8 -1
- package/dist/core/version.js +21 -1
- package/dist/features/tools/presenter/operationFormatter.js +17 -10
- package/dist/server/touchDesignerServer.js +2 -2
- package/dist/tdClient/touchDesignerClient.js +203 -83
- package/package.json +14 -7
package/README.ja.md
CHANGED
|
@@ -366,13 +366,39 @@ td/
|
|
|
366
366
|
|
|
367
367
|
### バージョン互換性のトラブルシューティング
|
|
368
368
|
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
柔軟な互換性チェックのために**セマンティックバージョニング**を使用しています
|
|
370
|
+
|
|
371
|
+
| MCP Server | API Server | 最小互換APIバージョン | 動作 | ステータス | 備考 |
|
|
372
|
+
|------------|------------|----------------|----------|--------|-------|
|
|
373
|
+
| 1.3.x | 1.3.0 | 1.3.0 | ✅ 正常動作 | 互換 | 推奨ベースライン構成 |
|
|
374
|
+
| 1.3.x | 1.4.0 | 1.3.0 | ⚠️ 警告表示、実行継続 | 警告 | 旧MCP MINORと新API、新機能未対応の可能性 |
|
|
375
|
+
| 1.4.0 | 1.3.x | 1.3.0 | ⚠️ 警告表示、実行継続 | 警告 | 新MCP MINORに追加機能がある可能性 |
|
|
376
|
+
| 1.3.2 | 1.3.1 | 1.3.2 | ❌ 実行停止 | エラー | APIが最小互換バージョン未満 |
|
|
377
|
+
| 2.0.0 | 1.x.x | N/A | ❌ 実行停止 | エラー | MAJORバージョン相違 = 破壊的変更 |
|
|
378
|
+
|
|
379
|
+
**互換性ルール**:
|
|
380
|
+
|
|
381
|
+
- ✅ **互換**: 同じMAJORバージョン、かつAPIバージョン ≥ 最小互換バージョン
|
|
382
|
+
- ⚠️ **警告**: 同じMAJOR内でMINORまたはPATCHバージョンが異なる(警告表示、実行継続)
|
|
383
|
+
- ❌ **エラー**: MAJORバージョンが異なる、またはAPIサーバー < 最小互換バージョン(即座に実行停止、更新が必要)
|
|
384
|
+
|
|
385
|
+
- **互換性エラーを解決するには:**
|
|
371
386
|
1. リリースページから最新の [touchdesigner-mcp-td.zip](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest/download/touchdesigner-mcp-td.zip) をダウンロードします。
|
|
372
387
|
2. 既存の `touchdesigner-mcp-td` フォルダを削除し、新しく展開した内容に置き換えます。
|
|
373
388
|
3. TouchDesignerプロジェクトから古い `mcp_webserver_base` コンポーネントを削除し、新しいフォルダから `.tox` をインポートします。
|
|
374
389
|
4. TouchDesignerとMCPサーバーを実行しているAIエージェント(例:Claude Desktop)を再起動します。
|
|
375
|
-
|
|
390
|
+
|
|
391
|
+
- **開発者向け:** ローカルで開発している場合は、`package.json` を編集した後に `npm run version` を実行してください(または単に `npm version ...` を使用してください)。これにより、Python API(`pyproject.toml` + `td/modules/utils/version.py`)、MCPバンドルマニフェスト、およびレジストリメタデータが同期され、ランタイム互換性チェックが成功するようになります。
|
|
392
|
+
|
|
393
|
+
### 接続エラーのトラブルシューティング
|
|
394
|
+
|
|
395
|
+
- `TouchDesignerClient` は接続に失敗した互換性チェック結果を **最大5秒間キャッシュ**し、その間のツール呼び出しでは同じエラーを再利用して TouchDesigner への無駄な負荷を避けます。TTL が切れると自動的に再試行します。
|
|
396
|
+
- MCP サーバーが TouchDesigner に接続できない場合は、次のようなガイド付きメッセージが表示されます:
|
|
397
|
+
- `ECONNREFUSED` / "connect refused": TouchDesigner を起動し、`mcp_webserver_base.tox` からインポートした WebServer DAT がアクティブか、ポート設定(デフォルト `9981`)が正しいか確認してください。
|
|
398
|
+
- `ETIMEDOUT` / "timeout": TouchDesigner の応答が遅い、またはネットワークが詰まっています。TouchDesigner/ WebServer DAT の再起動やネットワーク状況の確認を行ってください。
|
|
399
|
+
- `ENOTFOUND` / `getaddrinfo`: ホスト名が解決できません。特別な理由がなければ `127.0.0.1` を使用してください。
|
|
400
|
+
- これらの詳細なエラーテキストは `ILogger` にも出力されるため、MCP 側のログを確認すれば TouchDesigner に到達する前に止まった理由を把握できます。
|
|
401
|
+
- 問題を解決したら再度ツールを実行するだけで、キャッシュされたエラーがクリアされて接続チェックがやり直されます。
|
|
376
402
|
|
|
377
403
|
## 開発で貢献
|
|
378
404
|
|
package/README.md
CHANGED
|
@@ -366,13 +366,39 @@ The build process (`npm run build`) runs all necessary generation steps (`npm ru
|
|
|
366
366
|
|
|
367
367
|
### Troubleshooting version compatibility
|
|
368
368
|
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
The MCP server uses **semantic versioning** for flexible compatibility checks
|
|
370
|
+
|
|
371
|
+
| MCP Server | API Server | Minimum compatible API version | Behavior | Status | Notes |
|
|
372
|
+
|------------|------------|----------------|----------|--------|-------|
|
|
373
|
+
| 1.3.x | 1.3.0 | 1.3.0 | ✅ Works normally | Compatible | Recommended baseline configuration |
|
|
374
|
+
| 1.3.x | 1.4.0 | 1.3.0 | ⚠️ Warning shown, continues | Warning | Older MCP MINOR with newer API may lack new features |
|
|
375
|
+
| 1.4.0 | 1.3.x | 1.3.0 | ⚠️ Warning shown, continues | Warning | Newer MCP MINOR may have additional features |
|
|
376
|
+
| 1.3.2 | 1.3.1 | 1.3.2 | ❌ Execution stops | Error | API below minimum compatible version |
|
|
377
|
+
| 2.0.0 | 1.x.x | N/A | ❌ Execution stops | Error | Different MAJOR = breaking changes |
|
|
378
|
+
|
|
379
|
+
**Compatibility Rules**:
|
|
380
|
+
|
|
381
|
+
- ✅ **Compatible**: Same MAJOR version AND API version ≥ 1.3.0 (minimum compatible version)
|
|
382
|
+
- ⚠️ **Warning**: Different MINOR or PATCH versions within the same MAJOR version (shows warning but continues execution)
|
|
383
|
+
- ❌ **Error**: Different MAJOR versions OR API server < 1.3.0 (execution stops immediately, update required)
|
|
384
|
+
|
|
385
|
+
- **To resolve compatibility errors:**
|
|
371
386
|
1. Download the latest [touchdesigner-mcp-td.zip](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest/download/touchdesigner-mcp-td.zip) from the releases page.
|
|
372
|
-
2. Delete the existing
|
|
373
|
-
3. Remove the old
|
|
387
|
+
2. Delete the existing `touchdesigner-mcp-td` folder and replace it with the newly extracted contents.
|
|
388
|
+
3. Remove the old `mcp_webserver_base` component from your TouchDesigner project and import the `.tox` from the new folder.
|
|
374
389
|
4. Restart TouchDesigner and the AI agent running the MCP server (e.g., Claude Desktop).
|
|
375
|
-
|
|
390
|
+
|
|
391
|
+
- **For developers:** When developing locally, run `npm run version` after editing `package.json` (or simply use `npm version ...`). This keeps the Python API (`pyproject.toml` + `td/modules/utils/version.py`), MCP bundle manifest, and registry metadata in sync so that the runtime compatibility check succeeds.
|
|
392
|
+
|
|
393
|
+
### Troubleshooting connection errors
|
|
394
|
+
|
|
395
|
+
- `TouchDesignerClient` caches failed connection checks for **5 seconds**. Subsequent tool calls reuse the cached error to avoid spamming TouchDesigner and automatically retry after the TTL expires.
|
|
396
|
+
- When the MCP server cannot reach TouchDesigner, you now get guided error messages with concrete fixes:
|
|
397
|
+
- `ECONNREFUSED` / "connect refused": start TouchDesigner, ensure the WebServer DAT from `mcp_webserver_base.tox` is running, and confirm the configured port (default `9981`).
|
|
398
|
+
- `ETIMEDOUT` / "timeout": TouchDesigner is responding slowly or the network is blocked. Restart TouchDesigner/WebServer DAT or check your network connection.
|
|
399
|
+
- `ENOTFOUND` / `getaddrinfo`: the host name is invalid. Use `127.0.0.1` unless you explicitly changed it.
|
|
400
|
+
- The structured error text is also logged through `ILogger`, so you can check the MCP logs to understand why a request stopped before hitting TouchDesigner.
|
|
401
|
+
- Once the underlying issue is fixed, simply run the tool again—the client clears the cached error and re-verifies the connection automatically.
|
|
376
402
|
|
|
377
403
|
## Contributing
|
|
378
404
|
|
|
@@ -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,17 @@ 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
|
}
|
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: {},
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { getCompatibilityPolicy, getCompatibilityPolicyType, } from "../core/compatibility.js";
|
|
1
3
|
import { createErrorResult, createSuccessResult } from "../core/result.js";
|
|
2
|
-
import {
|
|
4
|
+
import { MCP_SERVER_VERSION, MIN_COMPATIBLE_API_VERSION, } from "../core/version.js";
|
|
3
5
|
import { createNode as apiCreateNode, deleteNode as apiDeleteNode, execNodeMethod as apiExecNodeMethod, execPythonScript as apiExecPythonScript, getModuleHelp as apiGetModuleHelp, getNodeDetail as apiGetNodeDetail, getNodeErrors as apiGetNodeErrors, getNodes as apiGetNodes, getTdInfo as apiGetTdInfo, getTdPythonClassDetails as apiGetTdPythonClassDetails, getTdPythonClasses as apiGetTdPythonClasses, updateNode as apiUpdateNode, } from "../gen/endpoints/TouchDesignerAPI.js";
|
|
4
|
-
const updateGuide = `
|
|
5
|
-
1. Download the latest [touchdesigner-mcp-td.zip](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest/download/touchdesigner-mcp-td.zip) from the releases page.
|
|
6
|
-
2. Delete the existing \`touchdesigner-mcp-td\` folder and replace it with the newly extracted contents.
|
|
7
|
-
3. Remove the old \`mcp_webserver_base\` component from your TouchDesigner project and import the \`.tox\` from the new folder.
|
|
8
|
-
4. Restart TouchDesigner and the AI agent running the MCP server (e.g., Claude Desktop).
|
|
9
|
-
`;
|
|
10
6
|
/**
|
|
11
7
|
* Default implementation of ITouchDesignerApi using generated API clients
|
|
12
8
|
*/
|
|
@@ -24,6 +20,7 @@ const defaultApiClient = {
|
|
|
24
20
|
getTdPythonClasses: apiGetTdPythonClasses,
|
|
25
21
|
updateNode: apiUpdateNode,
|
|
26
22
|
};
|
|
23
|
+
export const ERROR_CACHE_TTL_MS = 5000; // 5 seconds
|
|
27
24
|
/**
|
|
28
25
|
* Null logger implementation that discards all logs
|
|
29
26
|
*/
|
|
@@ -68,6 +65,21 @@ export class TouchDesignerClient {
|
|
|
68
65
|
logger;
|
|
69
66
|
api;
|
|
70
67
|
verifiedCompatibilityError;
|
|
68
|
+
cachedCompatibilityCheck;
|
|
69
|
+
errorCacheTimestamp;
|
|
70
|
+
/**
|
|
71
|
+
* Initialize TouchDesigner client with optional dependencies
|
|
72
|
+
*/
|
|
73
|
+
constructor(params = {}) {
|
|
74
|
+
this.logger = params.logger || nullLogger;
|
|
75
|
+
this.api = params.httpClient || defaultApiClient;
|
|
76
|
+
this.verifiedCompatibilityError = null;
|
|
77
|
+
this.cachedCompatibilityCheck = false;
|
|
78
|
+
this.errorCacheTimestamp = null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Log debug message
|
|
82
|
+
*/
|
|
71
83
|
logDebug(message, context) {
|
|
72
84
|
const data = context ? { message, ...context } : { message };
|
|
73
85
|
this.logger.sendLog({
|
|
@@ -76,176 +88,284 @@ export class TouchDesignerClient {
|
|
|
76
88
|
logger: "TouchDesignerClient",
|
|
77
89
|
});
|
|
78
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if the cached error should be cleared (TTL expired)
|
|
93
|
+
*/
|
|
94
|
+
shouldClearErrorCache() {
|
|
95
|
+
if (!this.errorCacheTimestamp) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
return now - this.errorCacheTimestamp >= ERROR_CACHE_TTL_MS;
|
|
100
|
+
}
|
|
79
101
|
/**
|
|
80
102
|
* Verify compatibility with the TouchDesigner server
|
|
81
103
|
*/
|
|
82
104
|
async verifyCompatibility() {
|
|
105
|
+
// If we've already verified compatibility successfully, skip re-verification
|
|
106
|
+
if (this.cachedCompatibilityCheck && !this.verifiedCompatibilityError) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Clear cached error if TTL has expired
|
|
110
|
+
if (this.verifiedCompatibilityError && this.shouldClearErrorCache()) {
|
|
111
|
+
this.logDebug("Clearing cached connection error (TTL expired), retrying...");
|
|
112
|
+
this.verifiedCompatibilityError = null;
|
|
113
|
+
this.errorCacheTimestamp = null;
|
|
114
|
+
this.cachedCompatibilityCheck = false;
|
|
115
|
+
}
|
|
83
116
|
if (this.verifiedCompatibilityError) {
|
|
117
|
+
// Re-log the cached error so users know it's still failing
|
|
118
|
+
const ttlRemaining = this.errorCacheTimestamp
|
|
119
|
+
? Math.max(0, Math.ceil((ERROR_CACHE_TTL_MS - (Date.now() - this.errorCacheTimestamp)) /
|
|
120
|
+
1000))
|
|
121
|
+
: 0;
|
|
122
|
+
this.logDebug(`Using cached connection error (retry in ${ttlRemaining} seconds)`, {
|
|
123
|
+
cacheAge: this.errorCacheTimestamp
|
|
124
|
+
? Date.now() - this.errorCacheTimestamp
|
|
125
|
+
: 0,
|
|
126
|
+
cachedError: this.verifiedCompatibilityError.message,
|
|
127
|
+
});
|
|
84
128
|
throw this.verifiedCompatibilityError;
|
|
85
129
|
}
|
|
86
130
|
const result = await this.verifyVersionCompatibility();
|
|
87
131
|
if (result.success) {
|
|
88
132
|
this.verifiedCompatibilityError = null;
|
|
133
|
+
this.errorCacheTimestamp = null;
|
|
134
|
+
this.cachedCompatibilityCheck = true;
|
|
135
|
+
this.logDebug("Compatibility verified successfully");
|
|
89
136
|
return;
|
|
90
137
|
}
|
|
138
|
+
// Log when we're caching a NEW error
|
|
139
|
+
this.logDebug(`Caching connection error for ${ERROR_CACHE_TTL_MS / 1000} seconds`, {
|
|
140
|
+
error: result.error.message,
|
|
141
|
+
});
|
|
91
142
|
this.verifiedCompatibilityError = result.error;
|
|
143
|
+
this.errorCacheTimestamp = Date.now();
|
|
144
|
+
this.cachedCompatibilityCheck = false;
|
|
92
145
|
throw result.error;
|
|
93
146
|
}
|
|
94
147
|
/**
|
|
95
|
-
*
|
|
148
|
+
* Wrapper for API calls that require compatibility verification
|
|
149
|
+
* @private
|
|
96
150
|
*/
|
|
97
|
-
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
|
|
151
|
+
async apiCall(message, call, context) {
|
|
152
|
+
this.logDebug(message, context);
|
|
153
|
+
await this.verifyCompatibility();
|
|
154
|
+
const result = await call();
|
|
155
|
+
return handleApiResponse(result);
|
|
101
156
|
}
|
|
102
157
|
/**
|
|
103
158
|
* Execute a node method
|
|
104
159
|
*/
|
|
105
160
|
async execNodeMethod(params) {
|
|
106
|
-
this.
|
|
161
|
+
return this.apiCall("Executing node method", () => this.api.execNodeMethod(params), {
|
|
107
162
|
method: params.method,
|
|
108
163
|
nodePath: params.nodePath,
|
|
109
164
|
});
|
|
110
|
-
await this.verifyCompatibility();
|
|
111
|
-
const result = await this.api.execNodeMethod(params);
|
|
112
|
-
return handleApiResponse(result);
|
|
113
165
|
}
|
|
114
166
|
/**
|
|
115
167
|
* Execute a script in TouchDesigner
|
|
116
168
|
*/
|
|
117
169
|
async execPythonScript(params) {
|
|
118
|
-
this.
|
|
119
|
-
await this.verifyCompatibility();
|
|
120
|
-
const result = await this.api.execPythonScript(params);
|
|
121
|
-
return handleApiResponse(result);
|
|
170
|
+
return this.apiCall("Executing Python script", () => this.api.execPythonScript(params), { params });
|
|
122
171
|
}
|
|
123
172
|
/**
|
|
124
173
|
* Get TouchDesigner server information
|
|
125
174
|
*/
|
|
126
175
|
async getTdInfo() {
|
|
127
|
-
this.
|
|
128
|
-
await this.verifyCompatibility();
|
|
129
|
-
const result = await this.api.getTdInfo();
|
|
130
|
-
return handleApiResponse(result);
|
|
176
|
+
return this.apiCall("Getting server info", () => this.api.getTdInfo());
|
|
131
177
|
}
|
|
132
178
|
/**
|
|
133
179
|
* Get list of nodes
|
|
134
180
|
*/
|
|
135
181
|
async getNodes(params) {
|
|
136
|
-
this.
|
|
137
|
-
parentPath: params.parentPath,
|
|
138
|
-
});
|
|
139
|
-
await this.verifyCompatibility();
|
|
140
|
-
const result = await this.api.getNodes(params);
|
|
141
|
-
return handleApiResponse(result);
|
|
182
|
+
return this.apiCall("Getting nodes for parent", () => this.api.getNodes(params), { parentPath: params.parentPath });
|
|
142
183
|
}
|
|
143
184
|
/**
|
|
144
185
|
* Get node properties
|
|
145
186
|
*/
|
|
146
187
|
async getNodeDetail(params) {
|
|
147
|
-
this.
|
|
148
|
-
nodePath: params.nodePath,
|
|
149
|
-
});
|
|
150
|
-
await this.verifyCompatibility();
|
|
151
|
-
const result = await this.api.getNodeDetail(params);
|
|
152
|
-
return handleApiResponse(result);
|
|
188
|
+
return this.apiCall("Getting properties for node", () => this.api.getNodeDetail(params), { nodePath: params.nodePath });
|
|
153
189
|
}
|
|
154
190
|
/**
|
|
155
191
|
* Get node error information
|
|
156
192
|
*/
|
|
157
193
|
async getNodeErrors(params) {
|
|
158
|
-
this.
|
|
159
|
-
nodePath: params.nodePath,
|
|
160
|
-
});
|
|
161
|
-
await this.verifyCompatibility();
|
|
162
|
-
const result = await this.api.getNodeErrors(params);
|
|
163
|
-
return handleApiResponse(result);
|
|
194
|
+
return this.apiCall("Checking node errors", () => this.api.getNodeErrors(params), { nodePath: params.nodePath });
|
|
164
195
|
}
|
|
165
196
|
/**
|
|
166
197
|
* Create a new node
|
|
167
198
|
*/
|
|
168
199
|
async createNode(params) {
|
|
169
|
-
this.
|
|
200
|
+
return this.apiCall("Creating node", () => this.api.createNode(params), {
|
|
170
201
|
nodeName: params.nodeName,
|
|
171
202
|
nodeType: params.nodeType,
|
|
172
203
|
parentPath: params.parentPath,
|
|
173
204
|
});
|
|
174
|
-
await this.verifyCompatibility();
|
|
175
|
-
const result = await this.api.createNode(params);
|
|
176
|
-
return handleApiResponse(result);
|
|
177
205
|
}
|
|
178
206
|
/**
|
|
179
207
|
* Update node properties
|
|
180
208
|
*/
|
|
181
209
|
async updateNode(params) {
|
|
182
|
-
this.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return handleApiResponse(result);
|
|
210
|
+
return this.apiCall("Updating node", () => this.api.updateNode(params), {
|
|
211
|
+
nodePath: params.nodePath,
|
|
212
|
+
});
|
|
186
213
|
}
|
|
187
214
|
/**
|
|
188
215
|
* Delete a node
|
|
189
216
|
*/
|
|
190
217
|
async deleteNode(params) {
|
|
191
|
-
this.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return handleApiResponse(result);
|
|
218
|
+
return this.apiCall("Deleting node", () => this.api.deleteNode(params), {
|
|
219
|
+
nodePath: params.nodePath,
|
|
220
|
+
});
|
|
195
221
|
}
|
|
196
222
|
/**
|
|
197
223
|
* Get list of available Python classes/modules in TouchDesigner
|
|
198
224
|
*/
|
|
199
225
|
async getClasses() {
|
|
200
|
-
this.
|
|
201
|
-
await this.verifyCompatibility();
|
|
202
|
-
const result = await this.api.getTdPythonClasses();
|
|
203
|
-
return handleApiResponse(result);
|
|
226
|
+
return this.apiCall("Getting Python classes", () => this.api.getTdPythonClasses());
|
|
204
227
|
}
|
|
205
228
|
/**
|
|
206
229
|
* Get details of a specific class/module
|
|
207
230
|
*/
|
|
208
231
|
async getClassDetails(className) {
|
|
209
|
-
this.
|
|
210
|
-
await this.verifyCompatibility();
|
|
211
|
-
const result = await this.api.getTdPythonClassDetails(className);
|
|
212
|
-
return handleApiResponse(result);
|
|
232
|
+
return this.apiCall("Getting class details", () => this.api.getTdPythonClassDetails(className), { className });
|
|
213
233
|
}
|
|
214
234
|
/**
|
|
215
235
|
* Retrieve Python help() documentation for modules/classes
|
|
216
236
|
*/
|
|
217
237
|
async getModuleHelp(params) {
|
|
218
|
-
this.
|
|
219
|
-
await this.verifyCompatibility();
|
|
220
|
-
const result = await this.api.getModuleHelp(params);
|
|
221
|
-
return handleApiResponse(result);
|
|
238
|
+
return this.apiCall("Getting module help", () => this.api.getModuleHelp(params), { moduleName: params.moduleName });
|
|
222
239
|
}
|
|
223
240
|
async verifyVersionCompatibility() {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
241
|
+
let tdInfoResult;
|
|
242
|
+
try {
|
|
243
|
+
tdInfoResult = await this.api.getTdInfo();
|
|
227
244
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
245
|
+
catch (error) {
|
|
246
|
+
// Use axios.isAxiosError() for robust network/HTTP error detection
|
|
247
|
+
// AxiosError includes connection refused, timeout, network errors, etc.
|
|
248
|
+
// All other errors (TypeError, etc.) are programming errors and should propagate
|
|
249
|
+
if (!axios.isAxiosError(error)) {
|
|
250
|
+
// This is a programming error (e.g., TypeError, ReferenceError), not a connection error
|
|
251
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
252
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
253
|
+
this.logger.sendLog({
|
|
254
|
+
data: {
|
|
255
|
+
error: errorMessage,
|
|
256
|
+
errorType: "programming_error",
|
|
257
|
+
stack: errorStack,
|
|
258
|
+
},
|
|
259
|
+
level: "error",
|
|
260
|
+
logger: "TouchDesignerClient",
|
|
261
|
+
});
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
// Handle AxiosError (network/HTTP errors)
|
|
265
|
+
const rawMessage = error.message || "Unknown network error";
|
|
266
|
+
const errorMessage = this.formatConnectionError(rawMessage);
|
|
267
|
+
this.logger.sendLog({
|
|
268
|
+
data: { error: rawMessage, errorType: "connection" },
|
|
269
|
+
level: "error",
|
|
270
|
+
logger: "TouchDesignerClient",
|
|
271
|
+
});
|
|
272
|
+
return createErrorResult(new Error(errorMessage));
|
|
231
273
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (normalizedServerVersion !== normalizedApiVersion) {
|
|
274
|
+
if (!tdInfoResult.success) {
|
|
275
|
+
const errorMessage = this.formatConnectionError(tdInfoResult.error);
|
|
235
276
|
this.logger.sendLog({
|
|
236
|
-
data: {
|
|
237
|
-
message: "MCP server and TouchDesigner API server versions are incompatible",
|
|
238
|
-
touchDesignerApiVersion: normalizedApiVersion,
|
|
239
|
-
touchDesignerServerVersion: normalizedServerVersion,
|
|
240
|
-
},
|
|
277
|
+
data: { error: tdInfoResult.error, errorType: "api_response" },
|
|
241
278
|
level: "error",
|
|
242
279
|
logger: "TouchDesignerClient",
|
|
243
280
|
});
|
|
244
|
-
return createErrorResult(new Error(
|
|
281
|
+
return createErrorResult(new Error(errorMessage));
|
|
282
|
+
}
|
|
283
|
+
const apiVersionRaw = tdInfoResult.data?.mcpApiVersion?.trim() || "";
|
|
284
|
+
const result = this.checkVersionCompatibility(MCP_SERVER_VERSION, apiVersionRaw);
|
|
285
|
+
this.logger.sendLog({
|
|
286
|
+
data: {
|
|
287
|
+
apiVersion: result.details.apiVersion,
|
|
288
|
+
mcpVersion: result.details.mcpVersion,
|
|
289
|
+
message: result.message,
|
|
290
|
+
minRequired: result.details.minRequired,
|
|
291
|
+
},
|
|
292
|
+
level: result.level,
|
|
293
|
+
logger: "TouchDesignerClient",
|
|
294
|
+
});
|
|
295
|
+
if (result.level === "error") {
|
|
296
|
+
return createErrorResult(new Error(result.message));
|
|
245
297
|
}
|
|
246
298
|
return createSuccessResult(undefined);
|
|
247
299
|
}
|
|
248
|
-
|
|
249
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Format connection errors with helpful messages
|
|
302
|
+
*/
|
|
303
|
+
formatConnectionError(error) {
|
|
304
|
+
if (!error) {
|
|
305
|
+
return "Failed to connect to TouchDesigner API server (unknown error)";
|
|
306
|
+
}
|
|
307
|
+
// Check for common connection errors
|
|
308
|
+
if (error.includes("ECONNREFUSED") ||
|
|
309
|
+
error.toLowerCase().includes("connect refused")) {
|
|
310
|
+
return `🔌 TouchDesigner Connection Failed
|
|
311
|
+
|
|
312
|
+
Cannot connect to TouchDesigner API server at the configured address.
|
|
313
|
+
|
|
314
|
+
Possible causes:
|
|
315
|
+
1. TouchDesigner is not running
|
|
316
|
+
→ Please start TouchDesigner
|
|
317
|
+
|
|
318
|
+
2. WebServer DAT is not active
|
|
319
|
+
→ Import 'mcp_webserver_base.tox' and ensure it's active
|
|
320
|
+
|
|
321
|
+
3. Wrong port configuration
|
|
322
|
+
→ Default port is 9981, check your configuration
|
|
323
|
+
|
|
324
|
+
For setup instructions, visit:
|
|
325
|
+
https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest
|
|
326
|
+
|
|
327
|
+
Original error: ${error}`;
|
|
328
|
+
}
|
|
329
|
+
if (error.includes("ETIMEDOUT") || error.includes("timeout")) {
|
|
330
|
+
return `⏱️ TouchDesigner Connection Timeout
|
|
331
|
+
|
|
332
|
+
The connection to TouchDesigner timed out.
|
|
333
|
+
|
|
334
|
+
Possible causes:
|
|
335
|
+
1. TouchDesigner is slow to respond
|
|
336
|
+
2. Network issues
|
|
337
|
+
3. WebServer DAT is overloaded
|
|
338
|
+
|
|
339
|
+
Try restarting TouchDesigner or check the network connection.
|
|
340
|
+
|
|
341
|
+
Original error: ${error}`;
|
|
342
|
+
}
|
|
343
|
+
if (error.includes("ENOTFOUND") || error.includes("getaddrinfo")) {
|
|
344
|
+
return `🌐 Invalid Host Configuration
|
|
345
|
+
|
|
346
|
+
Cannot resolve the TouchDesigner API server hostname.
|
|
347
|
+
|
|
348
|
+
Please check your host configuration (default: 127.0.0.1)
|
|
349
|
+
|
|
350
|
+
Original error: ${error}`;
|
|
351
|
+
}
|
|
352
|
+
// Generic error message
|
|
353
|
+
return `Failed to connect to TouchDesigner API server: ${error}`;
|
|
354
|
+
}
|
|
355
|
+
checkVersionCompatibility(mcpVersion, apiVersion) {
|
|
356
|
+
const policyType = getCompatibilityPolicyType({ apiVersion, mcpVersion });
|
|
357
|
+
const policy = getCompatibilityPolicy(policyType);
|
|
358
|
+
const details = {
|
|
359
|
+
apiVersion,
|
|
360
|
+
mcpVersion,
|
|
361
|
+
minRequired: MIN_COMPATIBLE_API_VERSION,
|
|
362
|
+
};
|
|
363
|
+
const message = policy.message(details);
|
|
364
|
+
return {
|
|
365
|
+
compatible: policy.compatible,
|
|
366
|
+
details,
|
|
367
|
+
level: policy.level,
|
|
368
|
+
message,
|
|
369
|
+
};
|
|
250
370
|
}
|
|
251
371
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "touchdesigner-mcp-server",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "MCP server for TouchDesigner",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"author": "8beeeaaat",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"mcpName": "io.github.8beeeaaat/touchdesigner-mcp-server",
|
|
16
|
+
"mcpCompatibility": {
|
|
17
|
+
"minApiVersion": "1.3.0"
|
|
18
|
+
},
|
|
16
19
|
"bugs": {
|
|
17
20
|
"url": "https://github.com/8beeeaaat/touchdesigner-mcp/issues"
|
|
18
21
|
},
|
|
@@ -23,13 +26,14 @@
|
|
|
23
26
|
"touchdesigner-mcp-server": "dist/cli.js"
|
|
24
27
|
},
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
27
30
|
"@mozilla/readability": "^0.6.0",
|
|
28
31
|
"@types/axios": "^0.14.4",
|
|
29
32
|
"@types/ws": "^8.18.1",
|
|
30
33
|
"@types/yargs": "^17.0.35",
|
|
31
34
|
"axios": "^1.13.2",
|
|
32
35
|
"mustache": "^4.2.0",
|
|
36
|
+
"semver": "^7.7.3",
|
|
33
37
|
"yaml": "^2.8.2",
|
|
34
38
|
"zod": "4.1.13"
|
|
35
39
|
},
|
|
@@ -39,15 +43,16 @@
|
|
|
39
43
|
"@types/jsdom": "^27.0.0",
|
|
40
44
|
"@types/mustache": "^4.2.6",
|
|
41
45
|
"@types/node": "^24.10.1",
|
|
42
|
-
"@
|
|
46
|
+
"@types/semver": "^7.7.1",
|
|
47
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
43
48
|
"archiver": "^7.0.1",
|
|
44
|
-
"msw": "^2.12.
|
|
49
|
+
"msw": "^2.12.4",
|
|
45
50
|
"npm-run-all": "^4.1.5",
|
|
46
51
|
"orval": "^7.17.0",
|
|
47
|
-
"prettier": "^3.7.
|
|
52
|
+
"prettier": "^3.7.4",
|
|
48
53
|
"shx": "^0.4.0",
|
|
49
54
|
"typescript": "^5.9.3",
|
|
50
|
-
"vitest": "^4.0.
|
|
55
|
+
"vitest": "^4.0.15"
|
|
51
56
|
},
|
|
52
57
|
"type": "module",
|
|
53
58
|
"exports": {
|
|
@@ -79,8 +84,10 @@
|
|
|
79
84
|
"test:integration": "vitest run ./tests/integration",
|
|
80
85
|
"test:unit": "vitest run ./tests/unit",
|
|
81
86
|
"coverage": "vitest run --coverage",
|
|
87
|
+
"version": "run-p version:*",
|
|
88
|
+
"version:api": "node ./scripts/syncApiServerVersions.ts",
|
|
89
|
+
"version:mcp": "node ./scripts/syncMcpServerVersions.ts",
|
|
82
90
|
"gen": "run-s gen:*",
|
|
83
|
-
"gen:version": "node ./scripts/syncVersions.ts",
|
|
84
91
|
"gen:webserver": "openapi-generator-cli generate -i ./src/api/index.yml -g python-flask -o ./td/modules/td_server",
|
|
85
92
|
"gen:handlers": "node td/genHandlers.js",
|
|
86
93
|
"gen:mcp": "orval --config ./orval.config.ts"
|