touchdesigner-mcp-server 0.2.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/LICENSE +21 -0
- package/README.ja.md +211 -0
- package/README.md +204 -0
- package/dist/api/customInstance.js +18 -0
- package/dist/cli.js +36 -0
- package/dist/core/constants.js +26 -0
- package/dist/core/errorHandling.js +19 -0
- package/dist/core/logger.js +45 -0
- package/dist/core/result.js +12 -0
- package/dist/features/prompts/handlers/td_prompts.js +131 -0
- package/dist/features/prompts/index.js +1 -0
- package/dist/features/prompts/register.js +7 -0
- package/dist/features/tools/handlers/tdTools.js +214 -0
- package/dist/features/tools/index.js +1 -0
- package/dist/features/tools/register.js +7 -0
- package/dist/features/tools/types.js +1 -0
- package/dist/features/tools/utils/toolUtils.js +1 -0
- package/dist/gen/endpoints/TouchDesignerAPI.js +250 -0
- package/dist/gen/mcp/touchDesignerAPI.zod.js +203 -0
- package/dist/index.js +3 -0
- package/dist/mock/index.js +5 -0
- package/dist/mock/node.js +3 -0
- package/dist/server/connectionManager.js +83 -0
- package/dist/server/touchDesignerServer.js +60 -0
- package/dist/tdClient/index.js +6 -0
- package/dist/tdClient/touchDesignerClient.js +150 -0
- package/package.json +76 -0
- package/src/index.ts +6 -0
- package/td/genHandlers.js +47 -0
- package/td/import_modules.py +52 -0
- package/td/mcp_webserver_base.tox +0 -0
- package/td/modules/mcp/controllers/__init__.py +9 -0
- package/td/modules/mcp/controllers/api_controller.py +623 -0
- package/td/modules/mcp/controllers/generated_handlers.py +365 -0
- package/td/modules/mcp/controllers/openapi_router.py +265 -0
- package/td/modules/mcp/services/__init__.py +8 -0
- package/td/modules/mcp/services/api_service.py +535 -0
- package/td/modules/mcp_webserver_script.py +134 -0
- package/td/modules/td_server/.dockerignore +72 -0
- package/td/modules/td_server/.openapi-generator/FILES +55 -0
- package/td/modules/td_server/.openapi-generator/VERSION +1 -0
- package/td/modules/td_server/.openapi-generator-ignore +23 -0
- package/td/modules/td_server/.travis.yml +14 -0
- package/td/modules/td_server/Dockerfile +16 -0
- package/td/modules/td_server/README.md +49 -0
- package/td/modules/td_server/git_push.sh +57 -0
- package/td/modules/td_server/openapi_server/__init__.py +0 -0
- package/td/modules/td_server/openapi_server/__main__.py +19 -0
- package/td/modules/td_server/openapi_server/controllers/__init__.py +0 -0
- package/td/modules/td_server/openapi_server/controllers/default_controller.py +160 -0
- package/td/modules/td_server/openapi_server/controllers/security_controller.py +2 -0
- package/td/modules/td_server/openapi_server/encoder.py +19 -0
- package/td/modules/td_server/openapi_server/models/__init__.py +33 -0
- package/td/modules/td_server/openapi_server/models/base_model.py +68 -0
- package/td/modules/td_server/openapi_server/models/create_node200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/create_node200_response_data.py +63 -0
- package/td/modules/td_server/openapi_server/models/create_node_request.py +123 -0
- package/td/modules/td_server/openapi_server/models/delete_node200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/delete_node200_response_data.py +91 -0
- package/td/modules/td_server/openapi_server/models/exec_node_method200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/exec_node_method200_response_data.py +65 -0
- package/td/modules/td_server/openapi_server/models/exec_node_method_request.py +153 -0
- package/td/modules/td_server/openapi_server/models/exec_node_method_request_args_inner.py +34 -0
- package/td/modules/td_server/openapi_server/models/exec_python_script200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/exec_python_script200_response_data.py +65 -0
- package/td/modules/td_server/openapi_server/models/exec_python_script200_response_data_result.py +63 -0
- package/td/modules/td_server/openapi_server/models/exec_python_script_request.py +65 -0
- package/td/modules/td_server/openapi_server/models/get_node_detail200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/get_nodes200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/get_nodes200_response_data.py +65 -0
- package/td/modules/td_server/openapi_server/models/get_td_info200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/get_td_info200_response_data.py +155 -0
- package/td/modules/td_server/openapi_server/models/get_td_python_class_details200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/get_td_python_classes200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/get_td_python_classes200_response_data.py +63 -0
- package/td/modules/td_server/openapi_server/models/td_node.py +175 -0
- package/td/modules/td_server/openapi_server/models/td_node_family_type.py +44 -0
- package/td/modules/td_server/openapi_server/models/td_python_class_details.py +191 -0
- package/td/modules/td_server/openapi_server/models/td_python_class_info.py +127 -0
- package/td/modules/td_server/openapi_server/models/td_python_method_info.py +121 -0
- package/td/modules/td_server/openapi_server/models/td_python_property_info.py +123 -0
- package/td/modules/td_server/openapi_server/models/update_node200_response.py +125 -0
- package/td/modules/td_server/openapi_server/models/update_node200_response_data.py +149 -0
- package/td/modules/td_server/openapi_server/models/update_node200_response_data_failed_inner.py +91 -0
- package/td/modules/td_server/openapi_server/models/update_node_request.py +93 -0
- package/td/modules/td_server/openapi_server/openapi/openapi.yaml +966 -0
- package/td/modules/td_server/openapi_server/test/__init__.py +16 -0
- package/td/modules/td_server/openapi_server/test/test_default_controller.py +200 -0
- package/td/modules/td_server/openapi_server/typing_utils.py +30 -0
- package/td/modules/td_server/openapi_server/util.py +147 -0
- package/td/modules/td_server/requirements.txt +13 -0
- package/td/modules/td_server/setup.py +37 -0
- package/td/modules/td_server/test-requirements.txt +4 -0
- package/td/modules/td_server/tox.ini +11 -0
- package/td/modules/utils/config.py +7 -0
- package/td/modules/utils/error_handling.py +104 -0
- package/td/modules/utils/logging.py +23 -0
- package/td/modules/utils/result.py +40 -0
- package/td/modules/utils/serialization.py +57 -0
- package/td/modules/utils/types.py +33 -0
- package/td/modules/utils/utils_logging.py +60 -0
- package/td/templates/mcp/api_controller_handlers.mustache +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 sadao komaki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# TouchDesigner MCP
|
|
2
|
+
|
|
3
|
+
TouchDesignerのためのMCP(Model Context Protocol) サーバー実装です。AIエージェントがTouchDesignerプロジェクトを制御・操作できるようになることを目指しています。
|
|
4
|
+
|
|
5
|
+
## 概要
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
TouchDesigner MCPは、AIモデルとTouchDesigner WebServer DAT 間のブリッジとして機能し、AIエージェントが以下のことが可能になります
|
|
10
|
+
- ノードの作成、変更、削除
|
|
11
|
+
- ノードプロパティやプロジェクト構造の照会
|
|
12
|
+
- PythonスクリプトによるTouchDesignerのプログラム的制御
|
|
13
|
+
|
|
14
|
+
## 前提条件
|
|
15
|
+
|
|
16
|
+
- Node.js(最新のLTSバージョンを推奨)
|
|
17
|
+
- TouchDesigner(最新の安定版を推奨)
|
|
18
|
+
- Docker(Pythonサーバーコードの生成に必要)
|
|
19
|
+
|
|
20
|
+
## MCPサーバーコードのビルド
|
|
21
|
+
|
|
22
|
+
1. リポジトリのクローン
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/8beeeaaat/touchdesigner-mcp.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. 依存パッケージのインストール
|
|
28
|
+
```bash
|
|
29
|
+
cd touchdesigner-mcp
|
|
30
|
+
npm install
|
|
31
|
+
```
|
|
32
|
+
3. 環境設定ファイルの設置とビルド
|
|
33
|
+
```
|
|
34
|
+
# テンプレートをコピーし、必要に応じて TD_WEB_SERVER_URL を調整してください
|
|
35
|
+
cp dotenv .env
|
|
36
|
+
|
|
37
|
+
# プロジェクトのビルド(APIクライアント/サーバー向けスキーマを生成し、MCPリソースをコンパイルします)
|
|
38
|
+
# このコマンドを実行する前にDockerデーモンが実行されていることを確認してください
|
|
39
|
+
npm run build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 使い方
|
|
43
|
+
|
|
44
|
+
### TouchDesignerのセットアップ
|
|
45
|
+
|
|
46
|
+
1. **コード生成:**
|
|
47
|
+
[MCPサーバーコードのビルド](#MCPサーバーコードのビルド) を参考に、プロジェクトルートで `npm run build` を実行します。これにより以下のコードが生成されます。
|
|
48
|
+
- MCPサーバコード
|
|
49
|
+
- TouchDesigner WebSever DAT向けのAPIサーバーコード
|
|
50
|
+
2. **TouchDesigner に MCPサーバー向けWebServerをインポートする:**
|
|
51
|
+
TouchDesignerを起動し、`td/mcp_webserver_base.tox` コンポーネントをTouchDesignerプロジェクト直下にimportします。
|
|
52
|
+
tox のimport により `td/import_modules.py` スクリプトが動作し、APIサーバのコントローラなどのモジュールがロードされます。
|
|
53
|
+
|
|
54
|
+
3. **APIサーバの動作確認:**
|
|
55
|
+
`td/modules` ディレクトリ内のPythonモジュールが `mcp_webserver_base` コンポーネントからアクセス可能であることを確認します。
|
|
56
|
+
`npm run test` を実行することでMCPサーバーコードのユニットテストと TouchDesigner への結合テストが実行されます。
|
|
57
|
+
TOuchDesigner のメニューから Textportを起動すると通信のログを確認することができます。
|
|
58
|
+
|
|
59
|
+
*TIPS*
|
|
60
|
+
`mcp_webserver_base.tox` には、MCPサーバーとTouchDesignerを連携させるように設定された WebServer DAT が含まれています。
|
|
61
|
+
このDATがActiveであり、`.env` ファイルの `TD_WEB_SERVER_URL` で指定されたポートで実行されていることを確認してください。(デフォルト: `9981`)
|
|
62
|
+
実行するポートを任意のものに変更したい場合は、以下の手順に従ってください。
|
|
63
|
+
1. `.env` ファイルの `TD_WEB_SERVER_PORT` を変更
|
|
64
|
+
2. `npm run build` を再実行
|
|
65
|
+
3. mcp_webserver_base (WebServer DAT) のポートを変更し、WebServer DATをRestart
|
|
66
|
+
|
|
67
|
+
### MCP対応 AIエージェントとの接続
|
|
68
|
+
|
|
69
|
+
TouchDesignerが起動した状態で、AIエージェント(Cursor, Claude Desktop, VSCode CopilotChatなど)をMCPサーバーに接続するように設定します。
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
// 設定例(例:VS Code settings.json の Copilot Chat 用)
|
|
73
|
+
"github.copilot.advanced": {
|
|
74
|
+
"touchdesigner": {
|
|
75
|
+
"command": "node",
|
|
76
|
+
"args": [
|
|
77
|
+
"/path/to/your/touchdesigner-mcp/dist/index.js", // <-- npm run buildによって生成された dist/index.js への絶対パスに置き換えてください
|
|
78
|
+
"--stdio"
|
|
79
|
+
],
|
|
80
|
+
"transportType": "stdio"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
TouchDesigner で APIサーバーが実行されていれば、エージェントは提供された TouchDesigner ツールを通じてTouchDesignerを使用できます。
|
|
86
|
+
|
|
87
|
+
## セットアップ後のプロジェクト構造概要
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
├── src/ # MCPサーバー ソースコード
|
|
91
|
+
│ ├── api/ # TD WebServerに対するOpenAPI仕様
|
|
92
|
+
│ ├── core/ # コアユーティリティ (ロガー, エラーハンドリング)
|
|
93
|
+
│ ├── features/ # MCP機能実装
|
|
94
|
+
│ │ ├── prompts/ # プロンプトハンドラ
|
|
95
|
+
│ │ ├── resources/ # リソースハンドラ
|
|
96
|
+
│ │ └── tools/ # ツールハンドラ (例: tdTools.ts)
|
|
97
|
+
│ ├── gen/ # OpenAPIスキーマから生成されたMCPサーバー向けコード
|
|
98
|
+
│ ├── server/ # MCPサーバーロジック (接続, メインサーバークラス)
|
|
99
|
+
│ ├── tdClient/ # TD接続API用クライアント
|
|
100
|
+
│ ├── index.ts # Node.jsサーバーのメインエントリーポイント
|
|
101
|
+
│ └── ...
|
|
102
|
+
├── td/ # TouchDesigner関連ファイル
|
|
103
|
+
│ ├── modules/ # TouchDesigner用Pythonモジュール
|
|
104
|
+
│ │ ├── mcp/ # TD内でMCPからのリクエストを処理するコアロジック
|
|
105
|
+
│ │ │ ├── controllers/ # APIリクエストコントローラ (api_controller.py, generated_handlers.py)
|
|
106
|
+
│ │ │ └── services/ # ビジネスロジック (api_service.py)
|
|
107
|
+
│ │ ├── td_server/ # OpenAPIスキーマから生成されたPythonモデルコード
|
|
108
|
+
│ │ └── utils/ # 共有Pythonユーティリティ
|
|
109
|
+
│ ├── templates/ # Pythonコード生成用Mustacheテンプレート
|
|
110
|
+
│ ├── genHandlers.js # generated_handlers.py 生成用のNode.jsスクリプト
|
|
111
|
+
│ ├── import_modules.py # TDへ APIサーバ関連モジュールをインポートするヘルパースクリプト
|
|
112
|
+
│ └── mcp_webserver_base.tox # メインTouchDesignerコンポーネント
|
|
113
|
+
├── tests/ # テストコード
|
|
114
|
+
│ ├── integration/
|
|
115
|
+
│ └── unit/
|
|
116
|
+
├── .env # ローカル環境変数 (git無視)
|
|
117
|
+
├── dotenv # .env用テンプレート
|
|
118
|
+
└── orval.config.ts # Orval 設定 (TSクライアント生成)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## MCPサーバーの機能
|
|
122
|
+
|
|
123
|
+
このサーバーは、Model Context Protocol (MCP) を通じてTouchDesigner への操作、および各種実装ドキュメントへの参照を可能にします。
|
|
124
|
+
|
|
125
|
+
### ツール (Tools)
|
|
126
|
+
|
|
127
|
+
ツールは、AIエージェントがTouchDesignerでアクションを実行できるようにします。
|
|
128
|
+
|
|
129
|
+
| ツール名 | 説明 |
|
|
130
|
+
| :-------------------------- | :--------------------------------------------- |
|
|
131
|
+
| `create_td_node` | 新しいノードを作成します。 |
|
|
132
|
+
| `delete_td_node` | 既存のノードを削除します。 |
|
|
133
|
+
| `exec_node_method`| ノードに対しPythonメソッドを呼び出します。 |
|
|
134
|
+
| `execute_python_script` | TD内で任意のPythonスクリプトを実行します。 |
|
|
135
|
+
| `get_td_class_details` | TD Pythonクラス/モジュールの詳細情報を取得します。 |
|
|
136
|
+
| `get_td_classes` | TouchDesigner Pythonクラスのリストを取得します。 |
|
|
137
|
+
| `get_td_info` | TDサーバー環境に関する情報を取得します。 |
|
|
138
|
+
| `get_td_node_parameters` | 特定ノードのパラメータを取得します。 |
|
|
139
|
+
| `get_td_nodes` | 親パス内のノードを取得します(オプションでフィルタリング)。 |
|
|
140
|
+
| `update_td_node_parameters` | 特定ノードのパラメータを更新します。 |
|
|
141
|
+
|
|
142
|
+
### プロンプト (Prompts)
|
|
143
|
+
|
|
144
|
+
プロンプトは、AIエージェントがTouchDesignerで特定のアクションを実行するための指示を提供します。
|
|
145
|
+
|
|
146
|
+
| プロンプト名 | 説明 |
|
|
147
|
+
| :-------------------------- | :--------------------------------------------- |
|
|
148
|
+
| `Search node` | ノードをファジー検索し、指定されたノード名、ファミリー、タイプに基づいて情報を取得します。 |
|
|
149
|
+
| `Node connection` | TouchDesigner内でノード同士を接続するための指示を提供します。 |
|
|
150
|
+
| `Check node errors` | 指定されたノードのエラーをチェックします。子ノードがあれば再帰的にチェックします。 |
|
|
151
|
+
|
|
152
|
+
### リソース (Resources)
|
|
153
|
+
|
|
154
|
+
未実装
|
|
155
|
+
|
|
156
|
+
## 開発
|
|
157
|
+
|
|
158
|
+
### 開発環境のセットアップ
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# 依存関係のインストール
|
|
162
|
+
npm install
|
|
163
|
+
|
|
164
|
+
# リンターと型チェッカーの実行
|
|
165
|
+
npm run lint
|
|
166
|
+
|
|
167
|
+
# テストの実行
|
|
168
|
+
npm test
|
|
169
|
+
|
|
170
|
+
# デバッグ用にMCP Inspectorを使用してサーバーを起動
|
|
171
|
+
npm run dev
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### APIコード生成ワークフロー
|
|
175
|
+
|
|
176
|
+
このプロジェクトでは、OpenAPIによるコード生成ツール ( Orval / openapi-generator-cli )を使用しています:
|
|
177
|
+
|
|
178
|
+
**API定義:** Node.js MCPサーバーとTouchDesigner内で実行されるPythonサーバー間のAPI規約は `src/api/index.yml` で定義されます。
|
|
179
|
+
|
|
180
|
+
1. **Pythonサーバー生成 (`npm run gen:webserver`):**
|
|
181
|
+
* Docker経由で `openapi-generator-cli` を使用します。
|
|
182
|
+
* `src/api/index.yml` を読み取ります。
|
|
183
|
+
* API定義に基づいてPythonサーバーのスケルトン (`td/modules/td_server/`) を生成します。このコードはWebServer DATを介してTouchDesigner内で実行されます。
|
|
184
|
+
* **Dockerがインストールされ、実行されている必要があります。**
|
|
185
|
+
2. **Pythonハンドラ生成 (`npm run gen:handlers`):**
|
|
186
|
+
* カスタムNode.jsスクリプト (`td/genHandlers.js`) とMustacheテンプレート (`td/templates/`) を使用します。
|
|
187
|
+
* 生成されたPythonサーバーコードまたはOpenAPI仕様を読み取ります。
|
|
188
|
+
* `td/modules/mcp/services/api_service.py` にあるビジネスロジックに接続するハンドラ実装 (`td/modules/mcp/controllers/generated_handlers.py`) を生成します。
|
|
189
|
+
3. **TypeScriptクライアント生成 (`npm run gen:mcp`):**
|
|
190
|
+
* `Orval` を使用し `openapi-generator-cli` がバンドルしたスキーマYAMLからAPIクライアントコードとToolの検証に用いるZodスキーマを生成します。
|
|
191
|
+
* Node.jsサーバーが WebServerDAT にリクエストを行うために使用する、型付けされたTypeScriptクライアント (`src/tdClient/`) を生成します。
|
|
192
|
+
|
|
193
|
+
ビルドプロセス (`npm run build`) は、必要なすべての生成ステップ (`npm run gen`) を実行し、その後にTypeScriptコンパイル (`tsc`) を行います。
|
|
194
|
+
|
|
195
|
+
## 貢献
|
|
196
|
+
|
|
197
|
+
貢献は歓迎します!貢献方法は以下の通りです:
|
|
198
|
+
|
|
199
|
+
1. リポジトリをフォーク
|
|
200
|
+
2. 機能ブランチを作成(`git checkout -b feature/amazing-feature`)
|
|
201
|
+
3. 変更を加える
|
|
202
|
+
4. テストを追加し、すべてが正常に動作することを確認(`npm test`)
|
|
203
|
+
5. 変更をコミット(`git commit -m 'Add some amazing feature'`)
|
|
204
|
+
6. ブランチにプッシュ(`git push origin feature/amazing-feature`)
|
|
205
|
+
7. プルリクエストを開く
|
|
206
|
+
|
|
207
|
+
プロジェクトのコーディング標準に従い、適切なテストを含めてください。
|
|
208
|
+
|
|
209
|
+
## ライセンス
|
|
210
|
+
|
|
211
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# TouchDesigner MCP
|
|
2
|
+
|
|
3
|
+
TouchDesigner MCP is an implementation of the Model Context Protocol (MCP) server for TouchDesigner, aiming to enable AI agents to control and interact with TouchDesigner projects.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
TouchDesigner MCP acts as a bridge between AI models and the TouchDesigner WebServer DAT, allowing AI agents to:
|
|
10
|
+
- Create, modify, and delete nodes
|
|
11
|
+
- Query node properties and project structure
|
|
12
|
+
- Programmatically control TouchDesigner using Python scripts
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
- Node.js (latest LTS version recommended)
|
|
17
|
+
- TouchDesigner (latest stable version recommended)
|
|
18
|
+
- Docker (Required for generating Python server code)
|
|
19
|
+
|
|
20
|
+
## Building the MCP Server Code
|
|
21
|
+
|
|
22
|
+
1. Clone the repository:
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/8beeeaaat/touchdesigner-mcp.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Install dependencies:
|
|
28
|
+
```bash
|
|
29
|
+
cd touchdesigner-mcp
|
|
30
|
+
npm install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Set up environment configuration and build:
|
|
34
|
+
```bash
|
|
35
|
+
# Copy the template and adjust TD_WEB_SERVER_URL if needed
|
|
36
|
+
cp dotenv .env
|
|
37
|
+
|
|
38
|
+
# Build the project (Generates API clients/servers and compiles MCP resources)
|
|
39
|
+
# Ensure Docker daemon is running before executing this command
|
|
40
|
+
npm run build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Setting Up TouchDesigner
|
|
46
|
+
|
|
47
|
+
1. **Generate Code:**
|
|
48
|
+
Refer to [Building the MCP Server Code](#building-the-mcp-server-code) and run `npm run build` in the project root. This generates:
|
|
49
|
+
- MCP server code
|
|
50
|
+
- API server code for the TouchDesigner WebServer DAT
|
|
51
|
+
|
|
52
|
+
2. **Import MCP WebServer into TouchDesigner:**
|
|
53
|
+
Launch TouchDesigner and import the `td/mcp_webserver_base.tox` component into your TouchDesigner project. The import triggers the `td/import_modules.py` script, which loads modules such as API server controllers.
|
|
54
|
+
|
|
55
|
+
3. **Verify API Server:**
|
|
56
|
+
Ensure that the Python modules in the `td/modules` directory are accessible from the `mcp_webserver_base` component. Run `npm run test` to execute unit tests for the MCP server code and integration tests with TouchDesigner. You can view communication logs by opening the Textport from the TouchDesigner menu.
|
|
57
|
+
|
|
58
|
+
*TIPS*
|
|
59
|
+
The `mcp_webserver_base.tox` includes a WebServer DAT configured to integrate the MCP server with TouchDesigner. Ensure this DAT is active and running on the port specified in the `.env` file's `TD_WEB_SERVER_URL` (default: `9981`). To change the port:
|
|
60
|
+
1. Update `TD_WEB_SERVER_PORT` in the `.env` file.
|
|
61
|
+
2. Rebuild the project with `npm run build`.
|
|
62
|
+
3. Update the port in the WebServer DAT and restart it.
|
|
63
|
+
|
|
64
|
+
### Connecting to an MCP-Compatible AI Agent
|
|
65
|
+
|
|
66
|
+
With TouchDesigner running, configure an AI agent (e.g., Cursor, Claude Desktop, VSCode CopilotChat) to connect to the MCP server.
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
// Example configuration (e.g., in VS Code settings.json for Copilot Chat)
|
|
70
|
+
"github.copilot.advanced": {
|
|
71
|
+
"touchdesigner": {
|
|
72
|
+
"command": "node",
|
|
73
|
+
"args": [
|
|
74
|
+
"/path/to/your/touchdesigner-mcp/dist/index.js", // <-- Replace with the absolute path generated by npm run build
|
|
75
|
+
"--stdio"
|
|
76
|
+
],
|
|
77
|
+
"transportType": "stdio"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Once the API server is running in TouchDesigner, the agent can use the provided TouchDesigner tools.
|
|
83
|
+
|
|
84
|
+
## Project Structure Overview
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
├── src/ # MCP server source code
|
|
88
|
+
│ ├── api/ # OpenAPI specification for TD WebServer
|
|
89
|
+
│ ├── core/ # Core utilities (logger, error handling)
|
|
90
|
+
│ ├── features/ # MCP feature implementations
|
|
91
|
+
│ │ ├── prompts/ # Prompt handlers
|
|
92
|
+
│ │ ├── resources/ # Resource handlers
|
|
93
|
+
│ │ └── tools/ # Tool handlers (e.g., tdTools.ts)
|
|
94
|
+
│ ├── gen/ # Code generated from OpenAPI schema for MCP server
|
|
95
|
+
│ ├── server/ # MCP server logic (connections, main server class)
|
|
96
|
+
│ ├── tdClient/ # Client for TD connection API
|
|
97
|
+
│ ├── index.ts # Main entry point for the Node.js server
|
|
98
|
+
│ └── ...
|
|
99
|
+
├── td/ # TouchDesigner-related files
|
|
100
|
+
│ ├── modules/ # Python modules for TouchDesigner
|
|
101
|
+
│ │ ├── mcp/ # Core logic for handling MCP requests in TD
|
|
102
|
+
│ │ │ ├── controllers/ # API request controllers (api_controller.py, generated_handlers.py)
|
|
103
|
+
│ │ │ └── services/ # Business logic (api_service.py)
|
|
104
|
+
│ │ ├── td_server/ # Python model code generated from OpenAPI schema
|
|
105
|
+
│ │ └── utils/ # Shared Python utilities
|
|
106
|
+
│ ├── templates/ # Mustache templates for Python code generation
|
|
107
|
+
│ ├── genHandlers.js # Node.js script for generating Python handlers
|
|
108
|
+
│ ├── import_modules.py # Helper script for importing API server modules into TD
|
|
109
|
+
│ └── mcp_webserver_base.tox # Main TouchDesigner component
|
|
110
|
+
├── tests/ # Test code
|
|
111
|
+
│ ├── integration/
|
|
112
|
+
│ └── unit/
|
|
113
|
+
├── .env # Local environment variables (gitignored)
|
|
114
|
+
├── dotenv # Template for .env
|
|
115
|
+
└── orval.config.ts # Orval configuration (TS client generation)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## MCP Server Features
|
|
119
|
+
|
|
120
|
+
This server enables operations on TouchDesigner via the Model Context Protocol (MCP) and provides access to various tools.
|
|
121
|
+
|
|
122
|
+
### Tools
|
|
123
|
+
|
|
124
|
+
| Tool Name | Description |
|
|
125
|
+
| :-------------------------- | :--------------------------------------------------- |
|
|
126
|
+
| `create_td_node` | Creates a new node. |
|
|
127
|
+
| `delete_td_node` | Deletes an existing node. |
|
|
128
|
+
| `exec_node_method` | Calls a Python method on a node. |
|
|
129
|
+
| `execute_python_script` | Executes an arbitrary Python script in TD. |
|
|
130
|
+
| `get_td_class_details` | Retrieves details of TD Python classes/modules. |
|
|
131
|
+
| `get_td_classes` | Lists TouchDesigner Python classes. |
|
|
132
|
+
| `get_td_info` | Retrieves information about the TD server environment. |
|
|
133
|
+
| `get_td_node_parameters` | Retrieves parameters of a specific node. |
|
|
134
|
+
| `get_td_nodes` | Retrieves nodes within a parent path (optional filtering). |
|
|
135
|
+
| `update_td_node_parameters` | Updates parameters of a specific node. |
|
|
136
|
+
|
|
137
|
+
### Prompts
|
|
138
|
+
|
|
139
|
+
Prompts allow AI agents to perform specific actions in TouchDesigner.
|
|
140
|
+
|
|
141
|
+
| Prompt Name | Description |
|
|
142
|
+
| :-------------------------- | :--------------------------------------------------- |
|
|
143
|
+
| `Search node` | Performs a fuzzy search for nodes based on name, family, or type. |
|
|
144
|
+
| `Node connection` | Provides instructions for connecting nodes in TouchDesigner. |
|
|
145
|
+
| `Check node errors` | Checks for errors in specified nodes, recursively if child nodes exist. |
|
|
146
|
+
|
|
147
|
+
### Resources
|
|
148
|
+
|
|
149
|
+
Not implemented.
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
### Setting Up the Development Environment
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Install dependencies
|
|
157
|
+
npm install
|
|
158
|
+
|
|
159
|
+
# Run linters and type checkers
|
|
160
|
+
npm run lint
|
|
161
|
+
|
|
162
|
+
# Run tests
|
|
163
|
+
npm test
|
|
164
|
+
|
|
165
|
+
# Start the server with MCP Inspector for debugging
|
|
166
|
+
npm run dev
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### API Code Generation Workflow
|
|
170
|
+
|
|
171
|
+
This project uses OpenAPI-based code generation tools (Orval / openapi-generator-cli):
|
|
172
|
+
|
|
173
|
+
**API Definition:** The API contract between the Node.js MCP server and the Python server running in TouchDesigner is defined in `src/api/index.yml`.
|
|
174
|
+
|
|
175
|
+
1. **Python Server Generation (`npm run gen:webserver`):**
|
|
176
|
+
* Uses Docker to run `openapi-generator-cli`.
|
|
177
|
+
* Reads `src/api/index.yml`.
|
|
178
|
+
* Generates Python server skeleton (`td/modules/td_server/`) for the WebServer DAT in TouchDesigner.
|
|
179
|
+
* **Requires Docker to be installed and running.**
|
|
180
|
+
2. **Python Handler Generation (`npm run gen:handlers`):**
|
|
181
|
+
* Uses a custom Node.js script (`td/genHandlers.js`) and Mustache templates (`td/templates/`).
|
|
182
|
+
* Generates handler implementations (`td/modules/mcp/controllers/generated_handlers.py`) that connect to business logic in `td/modules/mcp/services/api_service.py`.
|
|
183
|
+
3. **TypeScript Client Generation (`npm run gen:mcp`):**
|
|
184
|
+
* Uses `Orval` to generate a TypeScript client (`src/tdClient/`) for the Node.js server to communicate with the Python server.
|
|
185
|
+
|
|
186
|
+
The build process (`npm run build`) executes all generation steps (`npm run gen`) and compiles TypeScript (`tsc`).
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Contributions are welcome! Follow these steps:
|
|
191
|
+
|
|
192
|
+
1. Fork the repository.
|
|
193
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`).
|
|
194
|
+
3. Make your changes.
|
|
195
|
+
4. Add tests and ensure everything works (`npm test`).
|
|
196
|
+
5. Commit your changes (`git commit -m 'Add some amazing feature'`).
|
|
197
|
+
6. Push to the branch (`git push origin feature/amazing-feature`).
|
|
198
|
+
7. Open a Pull Request.
|
|
199
|
+
|
|
200
|
+
Ensure your code follows the project's coding standards and includes appropriate tests.
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Axios from "axios";
|
|
2
|
+
const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:9981";
|
|
3
|
+
export const AXIOS_INSTANCE = Axios.create({
|
|
4
|
+
baseURL: API_BASE_URL,
|
|
5
|
+
});
|
|
6
|
+
export const customInstance = (config, options) => {
|
|
7
|
+
const source = Axios.CancelToken.source();
|
|
8
|
+
const promise = AXIOS_INSTANCE({
|
|
9
|
+
...config,
|
|
10
|
+
...options,
|
|
11
|
+
cancelToken: source.token,
|
|
12
|
+
}).then(({ data }) => data);
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
promise.cancel = () => {
|
|
15
|
+
source.cancel("Query was cancelled");
|
|
16
|
+
};
|
|
17
|
+
return promise;
|
|
18
|
+
};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { config } from "dotenv";
|
|
5
|
+
import { TouchDesignerServer } from "./server/touchDesignerServer.js";
|
|
6
|
+
config({ path: resolve(process.cwd(), ".env") });
|
|
7
|
+
/**
|
|
8
|
+
* Start TouchDesigner MCP server
|
|
9
|
+
*/
|
|
10
|
+
export async function startServer() {
|
|
11
|
+
const isStdioMode = process.env.NODE_ENV === "cli" || process.argv.includes("--stdio");
|
|
12
|
+
try {
|
|
13
|
+
const server = new TouchDesignerServer();
|
|
14
|
+
if (isStdioMode) {
|
|
15
|
+
const transport = new StdioServerTransport();
|
|
16
|
+
const result = await server.connect(transport);
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
throw new Error(`Failed to connect: ${result.error.message}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
throw new Error("Sorry, this server is not yet available in the browser. Please use the CLI mode.");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
27
|
+
console.error(`Failed to initialize server: ${errorMessage}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (process.argv[1]) {
|
|
32
|
+
startServer().catch((error) => {
|
|
33
|
+
console.error("Failed to start server:", error);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference URLs for TouchDesigner Python documentation
|
|
3
|
+
*/
|
|
4
|
+
export const TD_PYTHON_CLASS_REFERENCE_BASE_URL = "https://docs.derivative.ca";
|
|
5
|
+
export const TD_PYTHON_CLASS_REFERENCE_INDEX_URL = `${TD_PYTHON_CLASS_REFERENCE_BASE_URL}/Python_Classes_and_Modules`;
|
|
6
|
+
/**
|
|
7
|
+
* Reference Tool Names for TouchDesigner MCP
|
|
8
|
+
*/
|
|
9
|
+
export const TOOL_NAMES = {
|
|
10
|
+
CREATE_TD_NODE: "create_td_node",
|
|
11
|
+
DELETE_TD_NODE: "delete_td_node",
|
|
12
|
+
EXECUTE_PYTHON_SCRIPT: "execute_python_script",
|
|
13
|
+
EXECUTE_NODE_METHOD: "exec_node_method",
|
|
14
|
+
GET_TD_INFO: "get_td_info",
|
|
15
|
+
GET_TD_CLASS_DETAILS: "get_td_class_details",
|
|
16
|
+
GET_TD_CLASSES: "get_td_classes",
|
|
17
|
+
GET_TD_NODE_PARAMETERS: "get_td_node_parameters",
|
|
18
|
+
GET_TD_NODES: "get_td_nodes",
|
|
19
|
+
UPDATE_TD_NODE_PARAMETERS: "update_td_node_parameters",
|
|
20
|
+
};
|
|
21
|
+
export const REFERENCE_COMMENT = `Check reference resources: ${TD_PYTHON_CLASS_REFERENCE_INDEX_URL}.`;
|
|
22
|
+
export const PROMPT_NAMES = {
|
|
23
|
+
SEARCH_NODE: "Search node",
|
|
24
|
+
CHECK_NODE_ERRORS: "Check node errors",
|
|
25
|
+
NODE_CONNECTION: "Node connection",
|
|
26
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles API errors consistently across the application
|
|
3
|
+
*/
|
|
4
|
+
export function handleToolError(error, logger, toolName, referenceComment) {
|
|
5
|
+
const formattedError = error instanceof Error
|
|
6
|
+
? error
|
|
7
|
+
: new Error(error === null ? "Null error received" : String(error));
|
|
8
|
+
logger.error(toolName, formattedError);
|
|
9
|
+
const errorMessage = `${toolName}: ${formattedError}${referenceComment ? `. ${referenceComment}` : ""}`;
|
|
10
|
+
return {
|
|
11
|
+
isError: true,
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: errorMessage,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP compatible logger implementation
|
|
3
|
+
* Handles "Not connected" errors gracefully
|
|
4
|
+
*/
|
|
5
|
+
export class McpLogger {
|
|
6
|
+
server;
|
|
7
|
+
constructor(server) {
|
|
8
|
+
this.server = server;
|
|
9
|
+
}
|
|
10
|
+
// biome-ignore lint/suspicious/noExplicitAny: logging accepts any type
|
|
11
|
+
log(...args) {
|
|
12
|
+
this.sendLog("info", args);
|
|
13
|
+
}
|
|
14
|
+
// biome-ignore lint/suspicious/noExplicitAny: logging accepts any type
|
|
15
|
+
debug(...args) {
|
|
16
|
+
this.sendLog("debug", args);
|
|
17
|
+
}
|
|
18
|
+
// biome-ignore lint/suspicious/noExplicitAny: logging accepts any type
|
|
19
|
+
warn(...args) {
|
|
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);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a success result with the provided data
|
|
3
|
+
*/
|
|
4
|
+
export function createSuccessResult(data) {
|
|
5
|
+
return { success: true, data };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates an error result with the provided error
|
|
9
|
+
*/
|
|
10
|
+
export function createErrorResult(error) {
|
|
11
|
+
return { success: false, error };
|
|
12
|
+
}
|