td-atlas
td-atlas exposes TouchDesigner to AI agents over MCP, combining an offline operator/parameter index, a live bridge into a running project, and offline .toe/.tox file tools.
Search the atom index for operators, parameters, Python API members, documentation, glossary entries, and palette components; inspect exact operator schemas and example networks.
Inspect a running TouchDesigner instance: status, running instances, call journal, doctor checks, network topology, operator details, flags, errors, health, and signal traces.
Edit live projects atomically: build networks, set parameters, set flags, undo/redo, add Python extensions, annotate networks, and coordinate multi-agent writes via claim scopes.
Render and record: render TOPs to images, run timeline frame-by-frame jobs, profile per-frame operator costs, and check, cancel, or poll those jobs.
Work with .toe/.tox files offline: read project trees, dump or rewrite networks as JSON, diff projects, grep embedded Python/GLSL, and save/list/restore/diff variants and snapshots.
Load ready-made palette components directly into a running project.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@td-atlas check health of my running TouchDesigner instance"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
td-atlas gives an agent three things. The exact operator and parameter names from this machine. Hands inside a running instance, with one step of undo. And a way to read a saved project without opening it.
What it does
The atom index is the name list. Two passes read every operator and parameter out of your own copy of the application into one SQLite file. The values in it are the values that copy reports.
The bridge lets an agent change your project while TouchDesigner is running. A script builds it there out of four ordinary nodes: a Web Server DAT, a callbacks DAT, a status panel, and an Execute DAT that fires when you save. You can read it, see its changes in git, and upgrade it in place.
What TouchDesigner does not report.
errorscovers what TouchDesigner itself calls an error, andtd_healthcovers the breakage it stays quiet about.The call journal writes one line per bridge call to a file on disk, and it outlives the session.
Reading projects offline inspects, searches and compares a project with TouchDesigner closed, and the original file is left alone.
The network text, written on save is what the bridge can put beside the
.toeon every save, so a project gets a diffable history in git.
Related MCP server: TDPilot
Install
Three things have to be there first.
TouchDesigner, already installed. The index is built from your copy of the application and holds the values that copy reports. There is nothing to download.
Python 3.11 or newer, on the same computer as TouchDesigner.
An AI agent that speaks MCP. The agent is what calls these tools. td-atlas was built and measured against Claude Code, whose command is the
claude mcp addline further down. Any MCP client reaches the same tools.
Compatibility lists the platforms and what the connector can change in your project.
On macOS, one line from a terminal. The installer is a POSIX shell script, so Windows takes the step-by-step sequence below.
curl -fsSL https://grigabyte.github.io/td-atlas/i | shIf that address does not answer, the same script comes out of the repository:
curl -fsSL https://raw.githubusercontent.com/grigabyte/td-atlas/main/install.sh | shinstall.sh finds a Python, clones the repository, makes a
virtualenv beside it, installs the package, builds the index and stages the
bridge. Every command is printed before it runs.
It asks two questions: where to clone, and whether to build the index now.
The default answer to the first is ~/td-atlas. With no terminal to ask, it
takes the default for both.
Two directories end up on disk: the checkout, ~/td-atlas unless you named
another, and ~/.td-atlas. Besides those, uv or pip fills its own package
cache, as it does for any package. No sudo. System directories and your shell
startup files are left alone. Run it again on an existing checkout and it
updates that checkout.
The block below uses uv, a fast installer
for Python packages. Each line carries a second form in the comment beside it,
and that one runs on the python3 you already have.
git clone https://github.com/grigabyte/td-atlas
cd td-atlas
uv venv # or: python3 -m venv .venv
uv pip install -e . # or: .venv/bin/pip install -e .There is no package on PyPI. pip install td-atlas and uvx td-atlas will
find nothing. Then, from the checkout:
.venv/bin/td-atlas build # offline index, 13–16 s, no TouchDesigner process
.venv/bin/td-atlas install # stage the bridge, print the bootstrap and MCP linesCommands from here on are written td-atlas for short. Unless the virtualenv
is activated, call it by path. In the checkout that path is
.venv/bin/td-atlas. From anywhere else it is the whole path,
~/td-atlas/.venv/bin/td-atlas for the default directory. On Windows it is
.venv\Scripts\td-atlas. A system Python does not see the package.
td-atlas install prints two things to paste. The curl line ran it for you,
so both are already at the end of what it printed; running it again prints them
again. First, into TouchDesigner's textport (Dialogs → Textport and DATs),
once per project:
exec(open('/Users/you/.td-atlas/bootstrap.py').read())The textport answers with [td-atlas] lines. The last one names your
TouchDesigner build and the project the bridge attached to.
[td-atlas] registered as /Users/you/.td-atlas/instances/9977.json
[td-atlas] bridge ready at /tdatlas on port 9977 (auth: token)
[td-atlas] TouchDesigner 2025.32460, project 'NewProject.1.toe'Second, a claude mcp add line for your MCP client. See
As an MCP server. To also write that same entry into
DIR/.mcp.json, or merge it into one that is already there, pass
--write-mcp-json DIR.
Once the textport has answered, finish the index.
td-atlas probeThis pass adds the facts only a running instance knows.
Last, check the install. If you came in halfway, start here.
td-atlas doctorA finished install answers with every link ok, and one closing line.
environment : ok — running from /Users/you/td-atlas/.venv …
touchdesigner : ok — build 2025.32460 at /Applications/TouchDesigner.app …
index : ok — 667 ops, 24251 params, 2060 articles …
index build : ok — index and installation agree: 2025.32460
probe : ok — runtime pass complete: 647 ops probed …
bridge : ok — connected on port 9977 to 'NewProject.1.toe' …
mcp server : ok — 'claude mcp add …' launches …
every link checked out.The counts come off your own copy of TouchDesigner, so yours will differ.
Every link that is not ok comes with its repair, and a broken one makes the
command exit non-zero. Before the index is built you see
index : FAIL … fix: td-atlas build, and before the bridge is staged,
bridge : warn … fix: td-atlas install.
As an MCP server
Run td-atlas install and paste the claude mcp add … line it prints. That
line names the interpreter by absolute path, so it keeps working from any
working directory, with or without an activated virtualenv. Wiring it in by
hand looks like this:
claude mcp add td-atlas -- /path/to/python -m td_atlas.cli mcpFrom here you say what you want in plain language. Here is what the agent calls on it:
What you say to the agent | What it calls |
"Which operator displaces an image with noise? Give me the exact parameter names before you build anything." |
|
"Build a noise into a blur into an out TOP in the project I have open, and check nothing is silently dead." |
|
"It looks like nothing is happening." |
|
"Show me what that looks like right now, and the motion over a second." |
|
"What is inside |
|
"What did you change since we started?" |
|
"Undo that." |
|
47 tools in three groups. 9 index tools work offline, 29 live tools act
on a running instance, and 9 project-file tools read and write
.toe/.tox from disk. Each one, with its arguments and what it is for, is in
plugin/skills/touchdesigner/references/tools.md,
and a test holds that list to the code.
td_build and td_set_params check parameter names against the index before
sending, so the usual mistakes come back as corrections:
- t: is a parameter group, not a settable parameter (try: tx, ty, tz)
- typ: no such parameter (try: type, ty)
- type: 'simplex5d' is not a valid menu entry
(try: simplex4d, simplex3d, simplex2d, sparse, perlin4d)
- period: -3 is below the clamped minimum 0.0Documentation
Document | For |
Agents using the connector | |
Every trap that produced no error | |
All 47 MCP tools | |
Agents contributing to this repository | |
How to run the tests and the linter before a pull request | |
What changed per version, and every protocol change without fail | |
How the three layers fit together, and why | |
Every | |
The reverse-engineered | |
The two passes that build the index, and what each source yields | |
The component that runs inside TouchDesigner, and what it adds beyond | |
What TouchDesigner does not report, and what | |
The call journal: what is written, by whom, and what is kept out | |
Reading, searching and comparing a | |
The diffable text written beside the | |
Builds, Python, operating systems, and what this can change in your project | |
The agent skill, and installing it as a plugin | |
Building the | |
Every symptom, what it is, and what to run | |
The test suite and the invariant it holds | |
Every directory in the repository and what lives there |
Licence
MIT, and the full text is in LICENSE. TouchDesigner is a product of Derivative Inc. This project is not affiliated with them and redistributes nothing from the installation. It only reads what is already on your machine.
Available Tools
46 toolstd_annotateA
Leave a note in the network saying what you built and why.
Reach for this at the end of a build, not as decoration: the network you made records what it does and nothing about why, and the person who opens the project next reads the network editor, not this conversation. An Annotate is a coloured box with your text in it, sitting beside the nodes it describes.
text is the body (newlines work), title the bar along the top. Without
position the note is placed where it does not cover anything, and without
size it takes the default 382x288 network units — make it big enough to
enclose the nodes it is about and td_annotations will report them as the
ones it covers.
Pass path (an existing note) instead of parent to rewrite that note
rather than add another — the right call when you rerun a build. The reply
always names the path the note actually has: TouchDesigner ignores the name
given at creation, so name is applied afterwards and can be refused if a
sibling holds it.
mode is comment, networkbox or annotate: a comment is text only, a
network box groups nodes without a title bar.
Inputs: text (required), mode, name, path, +7 more. Returns: result
td_annotationsA
Read the notes in a network — including the ones a person left for you.
Check this before building in a project you did not build. An artist can leave a brief as an Annotate beside the nodes it concerns, which is the natural place to put it and completely invisible to every other tool here: it is not an error, not a parameter and not a name.
Each note comes back with the nodes its box sits over, so a note saying "this chain is the one to keep" can be matched to the chain. That list is geometric — the tiles whose centre falls inside the box — so a node the artist dragged half out of the box counts as outside.
Inputs: path, depth. Returns: result
td_buildA
Apply several edits to the project as one atomic, undoable block.
Prefer this over separate calls: if any step fails the whole batch is rolled back, so the project never ends up half-modified, and a successful batch is a single Ctrl+Z for the person using TouchDesigner.
Each operation is {"method": ..., "params": {...}} where method is one of op_create, op_delete, op_connect, op_disconnect, par_set.
op_create takes parent, type, name, optional pars {name: value}, optional position [x, y], optional connect [{"from": path, "index": 0}], and optional text for a DAT's contents — shader and script source belongs there, not in a separate td_exec, so it lands inside this undo block. Values may be a constant, {"expr": "..."} for an expression, {"bind": "..."} or {"pulse": true}. Parameter names are validated against the index first.
Pass the same owner you claimed the area with — it carries into every
step, and without it your own claim refuses the batch.
Inputs: operations (required), owner, undo_name. Returns: result
td_claim_scopeA
Announce one subtree of the network as yours while you work in it.
Reach for this before a run of edits whenever another agent or session may
be touching the same project: without a claim, two agents editing the same
nodes overwrite each other and neither result reports anything wrong.
owner is any string that identifies you (a task name, a session id) —
it is what the other agent is told when it is refused.
The claim covers everything below path: '/project1/audio' includes
'/project1/audio/eq1' but not '/project1/audio2'. It lapses on its own
after ttl_seconds, so a crash cannot park a subtree for the session;
claim again to renew. This is an agreement between agents, not a lock —
it does not constrain a person editing those nodes by hand.
Write calls must carry the same owner to pass their own claim; the
refusal text says which owner to send.
Inputs: path (required), owner (required), ttl_seconds. Returns: result
td_docsA
Search or read TouchDesigner's documentation, mirrored offline.
Pass page to read one article in full (for example 'Write_a_GLSL_Material'
or 'Noise_TOP'); otherwise query searches all 2000-odd pages and returns
matching excerpts. Covers concepts and guides, not just operators.
Inputs: query (required), page, limit. Returns: result
td_doctorA
Check the whole chain — install, index, probe pass, bridge, this server.
Run this when something is wrong and it is not obvious which link broke, or before trusting a long build session. The trap it exists for is the one that raises nothing: an index built from a different TouchDesigner build still answers every question, with defaults and menu options that describe the other build, so an agent configures parameters that may not exist and the only symptom is a network that quietly does not work. It also separates 'not running' (a state) from 'registered but silent' and 'answering but refusing the token', which need different repairs. Each line names the command that fixes it.
Inputs: no named parameters. Returns: result
td_errorsA
Every operator at or under path currently reporting an error or warning.
Node errors are shown as colours in the TouchDesigner UI and are otherwise invisible to you; check this after building something.
The default is the project, not /, and asking for / is usually the
wrong move: the walk is breadth-first and bounded, and on an open session
TouchDesigner's own /ui and /sys are thousands of operators wide at
the shallow levels, so the budget runs out before the walk reaches
anything of yours. Point it at the component you built instead.
Inputs: path. Returns: result
td_exampleA
Show a working example network for an operator.
TouchDesigner ships an example .tox for most operators. This reads one offline and describes how it is wired and configured — a real usage reference rather than a parameter list.
Inputs: op_type (required), depth. Returns: result
td_execA
Run Python inside TouchDesigner and return its output.
The full td namespace is in scope (op, ops, root, project, ui, app,
families, operator type classes). A trailing expression, or a variable named
result, is returned. Reach for the structured tools first — this blocks
TouchDesigner's main thread while it runs.
A script that raises still returns what it printed before the error, and
result if it had been set, so a mistyped name on the last line does not
cost the measurements above it.
Inputs: code (required). Returns: result
td_expression_helpC
Look up TouchDesigner expression and command syntax.
Inputs: query (required), limit. Returns: result
td_extension_addA
Attach a Python class to a COMP as an extension, in one call.
Reach for this instead of td_exec whenever a component needs methods or
state of its own. Done by hand it is five steps — create the COMP, create
the DAT, write the text, set three parameters on the Extensions page,
re-initialise — and the last one fails silently: measured on 2025.32460, a
wrong Extension Object expression or a class that raises in __init__
leaves the COMP reporting no error, no warning, and extensionsReady True,
with the real message only in the textport. This tool reads the result back
off the COMP and hands you that message.
Aim it either at path (an existing COMP) or at parent plus name (a
baseCOMP to create) — not both. code must define class <class_name>,
conventionally taking ownerComp and capitalising anything meant to be
called from outside: with promote on, capitalised members are callable
straight on the COMP, and every member is reachable as
op(...).ext.<name>.<member> regardless.
The class name doubles as the name of the textDAT holding the code, which
is what the generated Extension Object expression points at
(op('./Name').module.Name(me)). extension_name renames the extension
for ext lookups without touching the class. index picks which
extension slot to write; the wiki says a COMP has four, the sequence took
six here. A created COMP is given a free spot in the parent network
unless position names one — [x, y] in network units, the left and
bottom edges of the tile; it is ignored when aiming at a COMP that
already exists.
The code is parsed on this host before anything is sent, so a typo costs
no round trip. That check is not a guarantee TouchDesigner accepts it:
this host's Python may be newer than TouchDesigner's embedded 3.11, so
3.12+ syntax passes here and fails there — which is caught, but only by
the read-back above. Pass the same owner you claimed the area with, or
your own claim refuses this write.
Inputs: code (required), class_name (required), name, path, +6 more. Returns: result
td_flagsA
Read the flags that decide whether a node runs and what is visible.
Run this when a network looks right and produces nothing. A bypassed operator, a COMP with its display or render flag off, and a COMP with cooking disabled are all invisible in a parameter dump and in td_network, and each of them makes a correct network output nothing — the kind of silent failure that costs an hour of re-reading parameters.
unavailable names the flags this operator genuinely does not have, so you
can tell "off" from "not a thing here". The clone master is a parameter
rather than a flag, so it is not listed; cloneImmune is the flag half.
Inputs: path (required). Returns: result
td_glossaryA
Look up TouchDesigner terminology.
185 glossary entries defining the vocabulary the rest of the docs assume: Cook, Time Slice, Par, CHOP, Clone, Tox, Perform Mode, Sample.
Inputs: term (required), limit. Returns: result
td_healthA
Find what is quietly broken — the failures nothing reports.
Run this after building anything, and whenever a composition "looks fine but does nothing". td_errors only covers what TouchDesigner calls an error; this additionally catches:
operators that never cook, because a branch nothing displays or records is never pulled and therefore is not running at all
output operators switched off (audio device, movie recorder, MIDI, OSC) which produce nothing and report nothing
GLSL operators whose shader failed to compile, quoting the compiler's own line: TouchDesigner only warns that an Info DAT would show the details
tracebacks raised inside callbacks and extensions (Execute DAT, Replicator, component callbacks), which are kept apart from the error list. A Script operator's onCook raising during a cook Python asked for is not covered — that traceback goes back to the caller instead
operators costing more than half a frame to cook, and the resulting frame rate collapse. A cook time is named by the frame it was measured on, so one left over from a cook long before this check is set apart as stale rather than blamed for the current frame rate
bypassed operators, and the current licence
feedback loops (Feedback TOP, and the CHOP and POP that hold state between frames), which cook(force=True) does not advance: frames made by forced cooks carry a stale trail
bypassed gain operators (Level, Math, HSV Adjust), which pass their input through at full strength instead of switching the layer off
Level TOPs that can output negative floats (float format, no clamp, and contrast above 1, inlow above 0 or outlow below 0 — black level only cuts to 0), and whether an Add below them takes those values away from what it adds to
reads of the application clock (absTime) or an unseeded random generator, which keep a render from reproducing between runs
interval is the gap between the two samples, in seconds, and is capped:
this process sleeps through it and answers nothing else meanwhile.
Inputs: path, interval. Returns: result
td_instancesA
Which TouchDesigner instances are running, and which one these tools reach.
Reach for this whenever the artist may have more than one project open —
and always before believing that an edit went where you meant. Every
other bridge tool here dials a single bridge chosen on this host (the
session file, or a --port/--project flag given to the td-atlas CLI);
with two TouchDesigners running, the one it picks may not be the one the
conversation is about, and nothing in a successful result would say so.
This lists all of them — project, port, build, pid and when each was last
seen — and marks the one the other tools are talking to. Aiming at a
different one is not possible from here (the CLI's --port/--project
have no MCP equivalent yet): name the port to the user and let them
decide, rather than assuming the edit landed where they meant.
Inputs: no named parameters. Returns: result
td_logA
Your own trail: every bridge call this host has made, and how it went.
Reach for this when something is wrong and you do not know what you did —
an operator is missing, a parameter is not what you set, the artist says
"it broke after you touched it". td_status shows only the last call and
the next one overwrites it; this is the whole session, and it survives
TouchDesigner being closed and reopened, so it also answers "what happened
yesterday".
Every call that changed the project is listed with what it changed:
tx = 0.5 and ty = expr ... under a td_set_params, each step of a
td_build, flags with the value they had before, and the first lines of
the code a td_exec ran. To put back what was set earlier, read it here
with method="par_set", "batch" or "exec" and a large limit,
rather than reconstructing it from a render. An old parameter value is
the earlier line that set it; the journal does not record one otherwise.
Also reach for it before repeating a call that failed. failures=True
gives the refusals alone, each with the text it refused with, and the
repair for the most recent one — repeating a call that a scope claim or a
missing path already refused will refuse again for the same reason.
summary=True answers a different question: over everything recorded,
which methods refuse and which are slow. Use it to notice a pattern you
are inside of — the same method failing five times means the approach is
wrong, not the call.
Not everything is here, and the gap matters: only calls that reached the bridge are recorded. The offline tools (td_project_read, td_docs, td_search_operators) never dial it and leave no trace, so an empty journal means no live work, not no work.
Inputs: limit, method, summary, failures. Returns: result
td_networkA
List the operators inside a component and how they are wired.
Inputs: path, depth. Returns: result
td_operator_schemaA
Every parameter of an operator: exact names, defaults, menu options, ranges.
Read this before creating or configuring an operator — it gives the names
TouchDesigner actually accepts. Note that TouchDesigner's own documentation
describes parameter groups (such as 't' for Translate) while the settable
parameters are the members ('tx', 'ty', 'tz'); this returns the members.
page filters to one parameter page.
Inputs: op_type (required), page, include_hidden. Returns: result
td_op_infoA
Inspect one operator in the running project: type, wiring, live parameter values.
Inputs: path (required). Returns: result
td_paletteA
Search the ready-made components TouchDesigner ships in its palette.
277 finished tools — projection mappers, corner-pinners, colour pickers, audio analysers, UI widgets. Check here before building something from scratch, then install the one you want with td_palette_load.
Inputs: limit, query, category. Returns: result
td_palette_loadA
Install one of TouchDesigner's palette components into the project.
Reach for this the moment td_palette shows a component that does what you
were about to build by hand — it is one call, where the alternative is
td_exec with a loadTox path you have to get exactly right, on a machine
whose TouchDesigner may not be installed where you assume.
name is the component name td_palette reports. The .tox path comes from
the index and is checked on disk before anything is sent, so a stale index
fails here rather than as a TouchDesigner traceback. Fourteen palette names
exist in two folders each (the Ableton set, operatorPath,
vrRenderToMovie): those are refused with the candidates listed until you
narrow them with category.
The node's final name is reported back rather than assumed: TouchDesigner
names a loaded component after its file, and numbers it (checker1,
checker2) when a sibling already holds that name. rename is stricter —
a name already taken is refused outright and the load is rolled back, so
read the path in the reply rather than assuming the name you asked for.
Loading is not free: measured 0.006 s for a 20-operator component and 1.08 s for kantanMapper's 4,079, all of it on TouchDesigner's main thread.
Inputs: name (required), owner, parent, rename, +2 more. Returns: result
td_project_diffA
Compare two .toe/.tox files and report what actually changed.
Reports added, removed, retyped, rewired and re-parameterised operators, plus a line diff of any changed DAT code. Nodes that were only dragged to a new position are counted separately so they cannot bury a real change.
To compare a live branch before and after some edits, pass two td_snapshot
files of the same COMP. A parameter line shows what drives the parameter:
its constant, or its expression or bind text, with no mark saying which.
A file keeps only parameters that are off their default, so -name (was X) normally means the parameter went back to its default, and +name
that it left it. To put a value back, read it from td_project_text of the
before file, which keeps the mode.
Inputs: after (required), before (required), show_moves, include_text. Returns: result
td_project_grepA
Search the Python and GLSL held inside a project's DATs.
Ordinary file search cannot reach this code: it lives inside the .toe
container, not on disk. pattern is a regular expression.
Inputs: file (required), pattern (required), limit. Returns: result
td_project_readA
Read a .toe or .tox from disk, without TouchDesigner running.
Returns the operator tree with wiring. path narrows to a subtree such as
'/project1', depth is how many levels of children to show, and params
adds the parameter values that differ from the defaults — which is all a
saved project records, so it is exactly what someone chose deliberately.
Inputs: file (required), path, depth, params. Returns: result
td_project_textA
Dump a whole .toe/.tox network as JSON, without TouchDesigner running.
Use this when td_project_read's tree is not enough — when the answer needs
every parameter, the wiring, the flags and the DAT code at once, for
instance before rewriting a component or explaining what an unfamiliar
project actually does.
DAT text arrives as an array of lines rather than one escaped string, so a
single changed line stays a single changed line; join the array with '
' to get the file back byte for byte. Standard JSON otherwise.
A network larger than `max_bytes` is refused rather than truncated: a cut
dump is not parseable JSON, and `path` narrows the dump to one component.
Inputs: file (required), path, max_bytes. Returns: result
td_project_writeA
Write an edited td_project_text dump back into a new .toe/.tox.
The return leg of td_project_text: edit the JSON, hand the whole document back here, and get a file TouchDesigner opens — with no instance running.
Three things to know before reaching for it, because each one is a silent wrong answer otherwise:
filemust still be the original the text came from. The dump covers five of the forty-odd kinds of file a .toe holds; panel layouts, replicator settings and custom parameter definitions live in the others and are copied across from the original. There is no path from text alone to a .toe.outputmust not exist. Repacking writes the file whole, and this tool will not overwrite anything of the user's. Write beside it and diff.Read the gaps in the reply. Anything the text asked for that could not be written — a new operator, a changed operator type, a custom parameter page — is listed rather than approximated, and the built file does not say what the text said.
Changing a parameter, its expression, a DAT's code, a table cell, the wiring, the flags, the placement or the colour all work, as does deleting an operator.
Inputs: file (required), text (required), output (required). Returns: result
td_python_apiA
Python members and methods available on a class, with inherited ones.
name is an operator type ('noiseTOP') or a class ('TOP', 'OP', 'Par',
'UI'). query filters the member list. Signatures and return types come
from the reference shipped with this TouchDesigner build.
Inputs: name (required), query. Returns: result
td_release_scopeA
Give a claimed subtree back before its claim expires.
Call it as soon as a run of edits is finished — otherwise the next agent waits out the whole time-to-live for nothing. Only the owner named on the claim can release it.
Inputs: path (required), owner (required). Returns: result
td_renderA
Render a TOP and return the image, so you can see what you built.
TouchDesigner is a visual tool: check your work with this rather than
inferring it from parameter values. height defaults to preserving the
TOP's aspect ratio; width=0 keeps the TOP's own resolution.
save_to writes the PNG to that path on this machine and answers in text
instead of returning the image — for comparing two states pixel by pixel,
or keeping a frame, without spending context on it. A file already at
that path is refused unless overwrite=True: it may be the artist's.
settle_frames waits that many of TouchDesigner's own frames before
rendering. A render right after td_set_params or td_build can return the
frame from before the edit; 2–3 frames is enough for a parameter change.
The answer says so if TouchDesigner stopped drawing during the wait.
Inputs: path (required), width, height, save_to, +2 more.
td_scopesA
Which subtrees other agents have claimed, and until when.
Check this before editing a project someone else may be in — it is the only way to see a claim before a write bounces off it, and it names the owner to coordinate with.
Inputs: no named parameters. Returns: result
td_search_operatorsA
Find TouchDesigner operators by what they do.
Searches names, labels, summaries and full documentation. Use this first,
in plain language ("blur an image", "read a MIDI device", "instance
geometry"). family optionally narrows to TOP, CHOP, SOP, DAT, MAT, COMP
or POP.
Inputs: query (required), limit, family. Returns: result
td_search_parametersA
Find which operators have a parameter matching a description.
Useful when you know the effect you want but not which operator provides it — "feedback amount", "sample rate", "instancing".
Inputs: query (required), limit. Returns: result
td_set_flagsA
Turn node flags on or off — bypass a node, hide it, stop it cooking.
The write half of td_flags, and the way to bypass an operator without
deleting it. flags is {"bypass": true} and the like.
Every write is read back before this reports success, because the failure
it exists to prevent is silence: TouchDesigner accepts pickable on COMPs
only and refuses allowCooking = false outside a COMP, and a flag that
exists but does nothing on this family would otherwise look like it landed.
A refusal names the flag and the family, and nothing is left half-set.
Pass the same owner you claimed the area with, or your own claim refuses
this write.
Inputs: path (required), flags (required), owner. Returns: result
td_set_paramsA
Set parameters on an existing operator, checked against the index first.
Values may be a constant, {"expr": "..."} for an expression, {"bind": "..."}
or {"pulse": true}. Names and '../' OP references are validated against
the index before anything is sent; without op_type the operator's type
is asked of the bridge first, in the same call that resolves the
references. Pass the same owner you claimed the area with, or your own
claim refuses this write.
Inputs: pars (required), path (required), owner, op_type. Returns: result
td_snapshotA
Save a component to a file so it can be diffed later.
This is how to keep "every parameter of this branch" before changing it,
instead of dumping them to text by hand. path is the COMP holding the
branch. Take one snapshot before a round of edits and another of the same
path after, under a different label, then pass both files to
td_project_diff. It lists each parameter that moved as name: before -> after, including expressions and custom parameters, and it lists wiring
and DAT code too. That is three calls. Snapshots go to
~/.td-atlas/snapshots, and a label used again replaces its file, so
reusing a label loses the state you meant to compare against.
The before snapshot is also the roll-back point. td_project_text on it gives each parameter in the form td_set_params takes, with {"expr": ...} where the diff shows only the expression's text. The diff does not mark which values are expressions, so put values back from the text, not from the diff. Paths in the file start at the COMP's own name, so a snapshot of /project1/branch holds /branch/blur1, which is /project1/branch/blur1 live. td_undo is shorter while the edits are still on the undo stack.
A component is written rather than the whole session because saving the session is a Save As: it repoints TouchDesigner at the snapshot file and leaves the artist working in ~/.td-atlas instead of their own project.
Inputs: path, label. Returns: result
td_statusA
Whether TouchDesigner is reachable, what project it has open, and whether its timeline is playing.
Read the timeline: line before trusting a live CHOP between two of your
own calls: (playing) means frames keep cooking in between. abs is
absTime.frame, not the project's frame: stepping the timeline does not
move it, and a paused root timeline stops it. A (!) on the range means
playback stops short of end — usually a range left over from a test, and
a recording stops there without an error.
Inputs: no named parameters. Returns: result
td_timeline_cancelA
Stop a td_timeline_run job now; the crop and the play mode go back.
Files already written stay. Without job, the latest one.
Inputs: job. Returns: result
td_timeline_profileA
What each operator costs per frame, on real timeline frames — as a job.
Reach for this when the frame rate drops and you need to know who spends
the frame. Do not time cook(force=True) in td_exec: a TOP's cook only
queues GPU work and returns, so a hand-written loop reads ~0 ms for a TOP
that costs 80 (it took an agent a whole wrong hypothesis to see it). And do
not trust td_health's cookTime alone: it is the last cook, which may be
hundreds of thousands of frames old.
frames is the walk, e.g. "3000..3009"; every frame of it is measured.
Every TOP/CHOP/SOP/POP at or under path (up to limit, breadth-first)
is forced to cook on each frame, upstream first, and timed with the GPU
waited for. Returns at once with a job id like td_timeline_run — they share
one slot, since both move the timeline — and td_timeline_status shows the
table so far: mean and max ms per frame, costliest first. A row marked
"did not cook on its own" is what the operator would cost, not part of the
frame; one marked as cooked inside an earlier measurement shares its cost
with that operator (a Render TOP pulling its geometry, typically).
The timeline is paused for the walk and its play mode given back; each
step forces the whole list, so a heavy network makes each step as long as
its frame. Every operator cooks once more per frame than it would, so a
Script operator or a network/file out runs its side effect again — profile
a branch without those, or accept it. Profile a component, not /.
Inputs: path (required), frames (required), limit, settle. Returns: result
td_timeline_runA
Walk the timeline frame by frame and save a TOP's frames — as a job.
Reach for this instead of a td_exec loop whenever frames depend on what came before them: live audio analysis, Feedback TOPs, trails, anything with history. It returns at once with a job id; poll td_timeline_status, stop with td_timeline_cancel. No request holds TouchDesigner for more than one step, so the 30 s limit on a call does not apply to the walk.
frames is the walk, e.g. "1..994". save picks the frames to write,
e.g. "92..217,459..541" (default: every frame walked), into output, a
template such as "/renders/f{frame:04d}.png". Without output nothing is
saved and the job only advances the timeline — the way to warm history up
to frame N before td_render, and then the timeline is held paused at N.
What it handles so you do not have to: it pauses the timeline and gives
the play mode back at the end (so live audio is repeatable); it walks
every frame consecutively, from the start of frames when from_start,
otherwise from the first frame to save; it waits settle application
frames between steps (2 was measured repeatable for live audio — do not go
lower with audio); and its steps cannot run twice.
tiles=2 renders past the licence's 1280 cap as 2x2 quarters, by cropping
the Render TOP(s) named in render (or path, if it is one). Put {tile}
in output: 0 top left, 1 top right, 2 bottom left, 3 bottom right. Each
quarter is a whole walk of its own, four times the time, because a
Feedback TOP only builds a quarter's history right under that quarter's
crop. Nothing resets a Feedback TOP between passes, so each quarter's
first frames carry the last one's tail — a decaying trail forgets it, an
accumulator does not. The crop goes back to 0..1 however the job ends.
Inputs: path (required), frames (required), hold, save, +5 more. Returns: result
td_timeline_statusA
Progress of a td_timeline_run job: frame, pass, files saved, errors.
For a td_timeline_profile job, the table measured so far.
Without job, the latest one, finished or not. A walk that has not taken
a step for several seconds is reported as stalled, with what to do.
Inputs: job. Returns: result
td_traceA
Why is this TOP black, or darker than its parameters say? Find the node.
Reach for it when td_render shows black, a washed-out or a dimmed image
and every parameter looks right. Starting at the TOP at path, it walks
up every wired input (breadth first, depth hops, at most 40 nodes),
reads each image's min / mean / max over R, G, B and the alpha mean, and
marks the node where the signal was lost, with the reason when the node's
own settings show it:
dropped here— the image goes black while an input still carried something (opacity 0, a bypassed source, an empty input, an error), or an Add / Compositeaddis fed a negative input and so subtracts itnegative values start here— a float image gone below zero, typically a Level TOP with contrast above 1, inlow above 0 or outlow below 0 and no clamp: invisible on its own tile, it darkens whatever it is added to. A black level above 0 cuts to 0, not below, and is named underdropped herealpha goes to 0 here— colour still there under an alpha of 0, which vanishes once compositedNaN/Inf start here— usually a shader dividing by zero
A ? on a mark means an input could not be read, and the loss may have
come from there. No cook is forced to take a reading, but reading an
image that is out of date makes TouchDesigner cook that node once, as any
read would (measured on a Noise TOP: each read after a seed change added
one cook). On a Feedback TOP that cook is a step of the loop. A node that
never cooked is not read and says so instead of reporting zeros, and so
does a non-TOP input, a node past the time or download budget, and an
image the read failed on.
Wires only: an image a Select TOP or a Render TOP reaches through a
parameter is not followed — trace from that operator next.
Inputs: path (required), depth. Returns: result
td_undoA
Undo (or redo) the last change, including whole td_build batches.
Inputs: redo. Returns: result
td_variant_diffA
Compare two saved variants of the same project.
The same semantic comparison td_project_diff runs, aimed at two saved states instead of two files: added, removed, retyped, rewired and re-parameterised operators, plus a line diff of changed DAT code. Nodes that only moved are counted separately so they cannot bury a real change.
Inputs: file (required), after (required), before (required), show_moves, +1 more. Returns: result
td_variant_listA
List saved variants — of one .toe/.tox, or of every project that has any.
Each line carries when it was saved, how large it is, and whether the original file has changed since. That last one is information rather than a warning: a restore reads the variant's own copy, so a changed original cannot affect it.
Inputs: file. Returns: result
td_variant_restoreA
Write a saved variant back out as a .toe/.tox file.
A byte copy of what was saved, not a repack: nothing is collapsed, so
TouchDesigner's toecollapse never runs and never moves a user's file aside
to a .bkp1 name. output must not exist — hand back a new path and compare with
td_project_diff rather than replacing anything in place. A directory as
output keeps the name the file had when it was saved.
Inputs: file (required), label (required), output (required). Returns: result
td_variant_saveA
Keep the current state of a .toe/.tox so it can be returned to and compared.
Take one before trying a direction, another after, and td_variant_diff says exactly what the direction changed. Nothing of the user's is touched: the variant is the network text plus a byte copy of the file, kept under ~/.td-atlas/variants and grouped by the project's path.
That copy is what makes a restore possible at all: the rebuild is a patcher, so the text alone cannot produce a .toe. It is also cheap — measured across the shipped palette, the copy adds a median 19% on top of the text and no measurable time.
label may hold letters, digits, dot, dash and underscore. A label
already in use is refused rather than overwritten. path narrows only the
stored text to a subtree; the copy is always the whole file.
Inputs: file (required), label (required), note, path. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 46 tools
Most tools have distinct purposes, but several overlapping pairs exist: td_health vs td_errors, td_project_read vs td_project_text, td_snapshot vs td_variant_save, and td_project_diff vs td_variant_diff all require careful reading to pick correctly. The long descriptions help, but the sheer number of near-neighbor inspection and versioning tools creates real misselection risk.
All tools share the td_ prefix, and families like timeline_run/status/cancel/profile and variant_save/list/restore/diff follow parallel patterns. However, naming mixes bare verbs (exec, render, undo, trace, build) with noun-style names (status, errors, log, scopes), and the order varies between verb_noun (set_flags) and noun_verb (project_read).
At 46 tools, this is well past the 25+ threshold for 'too many' and approaches extreme territory. Even though TouchDesigner is a broad domain, an agent will spend significant effort just selecting among this many options, and many tools are highly specialized sub-utilities that could be consolidated.
The tool surface is remarkably comprehensive: live state inspection, error checking, editing via batch, rendering, timeline jobs, offline project read/write, versioning, scopes, annotations, palette loading, and a doctor/diagnostics tool. Minor gaps exist (e.g., no direct single-op delete outside td_build, parameter reads only via td_op_info), but the full lifecycle of inspecting, editing, verifying, and documenting a project is covered.
Maintenance
Related MCP Connectors
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Connect AI assistants to your approved computer for files, commands, browser and desktop tasks.
214 tools for AI agents over one MCP endpoint: image, video, audio, 3D, data, storage, mail, GPUs.
- DNS-DATA RemoteDeprecatedcom.dns-data
Connect AI assistants to authorized Windows and macOS devices for files, commands, and management.
Related MCP Servers
- AlicenseBqualityAmaintenanceA Model Context Protocol server that enables AI agents to control and operate TouchDesigner projects through creation, modification, and querying of nodes and project structures.144,246 npm613MIT
- AlicenseBqualityCmaintenanceAn MCP server for TouchDesigner that lets AI agents inspect, build, wire, optimize, and stabilize live TD networks with 106 tools, plus a technique memory system for reusable patterns.10016MIT
- AlicenseNot gradedqualityDmaintenanceEnables natural language control of TouchDesigner via AI, allowing operator creation, parameter setting, Python execution, and node graph building.7MIT
- AlicenseAqualityDmaintenanceEnables LLMs to directly control, introspect, and build TouchDesigner networks in real-time through a Model Context Protocol server.25MIT