Skip to content

MCP Server

v2.1.1Updated

The MCP Server LOP runs a Model Context Protocol server directly inside TouchDesigner. External AI coding tools such as Claude Code, Cursor, Windsurf, and other MCP-compatible clients can connect to it and call tools that you define in a Python DAT. This makes TouchDesigner a live, tool-capable backend that AI agents can interact with in real time.

🔧 GetTool Enabled 1 tool

This operator exposes 1 tool that allow Agent and Gemini Live LOPs to execute any tools defined in the user's MCP server code DAT, with schemas dynamically discovered at runtime.

When connected to an Agent LOP, the tools defined in the server code DAT are automatically discovered and exposed. The agent can call them just like any other LOP tool. Both synchronous and asynchronous tool functions are supported.

  • Streamable HTTP transport for direct connections from external MCP clients (no bridge proxy required)
  • User-defined tools via Python DAT — write standard FastMCP tool definitions and the server handles the rest
  • Auto port discovery — if the configured port is busy, the server automatically finds the next available one
  • Server health monitoring with the Ensure Running parameter, safe to call from a Timer CHOP for persistent uptime
  • Config presets — save and load different server configurations from MCP_Config, with built-in and custom presets
  • One-click client setup — copy MCP config JSON or a Claude Code CLI command directly to your clipboard
  • Python dependencies: FastMCP, Pydantic, and aiohttp. Pulse Install Dependencies on the Install / Debug page to install them into the LOPs shared virtual environment.
  • Windows: pywin32 is additionally required and installed automatically. If pywin32 registration fails, run TouchDesigner as Administrator and pulse Install Dependencies again.

None. The server operates independently. Tool definitions come from the Server Code DAT referenced on the MCP Server page.

One output. When connected to an Agent LOP, the agent discovers tools from this server via GetTool() and can execute them through the internal LOPs tool system.

The MCP Server loads a Python DAT containing standard FastMCP tool definitions. When you start the server, it:

  1. Checks that all dependencies are installed
  2. Loads the server code from the referenced DAT
  3. Finds an available port (auto-incrementing if the configured port is busy)
  4. Launches an HTTP server on the chosen host and port
  5. Pre-warms the tool cache so tools are immediately available to both external MCP clients and connected LOPs agents

External clients connect to http://<host>:<port>/mcp using the Streamable HTTP transport. The server handles the full MCP JSON-RPC protocol including initialize, tools/list, and tools/call.

  1. On the Install / Debug page, pulse Install Dependencies if this is your first time using the operator. Wait for the status to confirm all dependencies are installed.
  2. On the MCP Server page, confirm the Server Code DAT points to a DAT containing your FastMCP tool definitions.
  3. Set Transport to streamable-http and choose a Port (default is 18555).
  4. Pulse Start Server. The Running indicator will turn on and the Status field will show the server address.
  1. With the server running, pulse Copy Claude Code Config on the MCP Server page.
  2. Open a terminal where Claude Code is installed and paste the copied command. It will look like:
    claude mcp add --transport http mcp_server1_TD http://127.0.0.1:18555/mcp
  3. Claude Code can now call any tools defined in your server code DAT.
  1. Pulse Copy MCP Config to copy the JSON configuration block to your clipboard.
  2. Paste the block into your MCP client’s configuration file (e.g., Cursor’s mcp.json, Windsurf’s settings, or any Streamable HTTP-compatible client).

The server code DAT should contain a standard FastMCP server definition with a mcp instance. For example:

import fastmcp
mcp = fastmcp.FastMCP(name="My TD Server")
@mcp.tool()
def get_scene_info() -> str:
"""Get information about the current TouchDesigner project."""
return f"Project: {project.name}, FPS: {project.cookRate}"
@mcp.tool()
def set_background_color(r: float, g: float, b: float) -> str:
"""Set the background TOP color."""
bg = op('/project1/bg_top')
bg.par.colorr = r
bg.par.colorg = g
bg.par.colorb = b
return f"Background set to ({r}, {g}, {b})"

The DAT has access to TouchDesigner globals (op, me, parent, project), so your tools can read and modify anything in the project.

  1. On the Config page, select a server from the Current Server menu (options include Basic, Glsl Tool, Any Script Op, and any custom servers you have saved).
  2. Pulse Load Server. The server code DAT will be populated with the preset’s code.
  3. If Auto Start on Load is enabled, the server will start automatically after loading.
  1. Write your tool definitions in the server code DAT.
  2. On the Config page, type a name into Current Server (it is a string menu, so you can type freely).
  3. Pulse Save Server. Your configuration is saved to MCP_Config and will appear in the menu for future use.

