touchdesigner-mcp-server 1.2.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 +46 -0
- package/README.md +46 -0
- package/dist/cli.js +1 -1
- package/dist/core/compatibility.js +236 -0
- package/dist/core/constants.js +5 -3
- package/dist/core/errorHandling.js +18 -3
- package/dist/core/logger.js +17 -32
- package/dist/core/result.js +2 -2
- package/dist/core/version.js +24 -0
- package/dist/features/prompts/handlers/td_prompts.js +24 -18
- package/dist/features/tools/handlers/tdTools.js +75 -18
- package/dist/features/tools/metadata/touchDesignerToolMetadata.js +246 -172
- package/dist/features/tools/presenter/classListFormatter.js +22 -22
- package/dist/features/tools/presenter/index.js +2 -0
- package/dist/features/tools/presenter/moduleHelpFormatter.js +315 -0
- package/dist/features/tools/presenter/nodeDetailsFormatter.js +17 -17
- package/dist/features/tools/presenter/nodeErrorsFormatter.js +68 -0
- package/dist/features/tools/presenter/nodeListFormatter.js +12 -12
- package/dist/features/tools/presenter/operationFormatter.js +26 -19
- package/dist/features/tools/presenter/responseFormatter.js +4 -4
- package/dist/features/tools/presenter/scriptResultFormatter.js +14 -14
- package/dist/features/tools/presenter/toolMetadataFormatter.js +8 -8
- package/dist/gen/endpoints/TouchDesignerAPI.js +22 -4
- package/dist/gen/mcp/touchDesignerAPI.zod.js +52 -12
- package/dist/server/connectionManager.js +11 -28
- package/dist/server/touchDesignerServer.js +4 -3
- package/dist/tdClient/touchDesignerClient.js +267 -46
- package/package.json +31 -17
package/README.ja.md
CHANGED
|
@@ -250,9 +250,11 @@ td/
|
|
|
250
250
|
| `delete_td_node` | 既存のノードを削除します。 |
|
|
251
251
|
| `exec_node_method` | ノードに対してPythonメソッドを呼び出します。 |
|
|
252
252
|
| `execute_python_script` | TD内で任意のPythonスクリプトを実行します。 |
|
|
253
|
+
| `get_module_help` | TouchDesignerモジュール/クラスのPython help()ドキュメントを取得します。 |
|
|
253
254
|
| `get_td_class_details` | TD Pythonクラス/モジュールの詳細情報を取得します。 |
|
|
254
255
|
| `get_td_classes` | TouchDesigner Pythonクラスのリストを取得します。 |
|
|
255
256
|
| `get_td_info` | TDサーバー環境に関する情報を取得します。 |
|
|
257
|
+
| `get_td_node_errors` | 指定されたノードとその子ノードのエラーをチェックします。 |
|
|
256
258
|
| `get_td_node_parameters` | 特定ノードのパラメータを取得します。 |
|
|
257
259
|
| `get_td_nodes` | 親パス内のノードを取得します(オプションでフィルタリング)。 |
|
|
258
260
|
| `update_td_node_parameters` | 特定ノードのパラメータを更新します。 |
|
|
@@ -354,6 +356,50 @@ td/
|
|
|
354
356
|
|
|
355
357
|
ビルドプロセス (`npm run build`) は、必要なすべての生成ステップ (`npm run gen`) を実行し、その後にTypeScriptコンパイル (`tsc`) を行います。
|
|
356
358
|
|
|
359
|
+
### バージョン管理
|
|
360
|
+
|
|
361
|
+
- `package.json` はすべてのコンポーネントバージョンの唯一の信頼できる情報源です(Node.js MCPサーバー、TouchDesigner Python API、MCPバンドル、および `server.json` メタデータ)。
|
|
362
|
+
- バージョンを更新する際は `npm version <patch|minor|major>`(または内部で使用される `npm run gen:version`)を実行してください。このスクリプトは `pyproject.toml`、`td/modules/utils/version.py`、`mcpb/manifest.json`、および `server.json` を書き換え、リリースワークフローがタグ値を信頼できるようにします。
|
|
363
|
+
- GitHubリリースワークフロー(`.github/workflows/release.yml`)はコミットを `v${version}` としてタグ付けし、同じバージョン番号から `touchdesigner-mcp-td.zip` / `touchdesigner-mcp.mcpb` を公開します。リリースをトリガーする前に必ず同期ステップを実行し、すべてのアーティファクトが整合するようにしてください。
|
|
364
|
+
|
|
365
|
+
## トラブルシューティング
|
|
366
|
+
|
|
367
|
+
### バージョン互換性のトラブルシューティング
|
|
368
|
+
|
|
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
|
+
- **互換性エラーを解決するには:**
|
|
386
|
+
1. リリースページから最新の [touchdesigner-mcp-td.zip](https://github.com/8beeeaaat/touchdesigner-mcp/releases/latest/download/touchdesigner-mcp-td.zip) をダウンロードします。
|
|
387
|
+
2. 既存の `touchdesigner-mcp-td` フォルダを削除し、新しく展開した内容に置き換えます。
|
|
388
|
+
3. TouchDesignerプロジェクトから古い `mcp_webserver_base` コンポーネントを削除し、新しいフォルダから `.tox` をインポートします。
|
|
389
|
+
4. TouchDesignerとMCPサーバーを実行しているAIエージェント(例:Claude Desktop)を再起動します。
|
|
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
|
+
- 問題を解決したら再度ツールを実行するだけで、キャッシュされたエラーがクリアされて接続チェックがやり直されます。
|
|
402
|
+
|
|
357
403
|
## 開発で貢献
|
|
358
404
|
|
|
359
405
|
ぜひ一緒に改善しましょう!
|
package/README.md
CHANGED
|
@@ -250,9 +250,11 @@ Tools allow AI agents to perform actions in TouchDesigner.
|
|
|
250
250
|
| `delete_td_node` | Deletes an existing node. |
|
|
251
251
|
| `exec_node_method` | Calls a Python method on a node. |
|
|
252
252
|
| `execute_python_script` | Executes an arbitrary Python script in TouchDesigner. |
|
|
253
|
+
| `get_module_help` | Gets Python help() documentation for TouchDesigner modules/classes.|
|
|
253
254
|
| `get_td_class_details` | Gets details of a TouchDesigner Python class or module. |
|
|
254
255
|
| `get_td_classes` | Gets a list of TouchDesigner Python classes. |
|
|
255
256
|
| `get_td_info` | Gets information about the TouchDesigner server environment. |
|
|
257
|
+
| `get_td_node_errors` | Checks for errors on a specified node and its children. |
|
|
256
258
|
| `get_td_node_parameters`| Gets the parameters of a specific node. |
|
|
257
259
|
| `get_td_nodes` | Gets nodes under a parent path, with optional filtering. |
|
|
258
260
|
| `update_td_node_parameters` | Updates the parameters of a specific node. |
|
|
@@ -354,6 +356,50 @@ This project uses OpenAPI-based code generation tools (Orval and openapi-generat
|
|
|
354
356
|
|
|
355
357
|
The build process (`npm run build`) runs all necessary generation steps (`npm run gen`), followed by TypeScript compilation (`tsc`).
|
|
356
358
|
|
|
359
|
+
### Version management
|
|
360
|
+
|
|
361
|
+
- `package.json` is the single source of truth for every component version (Node.js MCP server, TouchDesigner Python API, MCP bundle, and `server.json` metadata).
|
|
362
|
+
- Run `npm version <patch|minor|major>` (or the underlying `npm run gen:version`) whenever you bump the version. The script rewrites `pyproject.toml`, `td/modules/utils/version.py`, `mcpb/manifest.json`, and `server.json` so that the release workflow can trust the tag value.
|
|
363
|
+
- The GitHub release workflow (`.github/workflows/release.yml`) tags the commit as `v${version}` and publishes `touchdesigner-mcp-td.zip` / `touchdesigner-mcp.mcpb` from the exact same version number. Always run the sync step before triggering a release so that every artifact stays aligned.
|
|
364
|
+
|
|
365
|
+
## Troubleshooting
|
|
366
|
+
|
|
367
|
+
### Troubleshooting version compatibility
|
|
368
|
+
|
|
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:**
|
|
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.
|
|
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.
|
|
389
|
+
4. Restart TouchDesigner and the AI agent running the MCP server (e.g., Claude Desktop).
|
|
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.
|
|
402
|
+
|
|
357
403
|
## Contributing
|
|
358
404
|
|
|
359
405
|
We welcome your contributions!
|
package/dist/cli.js
CHANGED
|
@@ -59,8 +59,8 @@ export async function startServer(params) {
|
|
|
59
59
|
}
|
|
60
60
|
// Start server if this file is executed directly
|
|
61
61
|
startServer({
|
|
62
|
-
nodeEnv: process.env.NODE_ENV,
|
|
63
62
|
argv: process.argv,
|
|
63
|
+
nodeEnv: process.env.NODE_ENV,
|
|
64
64
|
}).catch((error) => {
|
|
65
65
|
console.error("Failed to start server:", error);
|
|
66
66
|
if (process.env.NODE_ENV === "test")
|
|
@@ -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/constants.js
CHANGED
|
@@ -10,18 +10,20 @@ export const TOOL_NAMES = {
|
|
|
10
10
|
CREATE_TD_NODE: "create_td_node",
|
|
11
11
|
DELETE_TD_NODE: "delete_td_node",
|
|
12
12
|
DESCRIBE_TD_TOOLS: "describe_td_tools",
|
|
13
|
-
EXECUTE_PYTHON_SCRIPT: "execute_python_script",
|
|
14
13
|
EXECUTE_NODE_METHOD: "exec_node_method",
|
|
15
|
-
|
|
14
|
+
EXECUTE_PYTHON_SCRIPT: "execute_python_script",
|
|
16
15
|
GET_TD_CLASS_DETAILS: "get_td_class_details",
|
|
17
16
|
GET_TD_CLASSES: "get_td_classes",
|
|
17
|
+
GET_TD_INFO: "get_td_info",
|
|
18
|
+
GET_TD_MODULE_HELP: "get_td_module_help",
|
|
19
|
+
GET_TD_NODE_ERRORS: "get_td_node_errors",
|
|
18
20
|
GET_TD_NODE_PARAMETERS: "get_td_node_parameters",
|
|
19
21
|
GET_TD_NODES: "get_td_nodes",
|
|
20
22
|
UPDATE_TD_NODE_PARAMETERS: "update_td_node_parameters",
|
|
21
23
|
};
|
|
22
24
|
export const REFERENCE_COMMENT = `Check reference resources: ${TD_PYTHON_CLASS_REFERENCE_INDEX_URL}`;
|
|
23
25
|
export const PROMPT_NAMES = {
|
|
24
|
-
SEARCH_NODE: "Search node",
|
|
25
26
|
CHECK_NODE_ERRORS: "Check node errors",
|
|
26
27
|
NODE_CONNECTION: "Node connection",
|
|
28
|
+
SEARCH_NODE: "Search node",
|
|
27
29
|
};
|
|
@@ -5,15 +5,30 @@ export function handleToolError(error, logger, toolName, referenceComment) {
|
|
|
5
5
|
const formattedError = error instanceof Error
|
|
6
6
|
? error
|
|
7
7
|
: new Error(error === null ? "Null error received" : String(error));
|
|
8
|
-
|
|
8
|
+
const logData = {
|
|
9
|
+
error: formattedError.message,
|
|
10
|
+
message: "Tool execution failed",
|
|
11
|
+
toolName,
|
|
12
|
+
};
|
|
13
|
+
if (referenceComment) {
|
|
14
|
+
logData.referenceComment = referenceComment;
|
|
15
|
+
}
|
|
16
|
+
if (formattedError.stack) {
|
|
17
|
+
logData.stack = formattedError.stack;
|
|
18
|
+
}
|
|
19
|
+
logger.sendLog({
|
|
20
|
+
data: logData,
|
|
21
|
+
level: "error",
|
|
22
|
+
logger: "ErrorHandling",
|
|
23
|
+
});
|
|
9
24
|
const errorMessage = `${toolName}: ${formattedError}${referenceComment ? `. ${referenceComment}` : ""}`;
|
|
10
25
|
return {
|
|
11
|
-
isError: true,
|
|
12
26
|
content: [
|
|
13
27
|
{
|
|
14
|
-
type: "text",
|
|
15
28
|
text: errorMessage,
|
|
29
|
+
type: "text",
|
|
16
30
|
},
|
|
17
31
|
],
|
|
32
|
+
isError: true,
|
|
18
33
|
};
|
|
19
34
|
}
|
package/dist/core/logger.js
CHANGED
|
@@ -7,39 +7,24 @@ export class McpLogger {
|
|
|
7
7
|
constructor(server) {
|
|
8
8
|
this.server = server;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.sendLog("warning", args);
|
|
21
|
-
}
|
|
22
|
-
// biome-ignore lint/suspicious/noExplicitAny: logging accepts any type
|
|
23
|
-
error(...args) {
|
|
24
|
-
this.sendLog("error", args);
|
|
25
|
-
}
|
|
26
|
-
sendLog(level,
|
|
27
|
-
// biome-ignore lint/suspicious/noExplicitAny: logging accepts any type
|
|
28
|
-
args) {
|
|
29
|
-
for (const arg of args) {
|
|
30
|
-
try {
|
|
31
|
-
this.server.server.sendLoggingMessage({
|
|
32
|
-
level,
|
|
33
|
-
data: arg,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
if (error instanceof Error && error.message === "Not connected") {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
console.error(`Failed to send log to MCP server: ${error instanceof Error ? error.message : String(error)}`);
|
|
41
|
-
console[level === "warning" ? "warn" : level]?.(arg);
|
|
10
|
+
sendLog(args) {
|
|
11
|
+
try {
|
|
12
|
+
this.server.server.sendLoggingMessage({
|
|
13
|
+
...args,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
// Only swallow the expected "Not connected" error during startup/shutdown
|
|
18
|
+
if (error instanceof Error && error.message === "Not connected") {
|
|
19
|
+
return;
|
|
42
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
|
+
});
|
|
43
28
|
}
|
|
44
29
|
}
|
|
45
30
|
}
|
package/dist/core/result.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Creates a success result with the provided data
|
|
3
3
|
*/
|
|
4
4
|
export function createSuccessResult(data) {
|
|
5
|
-
return { success: true
|
|
5
|
+
return { data, success: true };
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Creates an error result with the provided error
|
|
9
9
|
*/
|
|
10
10
|
export function createErrorResult(error) {
|
|
11
|
-
return { success: false
|
|
11
|
+
return { error, success: false };
|
|
12
12
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const requirePackage = createRequire(import.meta.url);
|
|
3
|
+
const packageJson = requirePackage("../../package.json");
|
|
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();
|
|
@@ -2,40 +2,40 @@ import { GetPromptRequestSchema, ListPromptsRequestSchema, } from "@modelcontext
|
|
|
2
2
|
import { PROMPT_NAMES, TOOL_NAMES } from "../../../core/constants.js";
|
|
3
3
|
const PROMPTS = [
|
|
4
4
|
{
|
|
5
|
-
name: PROMPT_NAMES.SEARCH_NODE,
|
|
6
|
-
description: "Fuzzy search for node",
|
|
7
5
|
arguments: [
|
|
8
6
|
{
|
|
9
|
-
name: "nodeName",
|
|
10
7
|
description: "Name of the node to check",
|
|
8
|
+
name: "nodeName",
|
|
11
9
|
required: true,
|
|
12
10
|
},
|
|
13
11
|
{
|
|
14
|
-
name: "nodeFamily",
|
|
15
12
|
description: "Family of the node to check",
|
|
13
|
+
name: "nodeFamily",
|
|
16
14
|
required: false,
|
|
17
15
|
},
|
|
18
16
|
{
|
|
19
|
-
name: "nodeType",
|
|
20
17
|
description: "Type of the node to check",
|
|
18
|
+
name: "nodeType",
|
|
21
19
|
required: false,
|
|
22
20
|
},
|
|
23
21
|
],
|
|
22
|
+
description: "Fuzzy search for node",
|
|
23
|
+
name: PROMPT_NAMES.SEARCH_NODE,
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
|
-
name: PROMPT_NAMES.CHECK_NODE_ERRORS,
|
|
27
|
-
description: "Fuzzy search for node and return errors in TouchDesigner.",
|
|
28
26
|
arguments: [
|
|
29
27
|
{
|
|
30
|
-
name: "nodePath",
|
|
31
28
|
description: "Path to the node to check",
|
|
29
|
+
name: "nodePath",
|
|
32
30
|
required: true,
|
|
33
31
|
},
|
|
34
32
|
],
|
|
33
|
+
description: "Fuzzy search for node and return errors in TouchDesigner.",
|
|
34
|
+
name: PROMPT_NAMES.CHECK_NODE_ERRORS,
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
name: PROMPT_NAMES.NODE_CONNECTION,
|
|
38
37
|
description: "Connect nodes between each other in TouchDesigner.",
|
|
38
|
+
name: PROMPT_NAMES.NODE_CONNECTION,
|
|
39
39
|
},
|
|
40
40
|
];
|
|
41
41
|
/**
|
|
@@ -49,7 +49,10 @@ export function registerTdPrompts(server, logger) {
|
|
|
49
49
|
});
|
|
50
50
|
server.server.setRequestHandler(GetPromptRequestSchema, (request) => {
|
|
51
51
|
try {
|
|
52
|
-
logger.
|
|
52
|
+
logger.sendLog({
|
|
53
|
+
data: `Handling GetPromptRequest: ${request.params.name}`,
|
|
54
|
+
level: "debug",
|
|
55
|
+
});
|
|
53
56
|
const prompt = getPrompt(request.params.name);
|
|
54
57
|
if (!prompt) {
|
|
55
58
|
throw new Error("Prompt name is required");
|
|
@@ -60,8 +63,8 @@ export function registerTdPrompts(server, logger) {
|
|
|
60
63
|
}
|
|
61
64
|
const { nodeName, nodeFamily, nodeType } = request.params.arguments;
|
|
62
65
|
const messages = handleSearchNodePrompt({
|
|
63
|
-
nodeName,
|
|
64
66
|
nodeFamily,
|
|
67
|
+
nodeName,
|
|
65
68
|
nodeType,
|
|
66
69
|
});
|
|
67
70
|
return { messages };
|
|
@@ -84,7 +87,10 @@ export function registerTdPrompts(server, logger) {
|
|
|
84
87
|
}
|
|
85
88
|
catch (error) {
|
|
86
89
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
87
|
-
logger.
|
|
90
|
+
logger.sendLog({
|
|
91
|
+
data: `Error handling prompt request: ${errorMessage}`,
|
|
92
|
+
level: "error",
|
|
93
|
+
});
|
|
88
94
|
throw new Error(errorMessage);
|
|
89
95
|
}
|
|
90
96
|
});
|
|
@@ -92,33 +98,33 @@ export function registerTdPrompts(server, logger) {
|
|
|
92
98
|
function handleSearchNodePrompt(params) {
|
|
93
99
|
return [
|
|
94
100
|
{
|
|
95
|
-
role: "user",
|
|
96
101
|
content: {
|
|
97
|
-
type: "text",
|
|
98
102
|
text: `Use the "${TOOL_NAMES.GET_TD_NODES}", "${TOOL_NAMES.GET_TD_NODE_PARAMETERS}" tools to search nodes what named "${params.nodeName}" in the TouchDesigner project.${params.nodeType ? ` Node Type: ${params.nodeType}.` : ""}${params.nodeFamily ? ` Node Family: ${params.nodeFamily}.` : ""}`,
|
|
103
|
+
type: "text",
|
|
99
104
|
},
|
|
105
|
+
role: "user",
|
|
100
106
|
},
|
|
101
107
|
];
|
|
102
108
|
}
|
|
103
109
|
function handleCheckNodeErrorsPrompt(params) {
|
|
104
110
|
return [
|
|
105
111
|
{
|
|
106
|
-
role: "user",
|
|
107
112
|
content: {
|
|
113
|
+
text: `Use the "${TOOL_NAMES.GET_TD_NODE_ERRORS}" tool to inspect "${params.nodePath}" (and optionally its children) for error messages. If errors are returned, examine the affected nodes' parameters and connections to resolve them.`,
|
|
108
114
|
type: "text",
|
|
109
|
-
text: `Use the "${TOOL_NAMES.EXECUTE_NODE_METHOD}" like "op('${params.nodePath}').errors()" tool to check node errors. If there are any errors, please check the node parameters and connections. If the node has children, please check the child nodes as well. Please check the node connections and parameters. If the node has children, please check the child nodes as well.`,
|
|
110
115
|
},
|
|
116
|
+
role: "user",
|
|
111
117
|
},
|
|
112
118
|
];
|
|
113
119
|
}
|
|
114
120
|
function handleNodeConnectionPrompt() {
|
|
115
121
|
return [
|
|
116
122
|
{
|
|
117
|
-
role: "user",
|
|
118
123
|
content: {
|
|
119
|
-
type: "text",
|
|
120
124
|
text: `Use the "${TOOL_NAMES.EXECUTE_PYTHON_SCRIPT}" tool e.g. op('/project1/text_over_image').outputConnectors[0].connect(op('/project1/out1'))`,
|
|
125
|
+
type: "text",
|
|
121
126
|
},
|
|
127
|
+
role: "user",
|
|
122
128
|
},
|
|
123
129
|
];
|
|
124
130
|
}
|