Skip to content

The compatibility contract ​

Godot Editor MCP is built to be consumed by other software — an agent harness, an orchestrator, an eval runner, or your own client. The contract is the stable boundary between that software and this server.

It is one idea with two parts:

  1. The surface clients build against: tool names, parameters, result fields, the envelope, error codes, and safety semantics.
  2. A compatibility number for that surface: contract_version, with min_compatible_contract as the oldest client contract the server still serves.

“Contract tests” are the tests that pin the surface. contract_version is the counter for the guarantees those tests protect.

What the contract covers ​

SurfaceWhat is promised
ToolsExposed names, input parameter names/types/requiredness/defaults, and toolset categories
ResultsResult-model fields and their meaning, including honesty fields (persisted, undoable, aborted_at, rescan_pending, …)
ValuesJSON value shapes for Godot types (Vector2, Color, Rect2, NodePath, …)
Envelope{id, command, params} → {id, ok, result, error, hint, required}
ErrorsThe stable ErrorCode enum and the recovery contract (hint, required)
Safetyread_only / mutating / destructive / runtime, plus dry_run and confirm requirements
Discoverygodot_get_server_info fields clients use to negotiate and orient

What the contract does not cover ​

  • The CalVer build version. version (YYYY.MM.DD[.N], where .N is a same-day revision) moves on every release, including additive and internal changes.
  • The MCP protocol revision (2026-07-28) or the FastMCP version.
  • Server↔addon version matching. version_notice handles that separately; both halves should come from the same release.
  • Internal addon handler names (cmd_*). The server and addon ship together; clients do not negotiate against them.
  • Your game vocabulary. Tools and prompts that know about towers, waves, or enemies belong in a consumer project, not this contract.

Why it has its own version ​

version answers “which build is this?” It cannot answer “will my client still work?”, because most releases add tools and optional fields without breaking anything. Gating on CalVer would force every consumer to update on every release.

contract_version answers the compatibility question:

  • It is a monotonic integer, not a date.
  • It moves only when a client could break.
  • It lets a client fail fast at startup with a precise message instead of discovering the break mid-task.
  • It lets the server keep serving older clients through min_compatible_contract.

The two numbers ​

godot_get_server_info returns both, alongside the CalVer build:

jsonc
{
  "version": "…",                  // CalVer build — changes every release
  "contract_version": 1,           // newest contract this server serves
  "min_compatible_contract": 1     // oldest client contract still served
}

Current values are contract_version = 1 and min_compatible_contract = 1.

How negotiation works ​

A client carries the contract it was built against, K. The server advertises its newest contract, C, and its oldest compatible contract, M. The client is compatible when:

text
M  ≤  K  ≤  C
ConditionMeaningWhat to do
K < MThe client is too old — the server no longer serves that contract.Upgrade the client, or use a server release that still serves K.
M ≤ K ≤ CThe contracts overlap.Compatible.
K > CThe client is too new — it expects behavior this server does not have.Upgrade the server.

Inside the compatible range the additive guarantee applies: unknown fields are safe to ignore, and the tools, parameters, and result fields the client already uses keep working.

What bumps the contract ​

Breaking — bump CONTRACT_VERSION:

  • removing or renaming a tool
  • changing or removing a required parameter
  • changing a result-model field (name, type, or meaning)
  • changing the bridge-envelope shape
  • changing the meaning of an existing error code
  • changing a tool's safety class or its dry_run / confirm requirement

Additive — do not bump:

  • adding a tool, toolset, prompt, or resource
  • adding an optional parameter or result field
  • adding a new error code
  • documenting a new value shape without changing existing ones

When the floor moves — when the server stops serving an older client contract — update MIN_COMPATIBLE_CONTRACT as well. Both values live in mcp_server/__init__.py.

Check it at startup ​

A consumer that pins the contract should assert it once, before doing work:

python
info = await client.call_tool("godot_get_server_info", {})
compatible = (
    info["min_compatible_contract"]
    <= CLIENT_CONTRACT
    <= info["contract_version"]
)
if not compatible:
    raise RuntimeError(f"Godot Editor MCP contract mismatch: {info}")

That turns an incompatible server into one clear startup error instead of a sequence of mysterious tool failures.

Where it lives ​

ThingLocation
Version constantsmcp_server/__init__.py (CONTRACT_VERSION, MIN_COMPATIBLE_CONTRACT)
Runtime exposuregodot_get_server_info (contract_version, min_compatible_contract)
Authoritative per-tool specdocs/tool-contracts.md
Envelope rulesThe JSON envelope
Pinning teststests/contract/ — bridge envelope, output schema, diagnostics, capabilities
Consumer guidanceConsumer integration

194 tools · 29 categories · contract version 1