To keep the server running reliably across long sessions:

  1. On the Config page, enable Start on File Load so the server starts automatically when the .toe opens.
  2. Connect a Timer CHOP to periodically pulse the Ensure Running parameter on the Server page. This will start the server if it is not running, or restart it if a health check fails.

When the MCP Server output is wired into an Agent LOP’s tool input, the agent gains access to all tools defined in the server code. The tools appear alongside any other connected LOP tools. This is useful for giving an internal LOPs agent the same capabilities that external coding assistants have.

Pulse Check Dependencies on the Install / Debug page to see which packages are missing. Then pulse Install Dependencies again. If pywin32 fails on Windows, close TouchDesigner, reopen it as Administrator, and retry.

The server automatically tries the next 10 ports if the configured one is busy. If all are taken, check for other processes using those ports and free one, or change the Port parameter to a different range.

Server starts but external client cannot connect

Section titled “Server starts but external client cannot connect”

Verify the Host is set to 0.0.0.0 (accepts connections from any interface) rather than 127.0.0.1 (localhost only) if connecting from another machine. Check that your firewall allows inbound connections on the configured port.

The server requires FastMCP, Pydantic, and aiohttp to be installed in the LOPs shared virtual environment. Go to Install / Debug and pulse Install Dependencies. The button will be disabled once all dependencies are satisfied.

Server code DAT missing ‘mcp’ instance

Section titled “Server code DAT missing ‘mcp’ instance”

The server code must define a variable named mcp that is a fastmcp.FastMCP instance. If this variable is missing or named differently, the module loader will fail with an error in the logger.

Confirm the server is running and that the MCP Server output is wired to the Agent LOP. Tools are discovered dynamically from the server’s tool cache. If the server was restarted, the tool cache is re-warmed automatically on startup.

Status (Status) op('mcp_server').par.Status Str
Default:
"" (Empty String)
Start Server (Startserver) op('mcp_server').par.Startserver Pulse
Default:
False
Stop Server (Stopserver) op('mcp_server').par.Stopserver Pulse
Default:
False
Restart Server (Restartserver) op('mcp_server').par.Restartserver Pulse
Default:
False
Running (Running) op('mcp_server').par.Running Toggle
Default:
False
Transport (Transport) op('mcp_server').par.Transport Menu
Default:
streamable-http
Options:
stdio, streamable-http
Host (Host) op('mcp_server').par.Host Str
Default:
0.0.0.0
Port (Port) op('mcp_server').par.Port Int
Default:
18555
Range:
0 to 1
Slider Range:
0 to 1
Server Code DAT (Serverdat) op('mcp_server').par.Serverdat DAT
Default:
./server_code
Edit (open external) (Editserverdat) op('mcp_server').par.Editserverdat Pulse
Default:
False
View (View) op('mcp_server').par.View Menu
Default:
docked
Options:
server_dat, logger, docked
Copy MCP Config (Copyconfig) op('mcp_server').par.Copyconfig Pulse
Default:
False
Copy Claude Code Config (Copyclaudecodeconfig) op('mcp_server').par.Copyclaudecodeconfig Pulse
Default:
False
Current Server (Currentserver) op('mcp_server').par.Currentserver StrMenu
Default:
Basic
Menu Options:
  • Basic (Basic)
  • Glsl Tool (Glsl Tool)
  • Any Script Op (Any Script Op)
  • python_server (python_server)
Load Server (Loadserver) op('mcp_server').par.Loadserver Pulse
Default:
False
Auto Start on Load (Autostart) op('mcp_server').par.Autostart Toggle
Default:
True
Save Server (Saveserver) op('mcp_server').par.Saveserver Pulse
Default:
False
Server Name (Optional) (Servername) op('mcp_server').par.Servername Str

Optional custom name for config. If empty, uses operator name.

Default:
"" (Empty String)
Start on File Load (Startonload) op('mcp_server').par.Startonload Toggle

Automatically start server when .toe file is loaded

Default:
False
Status (Status2) op('mcp_server').par.Status2 Str
Default:
"" (Empty String)
Install Dependencies (Installdeps) op('mcp_server').par.Installdeps Pulse
Default:
False
Check Dependencies (Checkdeps) op('mcp_server').par.Checkdeps Pulse
Default:
False
Ensure Running (Ensurerunning) op('mcp_server').par.Ensurerunning Pulse

Start server if not running, health-check if running. Safe to call from Timer CHOP.

Default:
False
v2.1.12026-03-16
  • fix depdency check and pywin32 check
v2.1.02026-03-16

Initial release

