touchdesigner-mcp-server 0.2.1 → 0.2.3

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 CHANGED
@@ -4,20 +4,100 @@ TouchDesignerのためのMCP(Model Context Protocol) サーバー実装です。
4
4
 
5
5
  ## 概要
6
6
 
7
- ![スクリーンショット 2025-04-14 21 45 47](https://github.com/user-attachments/assets/b7130ebe-406c-4e05-9efc-5d493eb800cb)
7
+ ![demo](https://github.com/user-attachments/assets/333b7db8-ebcb-4ac2-812e-c2174fa4bb2b)
8
8
 
9
9
  TouchDesigner MCPは、AIモデルとTouchDesigner WebServer DAT 間のブリッジとして機能し、AIエージェントが以下のことが可能になります
10
10
  - ノードの作成、変更、削除
11
11
  - ノードプロパティやプロジェクト構造の照会
12
12
  - PythonスクリプトによるTouchDesignerのプログラム的制御
13
13
 
14
- ## 前提条件
14
+ ## 利用方法
15
15
 
16
- - Node.js(最新のLTSバージョンを推奨)
17
- - TouchDesigner(最新の安定版を推奨)
18
- - Docker(Pythonサーバーコードの生成に必要)
16
+ *Node.js がインストールされていることが前提となります*
19
17
 
20
- ## MCPサーバーコードのビルド
18
+ ### 1. touchdesigner-mcp-server パッケージのインストール
19
+
20
+ `npm install touchdesigner-mcp-server`
21
+
22
+ ### 2. TouchDesignerとの接続
23
+
24
+ #### mcp_webserver_base.tox を TouchDesigner に配置
25
+
26
+ TouchDesignerを起動し、`td/mcp_webserver_base.tox` コンポーネントをTouchDesignerプロジェクト直下にimportします。
27
+ 例: `/project1/mcp_webserver_base` となるように配置
28
+
29
+ tox のimport により `td/import_modules.py` スクリプトが動作し、APIサーバのコントローラなどのモジュールがロードされます。
30
+
31
+ ![import](https://github.com/user-attachments/assets/46c97e13-4a26-4437-84d3-3a306e56462b)
32
+
33
+ #### APIサーバの動作確認
34
+ `npm run test` を実行することでMCPサーバーコードのユニットテストと TouchDesigner への接続テストが実行されます。
35
+ このテストでは `td/modules` ディレクトリ内のPythonモジュールが `mcp_webserver_base` コンポーネントからアクセス可能であることを確認します。
36
+ TouchDesigner のメニューから Textportを起動すると通信のログを確認することができます。
37
+
38
+ ### 3. TouchDesigner MCP Server の設定
39
+ TouchDesignerが起動した状態で、AIエージェント(Claude Desktop,Cursor, VSCode CopilotChatなど)をMCPサーバーに接続するように設定します。
40
+
41
+ *例 Claude Desktop*
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "touchdesigner": {
46
+ "args": [
47
+ "/path/to/your/touchdesigner-mcp-server/dist/index.js", // <-- touchdesigner-mcp-server/dist/index.js への絶対パスに置き換えてください
48
+ "--stdio"
49
+ ],
50
+ "command": "node",
51
+ "transportType": "stdio"
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ MCPサーバーが認識されていればセットアップは完了です。
58
+ 起動時にエラーが表示される場合はTouchDesignerを先に起動してから再度エージェントを起動してください。
59
+ TouchDesigner で APIサーバーが実行されていれば、エージェントは提供された TouchDesigner ツールを通じてTouchDesignerを使用できます。
60
+
61
+
62
+ ## MCPサーバーの機能
63
+
64
+ このサーバーは、Model Context Protocol (MCP) を通じてTouchDesigner への操作、および各種実装ドキュメントへの参照を可能にします。
65
+
66
+ ### ツール (Tools)
67
+
68
+ ツールは、AIエージェントがTouchDesignerでアクションを実行できるようにします。
69
+
70
+ | ツール名 | 説明 |
71
+ | :-------------------------- | :--------------------------------------------- |
72
+ | `create_td_node` | 新しいノードを作成します。 |
73
+ | `delete_td_node` | 既存のノードを削除します。 |
74
+ | `exec_node_method`| ノードに対しPythonメソッドを呼び出します。 |
75
+ | `execute_python_script` | TD内で任意のPythonスクリプトを実行します。 |
76
+ | `get_td_class_details` | TD Pythonクラス/モジュールの詳細情報を取得します。 |
77
+ | `get_td_classes` | TouchDesigner Pythonクラスのリストを取得します。 |
78
+ | `get_td_info` | TDサーバー環境に関する情報を取得します。 |
79
+ | `get_td_node_parameters` | 特定ノードのパラメータを取得します。 |
80
+ | `get_td_nodes` | 親パス内のノードを取得します(オプションでフィルタリング)。 |
81
+ | `update_td_node_parameters` | 特定ノードのパラメータを更新します。 |
82
+
83
+ ### プロンプト (Prompts)
84
+
85
+ プロンプトは、AIエージェントがTouchDesignerで特定のアクションを実行するための指示を提供します。
86
+
87
+ | プロンプト名 | 説明 |
88
+ | :-------------------------- | :--------------------------------------------- |
89
+ | `Search node` | ノードをファジー検索し、指定されたノード名、ファミリー、タイプに基づいて情報を取得します。 |
90
+ | `Node connection` | TouchDesigner内でノード同士を接続するための指示を提供します。 |
91
+ | `Check node errors` | 指定されたノードのエラーをチェックします。子ノードがあれば再帰的にチェックします。 |
92
+
93
+ ### リソース (Resources)
94
+
95
+ 未実装
96
+
97
+
98
+ ## 開発者向け
99
+
100
+ ### MCPサーバーコードのビルド
21
101
 
22
102
  1. リポジトリのクローン
23
103
  ```bash
@@ -39,22 +119,23 @@ cp dotenv .env
39
119
  npm run build
40
120
  ```
41
121
 
42
- ## 使い方
43
-
44
122
  ### TouchDesignerのセットアップ
45
123
 
46
- 1. **コード生成:**
47
- [MCPサーバーコードのビルド](#MCPサーバーコードのビルド) を参考に、プロジェクトルートで `npm run build` を実行します。これにより以下のコードが生成されます。
124
+ #### 1. **コード生成:**
125
+ `npm run build` を実行します。これにより以下のコードが生成されます。
48
126
  - MCPサーバコード
49
127
  - TouchDesigner WebSever DAT向けのAPIサーバーコード
50
- 2. **TouchDesigner に MCPサーバー向けWebServerをインポートする:**
128
+
129
+ #### 2. **TouchDesigner に MCPサーバー向けWebServerをインポートする:**
51
130
  TouchDesignerを起動し、`td/mcp_webserver_base.tox` コンポーネントをTouchDesignerプロジェクト直下にimportします。
52
131
  tox のimport により `td/import_modules.py` スクリプトが動作し、APIサーバのコントローラなどのモジュールがロードされます。
53
132
 
54
- 3. **APIサーバの動作確認:**
133
+ #### 3. **APIサーバの動作確認:**
55
134
  `td/modules` ディレクトリ内のPythonモジュールが `mcp_webserver_base` コンポーネントからアクセス可能であることを確認します。
56
135
  `npm run test` を実行することでMCPサーバーコードのユニットテストと TouchDesigner への結合テストが実行されます。
57
- TOuchDesigner のメニューから Textportを起動すると通信のログを確認することができます。
136
+ TouchDesigner のメニューから Textportを起動すると通信のログを確認することができます。
137
+
138
+ `npm run dev` で @modelcontextprotocol/inspector させデバッグすることができます。
58
139
 
59
140
  *TIPS*
60
141
  `mcp_webserver_base.tox` には、MCPサーバーとTouchDesignerを連携させるように設定された WebServer DAT が含まれています。
@@ -68,23 +149,23 @@ TOuchDesigner のメニューから Textportを起動すると通信のログを
68
149
 
69
150
  TouchDesignerが起動した状態で、AIエージェント(Cursor, Claude Desktop, VSCode CopilotChatなど)をMCPサーバーに接続するように設定します。
70
151
 
152
+ #### 例. Claude Desktop
71
153
  ```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"
154
+ {
155
+ "mcpServers": {
156
+ "dev_touchdesigner": {
157
+ "args": [
158
+ "/path/to/your/touchdesigner-mcp/dist/index.js", // <-- ビルド後の /dist/index.js への絶対パスに置き換えてください
159
+ "--stdio"
160
+ ],
161
+ "command": "node",
162
+ "transportType": "stdio"
81
163
  }
164
+ }
82
165
  }
83
166
  ```
84
167
 
85
- TouchDesigner で APIサーバーが実行されていれば、エージェントは提供された TouchDesigner ツールを通じてTouchDesignerを使用できます。
86
-
87
- ## セットアップ後のプロジェクト構造概要
168
+ ### セットアップ後のプロジェクト構造概要
88
169
 
89
170
  ```
90
171
  ├── src/ # MCPサーバー ソースコード
@@ -118,58 +199,6 @@ TouchDesigner で APIサーバーが実行されていれば、エージェン
118
199
  └── orval.config.ts # Orval 設定 (TSクライアント生成)
119
200
  ```
120
201
 
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
202
 
174
203
  ### APIコード生成ワークフロー
175
204
 
@@ -192,9 +221,9 @@ npm run dev
192
221
 
193
222
  ビルドプロセス (`npm run build`) は、必要なすべての生成ステップ (`npm run gen`) を実行し、その後にTypeScriptコンパイル (`tsc`) を行います。
194
223
 
195
- ## 貢献
224
+ ## 開発で貢献
196
225
 
197
- 貢献は歓迎します!貢献方法は以下の通りです:
226
+ ぜひ一緒に改善しましょう!
198
227
 
199
228
  1. リポジトリをフォーク
200
229
  2. 機能ブランチを作成(`git checkout -b feature/amazing-feature`)
@@ -204,7 +233,7 @@ npm run dev
204
233
  6. ブランチにプッシュ(`git push origin feature/amazing-feature`)
205
234
  7. プルリクエストを開く
206
235
 
207
- プロジェクトのコーディング標準に従い、適切なテストを含めてください。
236
+ 実装の変更時は必ず適切なテストを含めてください。
208
237
 
209
238
  ## ライセンス
210
239
 
package/README.md CHANGED
@@ -1,91 +1,175 @@
1
1
  # TouchDesigner MCP
2
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.
3
+ This is an implementation of an MCP (Model Context Protocol) server for TouchDesigner. The goal is to enable AI agents to control and operate TouchDesigner projects.
4
4
 
5
5
  ## Overview
6
6
 
7
- ![スクリーンショット 2025-04-14 21 45 47](https://github.com/user-attachments/assets/b7130ebe-406c-4e05-9efc-5d493eb800cb)
7
+ ![demo](https://github.com/user-attachments/assets/333b7db8-ebcb-4ac2-812e-c2174fa4bb2b)
8
8
 
9
- TouchDesigner MCP acts as a bridge between AI models and the TouchDesigner WebServer DAT, allowing AI agents to:
9
+ TouchDesigner MCP acts as a bridge between AI models and the TouchDesigner WebServer DAT, enabling AI agents to:
10
10
  - Create, modify, and delete nodes
11
11
  - Query node properties and project structure
12
- - Programmatically control TouchDesigner using Python scripts
12
+ - Programmatically control TouchDesigner via Python scripts
13
13
 
14
- ## Prerequisites
14
+ ## Usage
15
+
16
+ *Requires Node.js to be installed*
17
+
18
+ ### 1. Install the touchdesigner-mcp-server package
19
+
20
+ `npm install touchdesigner-mcp-server`
21
+
22
+ ### 2. Connect to TouchDesigner
23
+
24
+ #### Place mcp_webserver_base.tox in TouchDesigner
25
+
26
+ Start TouchDesigner and import the `td/mcp_webserver_base.tox` component directly under your TouchDesigner project.
27
+ Example: Place it as `/project1/mcp_webserver_base`
28
+
29
+ Importing the tox will trigger the `td/import_modules.py` script, which loads modules such as API server controllers.
30
+
31
+ ![import](https://github.com/user-attachments/assets/46c97e13-4a26-4437-84d3-3a306e56462b)
32
+
33
+ #### Verify API server operation
34
+ Run `npm run test` to execute unit tests for the MCP server code and connection tests to TouchDesigner.
35
+ This test ensures that the Python modules in the `td/modules` directory are accessible from the `mcp_webserver_base` component.
36
+ You can check communication logs by opening the Textport from the TouchDesigner menu.
37
+
38
+ ### 3. Configure the TouchDesigner MCP Server
39
+ With TouchDesigner running, configure your AI agent (Claude Desktop, Cursor, VSCode CopilotChat, etc.) to connect to the MCP server.
40
+
41
+ *Example: Claude Desktop*
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "touchdesigner": {
46
+ "args": [
47
+ "/path/to/your/touchdesigner-mcp-server/dist/index.js", // <-- Replace with the absolute path to touchdesigner-mcp-server/dist/index.js
48
+ "--stdio"
49
+ ],
50
+ "command": "node",
51
+ "transportType": "stdio"
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ If the MCP server is recognized, setup is complete.
58
+ If you see an error at startup, try launching the agent again after starting TouchDesigner.
59
+ If the API server is running in TouchDesigner, the agent can use TouchDesigner via the provided tools.
60
+
61
+
62
+ ## MCP Server Features
63
+
64
+ This server enables operations on TouchDesigner via the Model Context Protocol (MCP) and provides references to various implementation documents.
65
+
66
+ ### Tools
67
+
68
+ Tools allow AI agents to perform actions in TouchDesigner.
69
+
70
+ | Tool Name | Description |
71
+ | :---------------------- | :----------------------------------------------------------------- |
72
+ | `create_td_node` | Create a new node. |
73
+ | `delete_td_node` | Delete an existing node. |
74
+ | `exec_node_method` | Call a Python method on a node. |
75
+ | `execute_python_script` | Execute an arbitrary Python script in TD. |
76
+ | `get_td_class_details` | Get details of a TD Python class/module. |
77
+ | `get_td_classes` | Get a list of TouchDesigner Python classes. |
78
+ | `get_td_info` | Get information about the TD server environment. |
79
+ | `get_td_node_parameters`| Get parameters of a specific node. |
80
+ | `get_td_nodes` | Get nodes under a parent path (optionally filtered). |
81
+ | `update_td_node_parameters` | Update parameters of a specific node. |
82
+
83
+ ### Prompts
84
+
85
+ Prompts provide instructions for AI agents to perform specific actions in TouchDesigner.
86
+
87
+ | Prompt Name | Description |
88
+ | :------------------| :-------------------------------------------------------------------------- |
89
+ | `Search node` | Fuzzy search for nodes and retrieve information based on name, family, type. |
90
+ | `Node connection` | Provide instructions to connect nodes within TouchDesigner. |
91
+ | `Check node errors`| Check errors for a specified node, recursively for child nodes if any. |
92
+
93
+ ### Resources
15
94
 
16
- - Node.js (latest LTS version recommended)
17
- - TouchDesigner (latest stable version recommended)
18
- - Docker (Required for generating Python server code)
95
+ Not implemented
19
96
 
20
- ## Building the MCP Server Code
21
97
 
22
- 1. Clone the repository:
98
+ ## For Developers
99
+
100
+ ### Building the MCP Server Code
101
+
102
+ 1. Clone the repository
23
103
  ```bash
24
104
  git clone https://github.com/8beeeaaat/touchdesigner-mcp.git
25
105
  ```
26
106
 
27
- 2. Install dependencies:
107
+ 2. Install dependencies
28
108
  ```bash
29
109
  cd touchdesigner-mcp
30
110
  npm install
31
111
  ```
32
-
33
- 3. Set up environment configuration and build:
34
- ```bash
35
- # Copy the template and adjust TD_WEB_SERVER_URL if needed
112
+ 3. Set up environment file and build
113
+ ```
114
+ # Copy the template and adjust TD_WEB_SERVER_URL as needed
36
115
  cp dotenv .env
37
116
 
38
- # Build the project (Generates API clients/servers and compiles MCP resources)
39
- # Ensure Docker daemon is running before executing this command
117
+ # Build the project (generates API client/server schemas and compiles MCP resources)
118
+ # Make sure the Docker daemon is running before executing this command
40
119
  npm run build
41
120
  ```
42
121
 
43
- ## Usage
44
-
45
- ### Setting Up TouchDesigner
122
+ ### TouchDesigner Setup
46
123
 
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:
124
+ #### 1. **Code Generation:**
125
+ Run `npm run build` to generate the following code:
49
126
  - MCP server code
50
- - API server code for the TouchDesigner WebServer DAT
127
+ - API server code for TouchDesigner WebServer DAT
128
+
129
+ #### 2. **Import the WebServer for MCP server into TouchDesigner:**
130
+ Start TouchDesigner and import the `td/mcp_webserver_base.tox` component directly under your project.
131
+ Importing the tox will trigger the `td/import_modules.py` script, which loads modules such as API server controllers.
51
132
 
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.
133
+ #### 3. **Verify API server operation:**
134
+ Ensure that the Python modules in the `td/modules` directory are accessible from the `mcp_webserver_base` component.
135
+ Run `npm run test` to execute unit and integration tests for the MCP server code and TouchDesigner connection.
136
+ You can check communication logs by opening the Textport from the TouchDesigner menu.
54
137
 
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.
138
+ You can debug with @modelcontextprotocol/inspector using `npm run dev`.
57
139
 
58
140
  *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.
141
+ `mcp_webserver_base.tox` includes a WebServer DAT configured to link the MCP server and TouchDesigner.
142
+ Ensure this DAT is active and running on the port specified by `TD_WEB_SERVER_URL` in your `.env` file (default: `9981`).
143
+ To change the port:
144
+ 1. Change `TD_WEB_SERVER_PORT` in `.env`
145
+ 2. Re-run `npm run build`
146
+ 3. Change the port in mcp_webserver_base (WebServer DAT) and restart the DAT
63
147
 
64
- ### Connecting to an MCP-Compatible AI Agent
148
+ ### Connecting with MCP-compatible AI Agents
65
149
 
66
- With TouchDesigner running, configure an AI agent (e.g., Cursor, Claude Desktop, VSCode CopilotChat) to connect to the MCP server.
150
+ With TouchDesigner running, configure your AI agent (Cursor, Claude Desktop, VSCode CopilotChat, etc.) to connect to the MCP server.
67
151
 
152
+ #### Example: Claude Desktop
68
153
  ```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"
154
+ {
155
+ "mcpServers": {
156
+ "dev_touchdesigner": {
157
+ "args": [
158
+ "/path/to/your/touchdesigner-mcp/dist/index.js", // <-- Replace with the absolute path to /dist/index.js after build
159
+ "--stdio"
160
+ ],
161
+ "command": "node",
162
+ "transportType": "stdio"
78
163
  }
164
+ }
79
165
  }
80
166
  ```
81
167
 
82
- Once the API server is running in TouchDesigner, the agent can use the provided TouchDesigner tools.
83
-
84
- ## Project Structure Overview
168
+ ### Project Structure After Setup
85
169
 
86
170
  ```
87
171
  ├── src/ # MCP server source code
88
- │ ├── api/ # OpenAPI specification for TD WebServer
172
+ │ ├── api/ # OpenAPI spec for TD WebServer
89
173
  │ ├── core/ # Core utilities (logger, error handling)
90
174
  │ ├── features/ # MCP feature implementations
91
175
  │ │ ├── prompts/ # Prompt handlers
@@ -93,10 +177,10 @@ Once the API server is running in TouchDesigner, the agent can use the provided
93
177
  │ │ └── tools/ # Tool handlers (e.g., tdTools.ts)
94
178
  │ ├── gen/ # Code generated from OpenAPI schema for MCP server
95
179
  │ ├── 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
180
+ │ ├── tdClient/ # TD connection API client
181
+ │ ├── index.ts # Main entry point for Node.js server
98
182
  │ └── ...
99
- ├── td/ # TouchDesigner-related files
183
+ ├── td/ # TouchDesigner related files
100
184
  │ ├── modules/ # Python modules for TouchDesigner
101
185
  │ │ ├── mcp/ # Core logic for handling MCP requests in TD
102
186
  │ │ │ ├── controllers/ # API request controllers (api_controller.py, generated_handlers.py)
@@ -104,100 +188,52 @@ Once the API server is running in TouchDesigner, the agent can use the provided
104
188
  │ │ ├── td_server/ # Python model code generated from OpenAPI schema
105
189
  │ │ └── utils/ # Shared Python utilities
106
190
  │ ├── 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
191
+ │ ├── genHandlers.js # Node.js script for generating generated_handlers.py
192
+ │ ├── import_modules.py # Helper script to import API server modules into TD
109
193
  │ └── mcp_webserver_base.tox # Main TouchDesigner component
110
194
  ├── tests/ # Test code
111
195
  │ ├── integration/
112
196
  │ └── unit/
113
- ├── .env # Local environment variables (gitignored)
197
+ ├── .env # Local environment variables (git ignored)
114
198
  ├── dotenv # Template for .env
115
- └── orval.config.ts # Orval configuration (TS client generation)
199
+ └── orval.config.ts # Orval config (TS client generation)
116
200
  ```
117
201
 
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
202
 
169
203
  ### API Code Generation Workflow
170
204
 
171
205
  This project uses OpenAPI-based code generation tools (Orval / openapi-generator-cli):
172
206
 
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`.
207
+ **API Definition:** The API contract between the Node.js MCP server and the Python server running inside TouchDesigner is defined in `src/api/index.yml`.
174
208
 
175
- 1. **Python Server Generation (`npm run gen:webserver`):**
176
- * Uses Docker to run `openapi-generator-cli`.
209
+ 1. **Python server generation (`npm run gen:webserver`):**
210
+ * Uses `openapi-generator-cli` via Docker.
177
211
  * Reads `src/api/index.yml`.
178
- * Generates Python server skeleton (`td/modules/td_server/`) for the WebServer DAT in TouchDesigner.
212
+ * Generates a Python server skeleton (`td/modules/td_server/`) based on the API definition. This code runs inside TouchDesigner via WebServer DAT.
179
213
  * **Requires Docker to be installed and running.**
180
- 2. **Python Handler Generation (`npm run gen:handlers`):**
214
+ 2. **Python handler generation (`npm run gen:handlers`):**
181
215
  * Uses a custom Node.js script (`td/genHandlers.js`) and Mustache templates (`td/templates/`).
216
+ * Reads the generated Python server code or OpenAPI spec.
182
217
  * 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.
218
+ 3. **TypeScript client generation (`npm run gen:mcp`):**
219
+ * Uses `Orval` to generate API client code and Zod schemas for tool validation from the schema YAML bundled by `openapi-generator-cli`.
220
+ * Generates a typed TypeScript client (`src/tdClient/`) used by the Node.js server to make requests to the WebServer DAT.
185
221
 
186
- The build process (`npm run build`) executes all generation steps (`npm run gen`) and compiles TypeScript (`tsc`).
222
+ The build process (`npm run build`) runs all necessary generation steps (`npm run gen`), followed by TypeScript compilation (`tsc`).
187
223
 
188
224
  ## Contributing
189
225
 
190
- Contributions are welcome! Follow these steps:
226
+ We welcome your contributions!
191
227
 
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.
228
+ 1. Fork the repository
229
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
230
+ 3. Make your changes
231
+ 4. Add tests and ensure everything works (`npm test`)
232
+ 5. Commit your changes (`git commit -m 'Add some amazing feature'`)
233
+ 6. Push to your branch (`git push origin feature/amazing-feature`)
234
+ 7. Open a pull request
199
235
 
200
- Ensure your code follows the project's coding standards and includes appropriate tests.
236
+ Please always include appropriate tests when making implementation changes.
201
237
 
202
238
  ## License
203
239
 
@@ -3,10 +3,8 @@
3
3
  * Do not edit manually.
4
4
  * TouchDesigner API
5
5
  * OpenAPI schema for generating TouchDesigner API client code
6
- * OpenAPI spec version: 0.2.1
6
+ * OpenAPI spec version: 0.2.3
7
7
  */
8
- import { faker } from '@faker-js/faker';
9
- import { HttpResponse, delay, http } from 'msw';
10
8
  import { customInstance } from '../../api/customInstance.js';
11
9
  // eslint-disable-next-line @typescript-eslint/no-redeclare
12
10
  export const TdNodeFamilyType = {
@@ -126,125 +124,3 @@ export const getTdInfo = (options) => {
126
124
  return customInstance({ url: `http://localhost:9981/api/td/server/td`, method: 'GET'
127
125
  }, options);
128
126
  };
129
- export const getDeleteNodeResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { deleted: faker.helpers.arrayElement([faker.datatype.boolean(), undefined]), node: faker.helpers.arrayElement([{ id: faker.number.int({ min: undefined, max: undefined }), opType: faker.string.alpha(20), name: faker.string.alpha(20), path: faker.string.alpha(20), properties: {} }, undefined]) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
130
- export const getGetNodesResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { nodes: faker.helpers.arrayElement([Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ id: faker.number.int({ min: undefined, max: undefined }), opType: faker.string.alpha(20), name: faker.string.alpha(20), path: faker.string.alpha(20), properties: {} })), undefined]) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
131
- export const getCreateNodeResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { result: faker.helpers.arrayElement([{ id: faker.number.int({ min: undefined, max: undefined }), opType: faker.string.alpha(20), name: faker.string.alpha(20), path: faker.string.alpha(20), properties: {} }, undefined]) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
132
- export const getGetNodeDetailResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { id: faker.number.int({ min: undefined, max: undefined }), opType: faker.string.alpha(20), name: faker.string.alpha(20), path: faker.string.alpha(20), properties: {} }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
133
- export const getUpdateNodeResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { path: faker.helpers.arrayElement([faker.string.alpha(20), undefined]), updated: faker.helpers.arrayElement([Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => (faker.string.alpha(20))), undefined]), failed: faker.helpers.arrayElement([Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ name: faker.helpers.arrayElement([faker.string.alpha(20), undefined]), reason: faker.helpers.arrayElement([faker.string.alpha(20), undefined]) })), undefined]), message: faker.helpers.arrayElement([faker.string.alpha(20), undefined]) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
134
- export const getGetTdPythonClassesResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { classes: faker.helpers.arrayElement([Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ name: faker.string.alpha(20), type: faker.helpers.arrayElement(['class', 'module', 'function', 'object']), description: faker.helpers.arrayElement([faker.string.alpha(20), undefined]) })), undefined]) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
135
- export const getGetTdPythonClassDetailsResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { name: faker.string.alpha(20), type: faker.helpers.arrayElement(['class', 'module', 'function', 'object']), description: faker.helpers.arrayElement([faker.string.alpha(20), undefined]), methods: Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ name: faker.string.alpha(20), signature: faker.helpers.arrayElement([faker.string.alpha(20), undefined]), description: faker.helpers.arrayElement([faker.string.alpha(20), undefined]) })), properties: Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ name: faker.string.alpha(20), type: faker.string.alpha(20), value: faker.helpers.arrayElement([{}, undefined]) })) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
136
- export const getExecNodeMethodResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { result: {} }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
137
- export const getExecPythonScriptResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { result: { value: faker.helpers.arrayElement([{}, undefined]) } }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
138
- export const getGetTdInfoResponseMock = (overrideResponse = {}) => ({ success: faker.datatype.boolean(), data: { server: faker.string.alpha(20), version: faker.string.alpha(20), osName: faker.string.alpha(20), osVersion: faker.string.alpha(20) }, error: faker.helpers.arrayElement([faker.string.alpha(20), null]), ...overrideResponse });
139
- export const getDeleteNodeMockHandler = (overrideResponse) => {
140
- return http.delete('*/api/nodes', async (info) => {
141
- await delay(1000);
142
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
143
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
144
- : getDeleteNodeResponseMock()), { status: 200,
145
- headers: { 'Content-Type': 'application/json' }
146
- });
147
- });
148
- };
149
- export const getGetNodesMockHandler = (overrideResponse) => {
150
- return http.get('*/api/nodes', async (info) => {
151
- await delay(1000);
152
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
153
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
154
- : getGetNodesResponseMock()), { status: 200,
155
- headers: { 'Content-Type': 'application/json' }
156
- });
157
- });
158
- };
159
- export const getCreateNodeMockHandler = (overrideResponse) => {
160
- return http.post('*/api/nodes', async (info) => {
161
- await delay(1000);
162
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
163
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
164
- : getCreateNodeResponseMock()), { status: 200,
165
- headers: { 'Content-Type': 'application/json' }
166
- });
167
- });
168
- };
169
- export const getGetNodeDetailMockHandler = (overrideResponse) => {
170
- return http.get('*/api/nodes/detail', async (info) => {
171
- await delay(1000);
172
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
173
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
174
- : getGetNodeDetailResponseMock()), { status: 200,
175
- headers: { 'Content-Type': 'application/json' }
176
- });
177
- });
178
- };
179
- export const getUpdateNodeMockHandler = (overrideResponse) => {
180
- return http.patch('*/api/nodes/detail', async (info) => {
181
- await delay(1000);
182
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
183
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
184
- : getUpdateNodeResponseMock()), { status: 200,
185
- headers: { 'Content-Type': 'application/json' }
186
- });
187
- });
188
- };
189
- export const getGetTdPythonClassesMockHandler = (overrideResponse) => {
190
- return http.get('*/api/td/classes', async (info) => {
191
- await delay(1000);
192
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
193
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
194
- : getGetTdPythonClassesResponseMock()), { status: 200,
195
- headers: { 'Content-Type': 'application/json' }
196
- });
197
- });
198
- };
199
- export const getGetTdPythonClassDetailsMockHandler = (overrideResponse) => {
200
- return http.get('*/api/td/classes/:className', async (info) => {
201
- await delay(1000);
202
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
203
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
204
- : getGetTdPythonClassDetailsResponseMock()), { status: 200,
205
- headers: { 'Content-Type': 'application/json' }
206
- });
207
- });
208
- };
209
- export const getExecNodeMethodMockHandler = (overrideResponse) => {
210
- return http.post('*/api/td/nodes/exec', async (info) => {
211
- await delay(1000);
212
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
213
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
214
- : getExecNodeMethodResponseMock()), { status: 200,
215
- headers: { 'Content-Type': 'application/json' }
216
- });
217
- });
218
- };
219
- export const getExecPythonScriptMockHandler = (overrideResponse) => {
220
- return http.post('*/api/td/server/exec', async (info) => {
221
- await delay(1000);
222
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
223
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
224
- : getExecPythonScriptResponseMock()), { status: 200,
225
- headers: { 'Content-Type': 'application/json' }
226
- });
227
- });
228
- };
229
- export const getGetTdInfoMockHandler = (overrideResponse) => {
230
- return http.get('*/api/td/server/td', async (info) => {
231
- await delay(1000);
232
- return new HttpResponse(JSON.stringify(overrideResponse !== undefined
233
- ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse)
234
- : getGetTdInfoResponseMock()), { status: 200,
235
- headers: { 'Content-Type': 'application/json' }
236
- });
237
- });
238
- };
239
- export const getTouchDesignerAPIMock = () => [
240
- getDeleteNodeMockHandler(),
241
- getGetNodesMockHandler(),
242
- getCreateNodeMockHandler(),
243
- getGetNodeDetailMockHandler(),
244
- getUpdateNodeMockHandler(),
245
- getGetTdPythonClassesMockHandler(),
246
- getGetTdPythonClassDetailsMockHandler(),
247
- getExecNodeMethodMockHandler(),
248
- getExecPythonScriptMockHandler(),
249
- getGetTdInfoMockHandler()
250
- ];
@@ -3,7 +3,7 @@
3
3
  * Do not edit manually.
