---
title: Tool API contract
description: The stable contract every tdmcp MCP tool follows — invariants every client can rely on as the project consolidates toward 1.0.
---

# Tool API contract

This page documents the invariants every tdmcp MCP tool follows from v0.9.0
onward and that will be **frozen at 1.0**. The full per-tool reference is the
generated [Tools reference](./tools); this page covers the rules behind it so
clients (Claude / Cursor / Codex / custom MCP clients) can rely on a stable
shape.

Changes that break any invariant below require a major version bump.

## 1. Naming

- Tool names are `snake_case`, registered via `server.registerTool(name, …)`
  inside the file's `registerX` function.
- A name shipped under a tagged release stays the same identity from 1.0
  forward. A renamed tool keeps an alias under the old name for at least one
  minor release before the alias is dropped.

## 2. Input schema

- Every tool defines a Zod schema and exposes it as
  `inputSchema: schema.shape`.
- Any field declared with `.default(...)` is **optional from the client's
  point of view** — the server fills the default before calling the
  implementation.
- Required fields stay required; making a required field optional is
  non-breaking, but the reverse (tightening) requires a major bump.

## 3. Error handling

- A handler **never throws**. Validation failures and TouchDesigner errors are
  serialized into `isError: true` results via the `errorResult` helper.
- TouchDesigner-side failures are normalized by `friendlyTdError` so the
  client sees a single readable shape regardless of which `TdError` subtype
  was raised by the bridge client.

## 4. Offline behavior

- When the TouchDesigner bridge is unreachable, a tool returns
  `isError: true` with a friendly message ("TouchDesigner bridge not running
  at…") instead of timing out silently or crashing the server.
- The MCP server itself stays up — every other tool, resource, and prompt
  remains callable while the bridge is offline.

## 5. Result shape

- `content[0].text` is a short human-readable description of what happened —
  safe to surface to an end user.
- `structuredContent` is the machine-readable payload. New keys are
  **additive**; existing keys keep their type and meaning across minor
  versions.
- A tool that returns no useful structured payload may omit
  `structuredContent`, but if it ever ships one it does not later remove it.

## 6. Deprecation policy

- A tool flagged for removal is first marked deprecated in the registry, kept
  registered as an alias, and stays callable for at least one minor release.
- The deprecation note documents the replacement tool (if any) so MCP clients
  can migrate without guessing.

## What this is **not**

- Not a per-tool spec — that's [Tools reference](./tools), regenerated from
  the live registry on every docs build.
- Not a promise that every internal helper is stable — only the registered
  tool surface is.
- Not a freeze on adding new tools. The contract governs **how** tools behave,
  not how many ship.
