tla-mcp

A TLA+ model checker as a Model Context Protocol server.

Plug a working model checker into Claude Code, Cursor, or any MCP-aware client. Validate specs, replay counterexamples, and catch invariant violations without leaving the conversation.

crates.io npm latest release license

What is this?

TLA+ is a specification language for designing and verifying concurrent and distributed systems. You describe what your protocol should do; a model checker tries every reachable state and tells you when something goes wrong.

The Model Context Protocol (MCP) is how agentic clients like Claude Code call external tools.

tla-mcp bridges the two. It's a stdio MCP server built on top of tla-rs, a fast TLA+ model checker written in Rust. Once registered, your client can parse a spec, list its invariants, run a full check with a budgeted time limit, and replay specific scenarios — all from inside the chat.

Install

Pick whichever fits your toolchain. All paths install the same v0.4.3 binary.

Homebrew (macOS, Linuxbrew)

brew install fabracht/tla/tla-mcp

Installs both tla (model checker CLI) and tla-mcp (MCP server).

Install script (Linux, macOS)

curl -fsSL https://raw.githubusercontent.com/fabracht/tla-rs/main/scripts/install.sh | bash

SHA256-verified binary download. Pass --bin tla-mcp to install just the server.

Cargo (any platform with a Rust toolchain)

cargo install tla-checker --bin tla-mcp

Pre-built release binaries

Linux x86_64, macOS x86_64, macOS arm64, Windows x86_64 are attached to every GitHub release as tla-<platform> and tla-mcp-<platform>, alongside a SHA256SUMS file.

Register with your client

Add to your MCP client config (Claude Code example, ~/.claude/mcp.json):

{
  "mcpServers": {
    "tla": {
      "command": "tla-mcp"
    }
  }
}

Restart the client. The four tools become available immediately.

What the agent gets

Four tools, versioned JSON schemas (schema_version: "1"):

toolpurpose
validate_spec Parse a .tla file. Returns vars, constants with resolved values, detected invariants, has_init / has_next, plus structured parse errors with source spans.
list_invariants Return invariant names matching Inv*, TypeOK*, NotSolved*, plus anything declared via cfg INVARIANT directive.
check_spec Full model checking with required max_states / max_depth / max_seconds budgets. Returns ok, invariant_violation (with trace + actions), deadlock, liveness_violation (prefix + cycle), limit_reached, or structured error.
replay_scenario Step through a spec along a guided path (step: <TLA+ expr> lines). Returns per-step state snapshots + variable changes, or a failure with available_actions on a mismatch.

Why TLA+ for an agent?

Most "is this code correct?" questions an agent answers are really questions about reachable behavior — a race condition that fires in one specific interleaving, a queue that grows unboundedly under a corner-case workload, a consensus rule that lets two leaders coexist for one tick. Reasoning about all these by reading code is hard. Asking a model checker is straightforward, when the model checker is one tool call away.

tla-mcp is opinionated about how an agent should use it. Tool descriptions explicitly tell the agent: budget all three limits upfront; inspect constants before running; treat limit_reached as inconclusive, not as a pass; bugs are usually in the last transition of the trace. These are not soft hints — they're encoded in the tool metadata so they survive context truncation.