touchdesigner-manual
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., "@touchdesigner-manualhow do I create a feedback loop in TOPs?"
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.
touchdesigner-wiki-rag
Search the entire TouchDesigner documentation from your AI agent — with real citations.
This tool builds a local search index over the official TouchDesigner wiki
(docs.derivative.ca, ~2,270 articles) and
exposes it to AI agents over MCP (Claude
Code, Claude Desktop, Cursor, and any other MCP client). Every answer carries
a Page § Section citation with a clickable URL, so you can verify what the
agent tells you instead of trusting a model's memory of TouchDesigner — which
is exactly how you end up with hallucinated parameter names.
You build the index yourself, on your machine, from the live wiki. This repo ships no documentation content — the docs belong to Derivative and are fetched by each user directly from docs.derivative.ca. The build takes ~45 minutes of unattended fetching (politely rate-limited) plus a few minutes of indexing, and can run entirely free with no API keys.
Why not just let the agent browse the wiki?
Three reasons this beats live browsing: hybrid retrieval (exact-term BM25 + semantic vectors, fused and reranked) finds sections a keyword search misses; the index knows TouchDesigner's operator-family trap — Noise TOP, Noise CHOP, Noise SOP, and Noise POP are four different operators, and results warn when same-named siblings exist in other families; and answers are grounded in retrieved text with citations rather than model memory.
Related MCP server: OmniDocs MCP
Requirements
Python 3.12+ and uv
~1.5 GB disk for the index
No API keys required for the default fully-local setup
Optional (better retrieval): an OpenAI key for stronger embeddings (about $1–2 one-time build cost) and HyDE query expansion; a Cohere key for stronger reranking (about $2 per 1,000 searches; free trial keys work)
Quickstart
git clone https://github.com/johnnyvincentvitale/touchdesigner-wiki-rag
cd touchdesigner-wiki-rag
uv sync
cp .env.example .env # optional: add API keys; works fine empty
uv run python fetch.py # ~45 min, fetches the wiki via its public API
uv run python ingest.py --rebuild # chunks + embeds + indexes
# try it from the terminal
uv run python query.py "how do I add noise to a texture"The embedding backend is chosen at build time — local
bge-base (free, no account)
by default, OpenAI text-embedding-3-large if OPENAI_API_KEY is set — and
stamped into the index so queries always use the matching model. See
.env.example for the details.
Already have the docs? Skip the fetch
TouchDesigner installs bundle an Offline Help mirror of the wiki. If you have it, import it instead of fetching (seconds instead of ~45 minutes):
# Windows (default install location):
uv run python fetch.py --offline-help "C:/Program Files/Derivative/TouchDesigner/Samples/Learn/OfflineHelp/https.docs.derivative.ca"
# then optionally pull only the pages edited since your mirror was generated:
uv run python fetch.py --update
uv run python ingest.py --rebuildNotes: the mirror snapshots the wiki at your TouchDesigner release date —
--update tops it up from the live API. Recent macOS builds ship the
Offline Help folder empty (a known TouchDesigner issue), so Mac users should
use the plain API fetch.
Configuration — what goes in .env
Nothing is required. With an empty (or absent) .env, everything runs on
free local models. Keys only upgrade individual stages:
Variable | What it enables | Without it |
|
| local bge embeddings; HyDE disabled |
| Cohere Rerank scoring | local ms-marco cross-encoder reranks |
| force | inferred: |
| different OpenAI embedding model (e.g. |
|
| different Cohere rerank model |
|
| different HyDE model |
|
| route OpenAI-client calls to any compatible server (see below) | api.openai.com |
Two behaviors worth knowing: the embedding backend is stamped into the
index at build time and queries auto-detect it, so you can't accidentally
query with the wrong model — but switching backends means rebuilding
(ingest.py --rebuild). And every API stage degrades visibly, never
silently: no Cohere key falls back to the local reranker, an unreachable
embedding API drops that search to keyword-only and says so in the response.
Going fully local (including HyDE)
The default keyless setup is already local except HyDE, which simply disables itself. To run HyDE on a local model, point the OpenAI client at any OpenAI-compatible server — Ollama or LM Studio:
# .env
OPENAI_API_KEY=anything-nonempty # satisfies the client; never sent anywhere real
OPENAI_BASE_URL=http://localhost:11434/v1
HYDE_MODEL=llama3.2 # any model you've pulled locally
EMBED_BACKEND=local # keeps embeddings on bge — required!EMBED_BACKEND=local is load-bearing here: without it, setting
OPENAI_API_KEY flips embeddings to the OpenAI backend, which would then be
aimed at your local server expecting a model it doesn't serve. A small local
HyDE model is rougher than gpt-4o-mini, but HyDE only fires on low-scoring
searches and only keeps its result when it scores better — so the downside is
bounded. (This recipe follows the OpenAI SDK's documented OPENAI_BASE_URL
behavior but hasn't been exercised against a live Ollama by the author —
issue reports welcome.)
"Local" models still download once from Hugging Face on first use (no account needed) and are cached after that; the wiki fetch itself needs the network once. After the index is built, the keyless setup searches fully offline.
Hook it up to your agent
Claude Code:
claude mcp add --scope user touchdesigner-manual -- uv run --directory /ABSOLUTE/PATH/TO/touchdesigner-wiki-rag python server.pyAny other MCP client — stdio server config:
{
"mcpServers": {
"touchdesigner-manual": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/TO/touchdesigner-wiki-rag", "python", "server.py"]
}
}
}What the agent gets
Tier | Tool | Returns |
L0 |
| section map — cheap orientation, discovers the wiki's own vocabulary |
L1 |
| reranked passages with |
L2 |
| full page as markdown |
Plus resources: manual://index (corpus stats and freshness) and
manual://operators/{family} (operator roster per family).
family accepts TOP, CHOP, SOP, DAT, MAT, COMP, or POP to scope a search to
one operator family.
How retrieval works
BM25 over SQLite FTS5, Porter-stemmed — exact operator and parameter names
Dense vector search over Chroma — paraphrased and conceptual questions
Reciprocal Rank Fusion combines both rankings
Rerank — Cohere Rerank if a key is configured, local ms-marco cross-encoder otherwise (automatic fallback, works offline)
Adaptive HyDE — if the top rerank score is low (a reliable "retrieval missed" signal), an LLM writes a hypothetical answer in the wiki's vocabulary and retrieval re-runs on that. Fires only when needed, only with an OpenAI key, and only keeps the result if it scores better.
Two guardrails ship in every response: a family warning when a result's operator has same-named siblings in other families, and a low-confidence warning when scores suggest retrieval missed — so an agent reports "not found" instead of inventing an answer, and never concludes a feature doesn't exist just because retrieval came back empty.
Keeping the index fresh
The wiki changes continuously. Responses warn when pages have been edited
since your index was built (checked against the wiki's recentchanges feed,
cached hourly, skipped silently when offline). To update:
uv run python fetch.py --update # re-fetches only pages edited since last fetch
uv run python ingest.py --rebuild # rebuilds the indexKnown issues
Every operator page carries an identical "Common Operator Info Channels" boilerplate section; those chunks can pollute results on hard queries.
The
--offline-helpimporter is tested against synthetic MediaWiki static pages, not yet against a real TouchDesigner install's mirror (the author's macOS build ships it empty). If the import misses pages on your install, please open an issue with a sample HTML file.Four title-variant pages (e.g.
Palette:webRTC ExtvsPalette:WebRTC Ext) collide in the page cache on case-insensitive filesystems; their partner pages are indexed, so coverage impact is negligible.Rerank/HyDE score thresholds were calibrated on a small held-out query set; they're adjustable in
retrieval.py(THRESHOLDS).ingest.pyis full-rebuild-only; with OpenAI embeddings that re-costs ~$1–2 per rebuild. The local backend rebuilds for free.
Content ownership
All documentation content belongs to Derivative. This repository contains no
wiki content — only code that fetches it from the public API into a private,
local index, the same way a browser or TouchDesigner's built-in help fetches
it. Please keep the polite rate limits in fetch.py intact.
License
MIT — see LICENSE. Applies to the code in this repository only, not to TouchDesigner or its documentation.
Available Tools
3 toolsbrowse_manualA
L0 - list page sections to orient before retrieving full passages.
Cheapest way to discover the wiki's own vocabulary — the best recovery move
when a search misses. Prefer this over search_manual when you need the
shape of a topic rather than a specific answer.
Args:
query: Optional keywords to filter section headings and page titles.
family: Optional operator family filter — TOP, CHOP, SOP, DAT, MAT, COMP, POP.
limit: Maximum sections to list.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | No | ||
| family | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively communicates that this is a cheap, non-destructive orientation tool ('Cheapest way', 'list sections'). It discloses what it filters by and discloses its return granularity (sections/headings, not full passages). The depth is good given zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, front-loaded with the core purpose, and every sentence earns its place. The strategy framing (cheapest, recovery move) and sibling comparison are woven into two tight lines, followed by a minimal Args block. Zero waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter browsing tool with an output schema present, the description is complete. It explains what it does, why to use it, when to prefer it over the key sibling, and clarifies all parameter semantics. The presence of an output schema relieves it from describing return values. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for all three parameters. It does: 'query' gets keyword-filter semantics (section headings and page titles), 'family' gets an operator-family filter with the enumerated options, and 'limit' gets maximum-section semantics. This fully compensates for the 0% coverage, though exact value formats aren't elaborated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb+resource ('list page sections') with a defined scope ('to orient before retrieving full passages'). It distinguishes itself from siblings by positioning it as a discovery/browsing tool versus search_manual. The 'L0' prefix and vocabulary-discovery framing make its purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly compares to search_manual ('Prefer this over search_manual when you need the shape of a topic rather than a specific answer'), giving a clear when-to-use directive. It also states the recovery use case ('best recovery move when a search misses'). It doesn't discuss when NOT to use it relative to read_page, but the when-to-use guidance relative to the key sibling is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_pageA
L2 - read the full markdown of one wiki page, or one of its sections.
Use after search_manual or browse_manual to get surrounding context.
Titles are exact wiki titles, e.g. "Noise TOP", "CHOP Execute DAT",
"noiseTOP Class".
Args:
title: Exact wiki page title.
section: Optional section heading to return just that section.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | ||
| section | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the L2 classification (suggesting a tiered access model), the exact-title matching behavior, and the section-scoping capability. It doesn't detail error behavior for nonexistent titles, but for a simple read with an output schema and no safety-critical behavior, this is largely sufficient. A 'read' operation's mutability is implicit in the name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: a one-line purpose, context positioning, title-format clarification with examples, and a compact args block. Zero waste, well front-loaded. The markdown structure mirrors the args list cleanly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read tool with an output schema, the description is nearly complete. It adds positioning among siblings, exact-title requirements, and section behavior. Minor gap: no statement about behavior when section doesn't exist or when title is invalid, and the L2 reference is unexplained, but overall the tool is adequately specified for selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and does. It explains that title must be an exact wiki title with concrete format examples, and explains section is optional and returns just that section. Both parameters get semantic context beyond bare names/null defaults. It doesn't specify section heading exactness rules, but the core semantics are well covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads the full markdown of one wiki page or one of its sections, using a specific verb ('read') with a clear resource ('wiki page'). It gives concrete example titles ('Noise TOP', 'CHOP Execute DAT') and explicitly distinguishes from sibling tools by referencing search_manual and browse_manual as preceding steps.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage guidance: 'Use after search_manual or browse_manual to get surrounding context.' It also establishes the exact-title matching requirement and gives examples of valid titles, which prevents common agent errors like fuzzy matching. No exclusions needed since the tool is a straightforward read.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_manualA
L1 - find passages answering a question, with wiki-URL citations.
Runs BM25 and dense retrieval, fuses with Reciprocal Rank Fusion, rescores
with a cross-encoder. If the top score signals a probable miss, a second
HyDE pass fires automatically. Handles exact operator/parameter names and
paraphrased questions alike.
Args:
query: What you need to know.
family: Optional operator family scope — TOP, CHOP, SOP, DAT, MAT, COMP, POP.
Use it when the question is about one family's operator; same-named
operators exist across families.
limit: Maximum passages to return.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| family | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it delivers: it discloses the multi-stage retrieval process, the automatic HyDE second pass when a miss is suspected, the citation output ('wiki-URL citations'), and that it handles both exact names and paraphrases. This is rich behavioral context well beyond what a schema would convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with a header line, retrieval-technique summary, and clear per-parameter annotations. Every sentence earns its place, technical detail is front-loaded, and the format is scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is complex (hybrid retrieval, fusion, rescoring, conditional HyDE), and the description covers this well. There is an output schema, so return-value explanation isn't required. The only slight gap is whether the 'L1' tag and end-user intent guidance could be clearer, but for a single-free-text-query retrieval tool this is quite complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for all three parameters. It does well: query ('What you need to know'), family (with concrete enum-like values and usage guidance), and limit ('Maximum passages to return'). Only minor gap is no detail on limit's default or range, but overall the description adds strong meaning absent from the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description is specific: 'find passages answering a question, with wiki-URL citations' plus a 'L1' label. It clearly identifies the resource (manual/search passages) and the action (retrieve answers). Though siblings include browse_manual and read_page, the search/retrieve semantics are distinguishable from browsing or reading.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains the retrieval pipeline (BM25, dense, RRF fusion, cross-encoder rescoring), notes the automated HyDE fallback on probable misses, and tells when to use the family parameter ('when the question is about one family's operator; same-named operators exist across families'). This gives a clear context and exclusions for parameter usage, though it doesn't explicitly name when NOT to use this vs siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
browse_manual - First observed
read_page - First observed
search_manual
TDQS
Scored across 3 tools
The three tools are mostly distinct: browse_manual for orientation/discovery, search_manual for finding passages, and read_page for reading full content. The browse_manual and search_manual could potentially overlap when searching for a specific topic (both filter by family and query), but the descriptions clearly differentiate them by cost tier and use case, so an agent can usually tell them apart.
The tool names follow a consistent verb_noun pattern (browse_manual, search_manual, read_page), all snake_case. Slight inconsistency in that browse_manual and search_manual both target 'manual' while read_page targets 'page', but the pattern is predictable and readable overall.
Three tools is a reasonable count for a documentation/manual retrieval server. It's on the lean side but each tool serves a distinct retrieval stage (discover, search, read). Given the narrow scope of a documentation lookup server, three well-chosen tools feel appropriate, though it borders on thin.
The core browse-search-read workflow is covered and represents the essential operations for a wiki documentation server. However, there are minor gaps: no way to list all pages in a family without a query, no direct tool for navigating to a specific page by title from scratch (read_page requires knowing the exact title), and no distinction between getting a section vs. full page could be improved. These are workable gaps but notable.
Maintenance
Related MCP Connectors
An MCP server that gives your AI access to the source code and docs of all public github repos
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
MCP server for agentverse documentation, generated by doc2mcp.
Related MCP Servers
- FlicenseBqualityCmaintenanceA MCP server that allows you to search and retrieve content on any wiki site using MediaWiki with LLMs 🤖. wikipedia.org, fandom.com, wiki.gg and more sites using Mediawiki are supported!227-
- FlicenseNot gradedqualityDmaintenanceAn intelligent MCP server that enables AI agents to crawl, index, and semantically search official framework documentation using local RAG. It prevents hallucinations by providing precise, up-to-date documentation excerpts directly into the AI's context window.1-
- AlicenseBqualityBmaintenanceAn 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.10014MIT
- AlicenseNot gradedqualityBmaintenanceA local-first MCP server for TouchDesigner that provides offline documentation retrieval and live control of TouchDesigner sessions, enabling AI-assisted network building and parameter management.MIT