New skill: creative/touchdesigner — control a running TouchDesigner
instance via REST API. Build real-time visual networks programmatically.
Architecture:
Hermes Agent -> HTTP REST (curl) -> TD WebServer DAT -> TD Python env
Key features:
- Custom API handler (scripts/custom_api_handler.py) that creates a
self-contained WebServer DAT + callback in TD. More reliable than the
official mcp_webserver_base.tox which frequently fails module imports.
- Discovery-first workflow: never hardcode TD parameter names. Always
probe the running instance first since names change across versions.
- Persistent setup: save the TD project once with the API handler baked
in. TD auto-opens the last project on launch, so port 9981 is live
with zero manual steps after first-time setup.
- Works via curl in execute_code (no MCP dependency required).
- Optional MCP server config for touchdesigner-mcp-server npm package.
Skill structure (2823 lines total):
SKILL.md (209 lines) — setup, workflow, key rules, operator reference
references/pitfalls.md (276 lines) — 24 hard-won lessons
references/operators.md (239 lines) — all 6 operator families
references/network-patterns.md (589 lines) — audio-reactive, generative,
video processing, GLSL, instancing, live performance recipes
references/mcp-tools.md (501 lines) — 13 MCP tool schemas
references/python-api.md (443 lines) — TD Python scripting patterns
references/troubleshooting.md (274 lines) — connection diagnostics
scripts/custom_api_handler.py (140 lines) — REST API handler for TD
scripts/setup.sh (152 lines) — prerequisite checker
Tested on TouchDesigner 099 Non-Commercial (macOS/darwin).
17 KiB
TouchDesigner MCP Tools Reference
Complete parameter schemas and usage examples for all 13 MCP tools from the 8beeeaaat/touchdesigner-mcp server.
Hermes Configuration
Add a touchdesigner entry under the mcp_servers section of your Hermes config. Example YAML block:
# Under mcp_servers: in config.yaml
mcp_servers:
touchdesigner:
command: npx
args: ["-y", "touchdesigner-mcp-server@latest"]
env:
TD_API_URL: "http://127.0.0.1:9981"
timeout: 120
connect_timeout: 60
For a locally built server, point command to node and args to the built server index.js path. Set TD_API_URL to the TouchDesigner WebServer DAT address (default port 9981).
For the documentation/knowledge server (no running TD needed), add a td_docs entry using touchdesigner-mcp-server as the npx package.
Tools are registered as mcp_touchdesigner_<tool_name> in Hermes.
If MCP tools are not available as direct function calls (common when the MCP server connects but Hermes doesn't expose them as callable tools), use the custom API handler directly via curl in execute_code or terminal:
import json, shlex
from hermes_tools import terminal
def td_exec(script):
"""Execute Python in TouchDesigner via the REST API."""
escaped = json.dumps({"script": script})
cmd = f"curl -s --max-time 15 -X POST -H 'Content-Type: application/json' -d {shlex.quote(escaped)} 'http://127.0.0.1:9981/api/td/server/exec'"
r = terminal(cmd, timeout=20)
return json.loads(r['output'])
# Example: list all nodes
result = td_exec('result = [c.name for c in op("/project1").children]')
print(result) # {"result": ["node1", "node2", ...], "stdout": "", "stderr": ""}
This td_exec helper works with both the official .tox handler and the custom API handler from scripts/custom_api_handler.py.
Tools are registered as mcp_touchdesigner_<tool_name> in Hermes.
Common Formatting Parameters
Most tools accept these optional formatting parameters:
| Parameter | Type | Values | Description |
|---|---|---|---|
detailLevel |
string | "minimal", "summary", "detailed" |
Response verbosity |
responseFormat |
string | "json", "yaml", "markdown" |
Output format |
limit |
integer | 1-500 | Max items (on list-type tools only) |
These are client-side formatting — they control how the MCP server formats the response text, not what data TD returns.
Tool 1: describe_td_tools
Purpose: Meta-tool — lists all available TouchDesigner MCP tools with descriptions and parameters.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
filter |
string | No | Keyword to filter tools by name, description, or parameter |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Example: Find tools related to node creation
describe_td_tools(filter="create")
Note: This tool runs entirely in the MCP server — it does NOT contact TouchDesigner. Use it to discover what's available.
Tool 2: get_td_info
Purpose: Get TouchDesigner server information (version, OS, build).
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Example: Check TD is running and get version
get_td_info()
Returns: TD version, build number, OS name/version, MCP API version.
Use this first to verify the connection is working before building networks.
Tool 3: execute_python_script
Purpose: Execute arbitrary Python code inside TouchDesigner's Python environment.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
script |
string | Yes | Python code to execute |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Available globals in the script:
op— find operators by pathops— find multiple operators by patternme— the WebServer DAT running the scriptparent— me.parent()project— root project componenttd— the full td moduleresult— set this to explicitly return a value
Execution behavior:
- Single-line scripts: tries
eval()first (returns value), falls back toexec() - Multi-line scripts: uses
exec()always - stdout/stderr are captured and returned separately
- If
resultis not set, tries to evaluate the last expression as the return value
Examples:
# Simple query
execute_python_script(script="op('/project1/noise1').par.seed.val")
# Returns: {"result": 42, "stdout": "", "stderr": ""}
# Multi-line script
execute_python_script(script="""
nodes = op('/project1').findChildren(type=TOP)
result = [{'name': n.name, 'type': n.OPType} for n in nodes]
""")
# Connect two operators
execute_python_script(script="op('/project1/noise1').outputConnectors[0].connect(op('/project1/level1'))")
# Create and configure in one script
execute_python_script(script="""
parent = op('/project1')
n = parent.create(noiseTop, 'my_noise')
n.par.seed.val = 42
n.par.monochrome.val = True
n.par.resolutionw.val = 1920
n.par.resolutionh.val = 1080
result = {'path': n.path, 'type': n.OPType}
""")
# Batch wire a chain
execute_python_script(script="""
chain = ['noise1', 'level1', 'blur1', 'composite1', 'null_out']
for i in range(len(chain) - 1):
src = op(f'/project1/{chain[i]}')
dst = op(f'/project1/{chain[i+1]}')
if src and dst:
src.outputConnectors[0].connect(dst)
result = 'Wired chain: ' + ' -> '.join(chain)
""")
When to use: Wiring connections, complex logic, batch operations, querying state that other tools don't cover. This is the most powerful and flexible tool.
Tool 4: create_td_node
Purpose: Create a new operator in TouchDesigner.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
parentPath |
string | Yes | Path to parent (e.g., /project1) |
nodeType |
string | Yes | Operator type (e.g., noiseTop, mathChop) |
nodeName |
string | No | Custom name (auto-generated if omitted) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Examples:
create_td_node(parentPath="/project1", nodeType="noiseTop", nodeName="bg_noise")
create_td_node(parentPath="/project1", nodeType="compositeTop") # auto-named
create_td_node(parentPath="/project1/audio_chain", nodeType="audiospectrumChop", nodeName="spectrum")
Returns: Node summary with id, name, path, opType, and all default parameter values.
Node type naming convention: camelCase family suffix — noiseTop, mathChop, gridSop, tableDat, phongMat, geometryComp. See references/operators.md for the full list.
Tool 5: delete_td_node
Purpose: Delete an existing operator.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
nodePath |
string | Yes | Absolute path to node (e.g., /project1/noise1) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Example:
delete_td_node(nodePath="/project1/noise1")
Returns: Confirmation with the deleted node's summary (captured before deletion).
Tool 6: get_td_nodes
Purpose: List operators under a path with optional filtering.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
parentPath |
string | Yes | Parent path (e.g., /project1) |
pattern |
string | No | Glob pattern for name filtering (default: *) |
includeProperties |
boolean | No | Include full parameter values (default: false) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
limit |
integer | No | Max items (1-500) |
Examples:
# List all direct children of /project1
get_td_nodes(parentPath="/project1")
# Find all noise operators
get_td_nodes(parentPath="/project1", pattern="noise*")
# Get full parameter details
get_td_nodes(parentPath="/project1", pattern="*", includeProperties=true, limit=20)
Returns: List of node summaries. With includeProperties=false (default): id, name, path, opType only. With includeProperties=true: full parameter values included.
Tool 7: get_td_node_parameters
Purpose: Get detailed parameters of a specific node.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
nodePath |
string | Yes | Node path (e.g., /project1/noise1) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
limit |
integer | No | Max parameters (1-500) |
Example:
get_td_node_parameters(nodePath="/project1/noise1")
Returns: All parameter name-value pairs for the node. Use this to discover available parameters before calling update_td_node_parameters.
Tool 8: get_td_node_errors
Purpose: Check for errors on a node and all its descendants (recursive).
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
nodePath |
string | Yes | Absolute path to inspect (e.g., /project1) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
limit |
integer | No | Max error items (1-500) |
Examples:
# Check entire project for errors
get_td_node_errors(nodePath="/project1")
# Check a specific chain
get_td_node_errors(nodePath="/project1/audio_chain")
Returns: Error count, hasErrors boolean, and list of errors each with nodePath, nodeName, opType, and error message.
Always call this after building a network to catch wiring mistakes, missing references, and configuration errors.
Tool 9: update_td_node_parameters
Purpose: Update parameters on an existing node.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
nodePath |
string | Yes | Path to node (e.g., /project1/noise1) |
properties |
object | Yes | Key-value pairs to update (e.g., {"seed": 42, "monochrome": true}) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Examples:
# Set noise parameters
update_td_node_parameters(
nodePath="/project1/noise1",
properties={"seed": 42, "monochrome": false, "period": 4.0, "harmonics": 3,
"resolutionw": 1920, "resolutionh": 1080}
)
# Set a file path
update_td_node_parameters(
nodePath="/project1/moviefilein1",
properties={"file": "/Users/me/Videos/clip.mp4", "play": true}
)
# Set compositing mode
update_td_node_parameters(
nodePath="/project1/composite1",
properties={"operand": 0} # 0=Over, 1=Under, 3=Add, 18=Multiply, 27=Screen
)
Returns: List of successfully updated properties and any that failed (with reasons). Raises error if zero properties were updated.
Parameter value types: Floats, ints, booleans, and strings are all accepted. For menu parameters, use either the string label or the integer index.
Tool 10: exec_node_method
Purpose: Call a Python method directly on a specific node.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
nodePath |
string | Yes | Path to node |
method |
string | Yes | Method name to call |
args |
array | No | Positional arguments (strings, numbers, booleans) |
kwargs |
object | No | Keyword arguments |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Examples:
# Get all children of a component
exec_node_method(nodePath="/project1", method="findChildren")
# Find specific children
exec_node_method(nodePath="/project1", method="findChildren",
kwargs={"name": "noise*", "depth": 1})
# Get node errors
exec_node_method(nodePath="/project1/noise1", method="errors")
# Get node warnings
exec_node_method(nodePath="/project1/noise1", method="warnings")
# Save a component as .tox
exec_node_method(nodePath="/project1/myContainer", method="save",
args=["/path/to/component.tox"])
Returns: Processed return value of the method call. TD operators are serialized to their path strings, iterables to lists, etc.
Tool 11: get_td_classes
Purpose: List available TouchDesigner Python classes and modules.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
limit |
integer | No | Max items (default: 50) |
Example:
get_td_classes(limit=100)
Returns: List of class/module names and their docstrings from the td module. Useful for discovering what's available in TD's Python environment.
Tool 12: get_td_class_details
Purpose: Get methods and properties of a specific TD Python class.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
className |
string | Yes | Class name (e.g., noiseTop, OP, COMP) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
limit |
integer | No | Max methods/properties (default: 30) |
Examples:
# Inspect the noiseTop class
get_td_class_details(className="noiseTop")
# Inspect the base OP class (all operators inherit from this)
get_td_class_details(className="OP", limit=50)
# Inspect COMP (component) class
get_td_class_details(className="COMP")
Returns: Class name, type, description, methods (name + description + type), and properties (name + description + type).
Tool 13: get_td_module_help
Purpose: Retrieve Python help() text for any TD module, class, or function.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
moduleName |
string | Yes | Module/class name (e.g., noiseCHOP, tdu, td.OP) |
detailLevel |
string | No | Response verbosity |
responseFormat |
string | No | Output format |
Examples:
# Get help for the noise CHOP class
get_td_module_help(moduleName="noiseCHOP")
# Get help for the tdu utilities module
get_td_module_help(moduleName="tdu")
# Dotted name resolution works
get_td_module_help(moduleName="td.OP")
Returns: Full Python help() text output, cleaned of backspace characters.
Workflow: Building a Complete Network
Typical sequence of tool calls to build a project:
get_td_info— verify connectionget_td_nodes(parentPath="/project1")— see what already existscreate_td_node(multiple) — create all operatorsupdate_td_node_parameters(multiple) — configure each operatorexecute_python_script— wire all connections in one batch scriptget_td_node_errors(nodePath="/project1")— check for problemsget_td_node_parameters— verify specific nodes if needed- Iterate: adjust parameters, add operators, fix errors
TD Documentation MCP Server Tools
The bottobot/touchdesigner-mcp-server provides 21 reference/knowledge tools (no running TD needed):
| Tool | Purpose |
|---|---|
get_operator |
Get full documentation for a specific operator |
search_operators |
Search operators by keyword |
list_operators |
List all operators (filterable by family) |
compare_operators |
Compare two operators side by side |
get_operator_examples |
Get usage examples for an operator |
suggest_workflow |
Get workflow suggestions for a task |
get_tutorial |
Get a full TD tutorial |
list_tutorials |
List available tutorials |
search_tutorials |
Search tutorial content |
get_python_api |
Get Python API class documentation |
search_python_api |
Search Python API |
list_python_classes |
List all documented Python classes |
get_version_info |
Get TD version release notes |
list_versions |
List all documented TD versions |
get_experimental_techniques |
Get advanced technique guides (GLSL, ML, generative, etc.) |
search_experimental |
Search experimental techniques |
get_glsl_pattern |
Get GLSL code patterns (SDF, color, math utilities) |
get_operator_connections |
Get common operator wiring patterns |
get_network_template |
Get complete network templates with Python generation scripts |
get_experimental_build |
Get experimental build info |
list_experimental_builds |
List experimental builds |
This server contains 630 operator docs, 14 tutorials, 69 Python API classes, and 7 experimental technique categories with working code.