td-mcp
# td-mcp
A lean, token-efficient [MCP](https://modelcontextprotocol.io) server for
driving [TouchDesigner](https://derivative.ca) from AI assistants like Claude.
Build whole node networks in one call, search CHOP channels by glob, inspect
operators compactly, and screenshot any TOP so the assistant can *see* what it
built. Battle-tested by building audio-reactive and hand-tracking projects
end to end.
## Why another TouchDesigner MCP?
Compared to a conventional per-node tool surface, td-mcp is designed to
minimize round trips and context tokens:
- **`td_build`** - create a whole network (operators + parameters +
expressions + wires) in ONE call.
- **`td_find_channels`** - glob-search every CHOP in the project
(e.g. `*pinch*`) instead of dumping node trees.
- **`td_get`** - returns only NON-default parameters.
- **`td_screenshot`** - saves any TOP to PNG for visual verification.
- **`td_ensure_cook`** - one call installs a per-frame force-cook (fixes the
classic "GLSL/feedback network renders once then freezes" gotcha).
- Wrong parameter names return close-match suggestions instead of bare errors.
- Operator paths self-locate by name if the exact path moved.
- One-line tool descriptions - tool schemas are loaded into every session,
so short docs are cheaper.
## Architecture
```
Claude / MCP client
| stdio (MCP)
server.py (Python, FastMCP)
| HTTP POST 127.0.0.1:9980/api (JSON)
TouchDesigner: /project1/td_mcp
|- webserver (Web Server DAT, port 9980)
|- callbacks (Text DAT - HTTP handler)
|- dispatcher (Text DAT - 16 command handlers, TD Python API)
```
The bridge is installed **by script** (no .tox drag-drop): re-runnable,
self-healing, and the DAT contents always match the repo sources.
## Setup
Requirements: [uv](https://docs.astral.sh/uv/), TouchDesigner (any recent
build; tested on 2025.3x macOS).
1. Clone and install:
```sh
git clone https://github.com/YOURNAME/td-mcp && cd td-mcp && uv sync
```
2. Install the bridge inside TouchDesigner - open the textport
(Alt+T / Option+T) and run (adjust the path to your clone):
```python
exec(open('/path/to/td-mcp/td/install_bridge.py').read())
```
Verify from a terminal:
`curl -s http://127.0.0.1:9980/api -d '{"cmd":"status"}'`
3. Register the server with your MCP client. For Claude Code, in
`.mcp.json`:
```json
{
"mcpServers": {
"td": {
"command": "uv",
"args": ["--directory", "/path/to/td-mcp", "run", "python", "server.py"]
}
}
}
```
4. Restart the client and ask it to `td_status`.
## Tools
| Tool | Purpose |
|---|---|
| `td_status` | TD + bridge status |
| `td_build` | whole network in one call (ops, params, exprs, wires) |
| `td_create` / `td_delete` | single operator create / delete |
| `td_set` | set params; `{"expr": ...}` for expressions, `"PULSE"` to pulse |
| `td_connect` | wire two operators |
| `td_get` / `td_list` | compact inspection |
| `td_find_channels` | glob-search CHOP channels project-wide |
| `td_read_chop` | live channel values |
| `td_ensure_cook` | per-frame force-cook (anti-freeze) |
| `td_screenshot` | save a TOP to PNG |
| `td_save` / `td_load_tox` | save project / load a .tox |
| `td_errors` | all erroring operators under a path |
| `td_exec` | escape hatch: run Python inside TD |
## Field notes (learned the hard way)
- TD's Python `open()` defaults to ASCII - the bridge sources are pure ASCII.
- `ParMode` is not on the `td` module inside DAT modules; the dispatcher uses
`type(par.mode).EXPRESSION` instead (version-proof).
- Feedback TOPs need an actual input connection, not just a Target TOP.
- COMP-to-COMP wiring requires matching connector families (a CHOP output
cannot feed a DAT input) - check `outputConnectors[i].outOP` types.
- After building feedback networks, pulse `resetpulse` once to flush any
pre-expression frames the loop may have latched.
## Credits
Bridge-over-Web-Server-DAT architecture inspired by
[8beeeaaat/touchdesigner-mcp](https://github.com/8beeeaaat/touchdesigner-mcp).
## License
MIT
TDQS
Scored across 16 tools
Each tool targets a distinct operation: status checks connection, build creates networks, create makes single ops, set modifies params, connect wires, get inspects, list enumerates children, delete removes, find_channels/read_chop handle CHOP data, ensure_cook forces cooking, screenshot captures images, save/load handle files, errors finds problems, and exec runs arbitrary Python. No two tools have overlapping purposes.
All tools follow a consistent `td_verb` or `td_noun` pattern, with verbs like create, set, connect, get, list, delete, find, read, save, load, and exec. The two noun-like names (td_status, td_errors) are intuitive and don't break the overall naming scheme.
16 tools is comprehensive but not excessive for a TouchDesigner MCP server that needs to support network building, parameter manipulation, inspection, debugging, file I/O, and execution. It's one tool over the typical '5-15' range but still well-scoped for the diversity of operations.
The tool set covers the core lifecycle: create, delete, connect, set params, save/load, and inspect. It also includes important extras like channel finding, error reporting, screenshots, and a Python escape hatch. Minor gaps exist (no explicit disconnect/rename/move operations), but td_exec can cover these, so agents have workarounds.