mcp server
cato
⚡ Claude Adaptive Token Optimizer — Zero-dependency, cache-preserving token optimization toolkit for Claude Code CLI and Desktop
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`)
{
"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)
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):
| Measure | Value |
|---|---|
| Total cost (API-equivalent) | $1,280 |
| Context re-reads (cache read) | 56% |
| 1-hour-TTL cache writes | 29% |
| Output | 14% |
| Uncached input | ~0% |
| Cost spent with context above 400k tokens | 60% |
| Cache rewrites after > 1h idle | 38x, $138 |
| Cache rewrites from switching models mid-session | 21x, $45 |
| Identical file re-reads | 49x, 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:
- 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.
- The cost is the context re-read every turn, plus cache rewrites when the TTL expires.
- Denying a read costs a turn (≈ context × cache-read price), so it only pays off with measured gains.
🏗️ How it works
| Layer | File | What it does |
|---|---|---|
| Real report | telemetry/usage_report.py, telemetry/pricing.py | Cost 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 guard | hooks/user_prompt_submit.py | Before 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 + CATO | hooks/pre_tool_use.py, hooks/post_tool_use.py | RTK 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 check | hooks/post_tool_use.py | After Edit/Write on .py/.json, reports a syntax error in the same turn. |
| MCP sandbox | hooks/post_tool_use.py, storage/db.py | Text MCP responses > 1,500 tokens go to SQLite FTS5 (BM25 search via cato_search_sandbox). |
| Post-compaction | hooks/session_lifecycle.py | Saves Git state before /compact and re-injects it afterwards. |
| Read guard (opt-in) | code_intel/dedup.py, code_intel/ast_skeleton.py | AST skeleton / Read dedup. Off by default; CATO_READ_GUARD=1 enables it. |
| Code map | code_intel/repomap.py, mcp_server/server.py | MCP 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 initon every machine, including after cloning this repository. The hooks in.claude/settings.jsonand the MCP server in.mcp.jsonpoint 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 runcato init.
💻 Commands
| Command | Description |
|---|---|
cato report [--days N] [--project P] [--json] | Real cost from Claude Code transcripts. |
cato stats | Real report (30 days) + interventions recorded by CATO. |
cato dashboard [--port 8765] | Web dashboard with the real cost (light/dark). |
cato statusline | For Claude Code's statusLine: current context, next-turn cost, minutes until the cache expires, today's cost. |
cato doctor | Audits 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-sandbox | Code navigation and sandbox search. |
Environment variables
| Variable | Default | Effect |
|---|---|---|
CATO_GUARD | on | 0 disables the cost guard. |
CATO_CONTEXT_WARN | 250000,400000,600000 | Context bands that trigger the warning. |
CATO_GUARD_BLOCK_USD | 1.00 | Minimum rewrite cost (USD) for the guard to hold a prompt. |
CATO_GUARD_BLOCK | on | 0 makes the guard warn only, never hold a prompt. |
CATO_BASH_COMPRESS | on | 0 disables Bash output compression. |
CATO_READ_GUARD | off | 1 enables the AST skeleton / Read dedup (install with cato init --read-guard). |
~/.cato/pricing.json | official table | Overrides 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).