4
4
  * TouchDesigner API
5
5
  * OpenAPI schema for generating TouchDesigner API client code
6
- * OpenAPI spec version: 0.2.1
6
+ * OpenAPI spec version: 0.2.3
7
7
  */
8
8
  import { z as zod } from 'zod';
9
9
  /**
@@ -18,7 +18,7 @@ export class TouchDesignerServer {
18
18
  constructor() {
19
19
  this.server = new McpServer({
20
20
  name: "TouchDesigner",
21
- version: "0.2.1",
21
+ version: "0.2.3",
22
22
  }, {
23
23
  capabilities: {
24
24
  prompts: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "touchdesigner-mcp-server",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "MCP server for TouchDesigner",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,6 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@biomejs/biome": "1.9.4",
31
- "@faker-js/faker": "^9.7.0",
32
31
  "@types/jsdom": "^21.1.7",
33
32
  "@types/node": "^22.15.2",
34
33
  "@vitest/coverage-v8": "^3.1.2",
@@ -2,7 +2,7 @@ openapi: 3.0.0
2
2
  info:
3
3
  description: OpenAPI schema for generating TouchDesigner API client code
4
4
  title: TouchDesigner API
5
- version: 0.2.1
5
+ version: 0.2.3
6
6
  servers:
7
7
  - url: "{baseUrl}"
8
8
  variables:
@@ -1,5 +0,0 @@
1
- async function initMocks() {
2
- const { node } = await import("./node.js");
3
- node.listen();
4
- }
5
- export { initMocks };
package/dist/mock/node.js DELETED
@@ -1,3 +0,0 @@
1
- import { setupServer } from "msw/node";
2
- import { getTouchDesignerAPIMock } from "../gen/endpoints/TouchDesignerAPI.js";
3
- export const node = setupServer(...getTouchDesignerAPIMock());