v2.0.32026-03-16
  • switch clipboard config to native HTTP transport (drop npx mcp-remote bridge) - update CLI copy command to use --transport http - add resources/list handler returning empty list - update MCP protocol version to 2025-11-25 - pin pydantic to ==2.11.7 for FastMCP compatibility
  • Add Startonload toggle for auto-start on .toe file load - Add Ensurerunning pulse with healthcheck (task/adapter/TDAsyncIO validation) - Fix IsRunning.val bug — was comparing dependency object as bool - Add pydantic dependency requirement for FastMCP - Enable pywin32/pywintypes check on Windows - Add GetTool warning when server not running - Track was_running in storage for state persistence
  • Add professional README with accurate description
  • Initial commit
v2.0.22025-12-16
  • Fixed MCP protocol compatibility issue with annotations: null in tool call responses
  • The MCP spec requires annotations to be an object or omitted entirely; null is invalid
  • Tool call responses now strip out null annotation fields before returning to clients
  • Resolves schema validation errors with mcp-remote and Claude Code clients
v2.0.12025-09-24
  • Fixed Gemini API compatibility by removing unsupported schema fields
  • Added tool schema cleaning for additionalProperties error
v2.0.02025-08-18

Major Features

  • MCP Config Integration: Added centralized server configuration system with MCP_Config operator
  • Load/Save Server UI: New Current Server dropdown, Load Server, and Save Server parameters for easy server management
  • Auto-Start on Load: Intelligent server startup when loading new configurations (configurable)
  • Connection Settings Management: Transport, host, and port settings now saved/loaded with server configs
  • Built-in Server Protection: Prevents saving built-in servers to disk - they stay in TouchDesigner only

Server Management

  • Smart Server Switching: Always stops current server when loading different server, prevents duplicate loads
  • Port Conflict Detection: Warns users when configured ports are unavailable, falls back to stdio transport
  • Docked Operator Management: Configurable removal of docked operators when loading servers (remove_docked setting)
  • Server ID Normalization: User-friendly names automatically converted to valid server IDs

Built-in Server Enhancements

  • Dynamic Config Tables: Auto-creates config/system_prompt DATs for new built-in servers
  • Default Port Assignment: Built-in servers get appropriate default ports (18760 for GLSL, 18792 for Script Op)
  • Basic Server Info DAT: Added helpful README DAT to basic server explaining usage and next steps

User Experience

  • Improved Error Messages: Clear warnings for built-in server save attempts, port conflicts, and duplicate loads
  • Delayed Port Warnings: 60-frame delayed warnings for port conflicts to ensure visibility
  • Connection Setting Validation: Automatic port availability checking with user guidance
  • File-First Architecture: Clean separation between built-in (TouchDesigner) and user (disk) servers
v1.1.12025-08-02

Critical Bug Fixes

  • Fixed "No module named 'td_mcp_adapter'" error: Moved DAT module import from async context to main thread where it has proper execution context to find sibling DATs
  • Fixed dependency detection issues: Replaced unreliable __import__() checks with importlib.metadata.version() for pip packages, ensuring consistent detection across different Python environments
  • Fixed sys.path conflicts: Implemented surgical venv path insertion that places LOPs venv before TouchDesigner's site-packages while respecting TD's core library paths, preventing conflicts with other Python environments (e.g., miniconda)

Technical Improvements

  • Removed stale global import: Eliminated module-load-time ADAPTER_AVAILABLE flag that could become stale after dependency installation
  • Enhanced dependency checking: Added _is_adapter_available() method with explicit, self-contained dependency validation
  • Improved error handling: Better logging and error messages for dependency and import failures
  • Safer path management: Replaced aggressive index=0 path insertion with intelligent placement before TD's site-packages

User Experience

  • Eliminated need for TouchDesigner restarts: Dependency installation now works without requiring project reload
  • Better cross-platform compatibility: Resolved Windows-specific import issues while maintaining macOS/Linux compatibility
  • Fixed Windows dependency management: Restored pywin32 installation requirement while keeping reliable detection methods to prevent false positives
v1.1.02025-06-30
  • GetTool Integration: The server now fully implements the GetTool method, allowing it to automatically discover and expose its user-defined tools to the TouchDesigner agent ecosystem (AgentEXT, geminilive, etc.). This enables seamless, zero-configuration tool usage by AI agents.
  • added a new parameter Editserverdat to open the linked server dat file in the editor.

## Fixes

  • Asynchronous Tool Discovery: Resolved a critical race condition where tools were not discoverable at startup. The server now pre-caches its tools, ensuring they are always available for synchronous inspection by agent systems.
  • API Compliance: Corrected the tool schema to be fully compliant with OpenAI, Google, and litellm standards, fixing a series of KeyError and BadRequestError exceptions.
  • Robust Tool Execution: The tool execution handler is now capable of calling both synchronous (def) and asynchronous (async def) tool functions, preventing await expression errors.