Skip to content
Conduit

mcp server

cato

⚡ Claude Adaptive Token Optimizer — Zero-dependency, cache-preserving token optimization toolkit for Claude Code CLI and Desktop

marcusaguiarmaciel-cmd/catocommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "cato": {
      "command": "uvx",
      "args": [
        "cato-claude"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 28, 2026

⚡ CATO (Claude Adaptive Token Optimizer)

License: MIT Python: 3.10+ Zero Dependencies Tests Passing PRs Welcome

🇧🇷 Versão em Português disponível aqui

CATO lowers Claude Code cost by targeting what real billing data shows actually drives it — context size × number of turns and prompt-cache misses — and it reports measured cost, computed from the billed usage fields in Claude Code's session transcripts and the official price table. Works alongside RTK. Zero dependencies.


📊 What the real data shows

cato report over 30 real transcripts (8,300 API calls, Opus 5.5 as the main model):

MeasureValue
Total cost (API-equivalent)$1,280
Context re-reads (cache read)56%
1-hour-TTL cache writes29%
Output14%
Uncached input~0%
Cost spent with context above 400k tokens60%
Cache rewrites after > 1h idle38x, $138
Cache rewrites from switching models mid-session21x, $45
Identical file re-reads49x, only 1,744 tokens (Claude Code already dedups)
Savings claimed by RTK (rtk gain)277k tokens — under 0.01% of re-read tokens

What follows from it:

  1. Compressing individual tool outputs barely moves the bill. Two controlled RTK studies (JetBrains, 425 pairs; Quesma, 1,740 attempts) found no net billed saving (−5% to +7.6%): compression can cause extra turns, and the baseline ignores Claude Code's own output truncation.
  2. The cost is the context re-read every turn, plus cache rewrites when the TTL expires.
  3. Denying a read costs a turn (≈ context × cache-read price), so it only pays off with measured gains.

🏗️ How it works

LayerFileWhat it does
Real reporttelemetry/usage_report.py, telemetry/pricing.pyCost by category and context-size band, cache misses by cause (idle past TTL, model switch, compaction), tokens per tool (images by real dimensions), noisiest shell commands, per-day RTK/CATO attribution. Dedups by message.id and tool_use_id.
Cost guardhooks/user_prompt_submit.pyBefore a prompt reaches the API. Cache expired with a large context: if rewriting it costs at least CATO_GUARD_BLOCK_USD ($1.00), it holds the prompt once with the cost and the options (/clear, /compact); resending goes through. Context past 250k/400k/600k: a warning only, the prompt goes through. Right after /compact it waits for the next real call. /commands are never touched.
Bash: RTK + CATOhooks/pre_tool_use.py, hooks/post_tool_use.pyRTK rewrites commands (if RTK's global hook isn't installed, CATO delegates to it — only for commands your permission rules already allow). CATO compresses the real output in PostToolUse (updatedToolOutput) only for tests, linters, installs, builds and container logs, registered with hook if filters so Python never starts for any other command. Any other output is data and is never altered; only exact repeated lines collapse. Raw log in ~/.cato/logs/.
Syntax checkhooks/post_tool_use.pyAfter Edit/Write on .py/.json, reports a syntax error in the same turn.
MCP sandboxhooks/post_tool_use.py, storage/db.pyText MCP responses > 1,500 tokens go to SQLite FTS5 (BM25 search via cato_search_sandbox).
Post-compactionhooks/session_lifecycle.pySaves Git state before /compact and re-injects it afterwards.
Read guard (opt-in)code_intel/dedup.py, code_intel/ast_skeleton.pyAST skeleton / Read dedup. Off by default; CATO_READ_GUARD=1 enables it.
Code mapcode_intel/repomap.py, mcp_server/server.pyMCP server with cato_repo_map (PageRank) and cato_read_symbol.

🚀 Installation

pip install git+https://github.com/marcusaguiarmaciel-cmd/cato.git
cato init --global      # or `cato init` inside a project
cato doctor

[!IMPORTANT] Run cato init on every machine, including after cloning this repository. The hooks in .claude/settings.json and the MCP server in .mcp.json point to the absolute paths of your Python interpreter and CATO install, so these files are generated per machine and are intentionally not committed (they are listed in .gitignore). A fresh clone has no CATO hooks until you run cato init.


💻 Commands

CommandDescription
cato report [--days N] [--project P] [--json]Real cost from Claude Code transcripts.
cato statsReal report (30 days) + interventions recorded by CATO.
cato dashboard [--port 8765]Web dashboard with the real cost (light/dark).
cato statuslineFor Claude Code's statusLine: current context, next-turn cost, minutes until the cache expires, today's cost.
cato doctorAudits configuration and gives recommendations from your real usage.
cato init [--global]Installs hooks, rules, subagent and MCP server without overwriting your settings.
cato exec <cmd>Runs a command and compresses its output (manual use).
cato repomap / cato symbol / cato skeleton / cato search-sandboxCode navigation and sandbox search.

Environment variables

VariableDefaultEffect
CATO_GUARDon0 disables the cost guard.
CATO_CONTEXT_WARN250000,400000,600000Context bands that trigger the warning.
CATO_GUARD_BLOCK_USD1.00Minimum rewrite cost (USD) for the guard to hold a prompt.
CATO_GUARD_BLOCKon0 makes the guard warn only, never hold a prompt.
CATO_BASH_COMPRESSon0 disables Bash output compression.
CATO_READ_GUARDoff1 enables the AST skeleton / Read dedup (install with cato init --read-guard).
~/.cato/pricing.jsonofficial tableOverrides per-model prices.

🧠 Prompt caching

CATO only changes new tool results (the conversation suffix), never history, the system prompt or the tool list — so the cached prefix stays valid.


🧪 Tests

python -m unittest discover -s tests -v

The 17 tests use synthetic transcripts and a temporary CATO_HOME; they never touch ~/.cato or your transcripts.


🤝 Contributing

See the Contributing Guide and Code of Conduct.

📄 License

MIT — see LICENSE. Created by Marcus Maciel (2026).

↑↓ navigate openesc close