Sophon
Honest token economics for MCP agents. One Rust binary. Zero ML. Reproducible benchmarks.
Sophon is a deterministic context layer for agents speaking the Model
Context Protocol. It compresses prompts, conversation memory, code
digests, file deltas, and shell output — without an embedding model,
without an LLM in the compression path, without a GPU, and without
API keys. 7.2 MB default Rust binary (25 MB with the optional
11-language tree-sitter AST backend), MCP-native, cl100k_base-accurate.
Every number below links to the reproducible benchmark script that produced it. Every caveat is in BENCHMARK.md — the source of truth for everything Sophon claims.
The three pillars
1. Measured economies, not promised ones
- 67.0 % of session tokens saved across a real 4-call workflow (BENCHMARK.md § 1.7)
- 64.5 % ± 0.5 % of cross-model tokens saved — stable across Claude Haiku / Sonnet / Opus and Codex low / medium / high (BENCHMARK.md § 2.1)
- 47.6 % saved on repeated boilerplate via fragment caching, even on the first call (BENCHMARK.md § 1.6)
- 99.55 % wire savings via
read_file_deltawhen the client already has the right hash (BENCHMARK.md § 1.5) - ~6 ms compression overhead per call — in-process, no GPU, no LLM
2. On-par with the best libraries, at a fraction of the cost
- vs LLMLingua-2 (Microsoft, EMNLP 2024) on the same 4 structured prompts: Sophon saves 77.3 % in 63 ms, LLMLingua-2 saves 68.4 % in 2 176 ms — ~10 points more saved and ~35× faster (BENCHMARK.md § 7.8.d)
- vs mem0-lite on LOCOMO (same 15 items, same judge, same rubric): Sophon 60.0 % accuracy ≈ mem0-lite 60.0 % — tie on accuracy, Sophon runs sub-second vs 8.7 minutes and zero LLM calls vs ~330 (BENCHMARK.md § 7.8.e)
- LOCOMO semantic retriever gain: enabling the opt-in retriever adds +13 accuracy points over compression alone on open-ended questions at N=60 (BENCHMARK.md § 3.7)
Every head-to-head above runs on the same machine, same tokenizer
(tiktoken cl100k_base), same LLM judge, and same inputs. The
benchmark scripts and raw JSON referenced throughout are bundled
with BENCHMARK.md — each § explicitly lists the
runner script and the output file it produced.
3. Honest about what it isn't
Sophon is not state-of-the-art on any single axis. We publish our losses as loudly as our wins:
- Plain-text semantic compression — LLMLingua-2 is the honest
choice when you need to preserve every bit of meaning in an
unstructured document. Sophon's
compress_promptshines on structured prompts with a query, not on arbitrary prose. (BENCHMARK.md § 7.8.d) - Learned semantic retrieval — Sophon ships a deterministic
HashEmbedder. For anything resembling MTEB-grade retrieval you wantfastembed-rs+ BGE-small or a proper vector DB. TheBertEmbedderslot exists in the code but is explicitly a stub. (BENCHMARK.md § 6.6) - Code navigation maturity — Aider's repomap
pioneered the tree-sitter + PageRank approach Sophon uses and
remains more mature, covering more languages in production
integration. Sophon's
navigate_codebaseis a faithful Rust re-implementation, not a reinvention. (BENCHMARK.md § 7.6) - Public corrections — BENCHMARK.md § 3.7 documents the jump from an optimistic N=30 headline (+23 pts) to the honest N=60 number (+13 pts) after we caught the sample bias ourselves. The git log shows the correction was pushed publicly.
If any benchmark here looks too clean, open an issue — we've already caught and published one regression on ourselves.
What's in the binary
Single Rust binary (7.2 MB default, 25 MB with tree-sitter), MCP stdio server, JSON-RPC 2024-11-05, eleven tools:
| Tool | What it compresses / why |
|---|---|
compress_prompt | Structured system prompt → query-relevant sections only. Topic-routed section picker, not a learned compressor. |
compress_history | Long conversation → summary + keyword index + verbatim recent window. Optional query param activates the semantic retriever (see SOPHON_RETRIEVER_PATH) for the LOCOMO retrieval gain in § 3.7. |
compress_output | stdout/stderr of git / cargo test / pytest / vitest / jest / go test / ls / grep / find / docker ps / docker logs → errors + modified files + test failures only. 14 command-aware filters + generic fallback, deterministic. |
navigate_codebase | Repository → token-budgeted map via symbol extraction + reference graph + personalised PageRank. Git-aware (honours .gitignore), incremental (mtime-diff cache), parallelised via rayon. 11 AST-backed languages with --features tree-sitter (Rust, Python, JS, TS, TSX, Go, Ruby, Java, C/C++, PHP, Kotlin, Swift) + regex fallback for every file. |
update_memory | Stateful session memory. Append + snapshot without re-sending full history. Opt-in JSONL persistence via SOPHON_MEMORY_PATH. |
read_file_delta | ETag-like resume. Returns Unchanged/Delta/Full based on the client's known hash — no bytes on the wire when nothing changed. |
write_file_delta | Atomic staged write with hash-versioned state. |
encode_fragments / decode_fragments | Repeated multi-paragraph block detection + substitution. Adaptive sliding window. |
count_tokens | Ground-truth cl100k_base token count. |
get_token_stats | Per-module cumulative savings across the session. |
Everything is deterministic. No embedding model, no LLM in the compression path, no vector DB to provision, no API key. Same input → same output bit-for-bit. Run it in CI, run it air-gapped, run it in a scratch Docker image.
Not in scope, on purpose: multimodal ingestion (OCR, PDF layout, image description, audio). If you need clean PDF/image text, run Docling / Marker / Unstructured / LlamaParse upstream and feed the extracted text into Sophon.
When to use it — and when not
Reach for Sophon when:
- You're building an MCP-based agent and want to cut the tokens that go out the door without adding a Python runtime, a vector DB, or a second LLM call.
- You need CI-reproducible compression behaviour — no model weights that silently change, no embedding drift, no non-determinism.
- Your system prompt is structured (XML/markdown sections) and you want query-aware section routing.
- You're hitting provider rate limits or cost caps from re-sending the same history or files every turn.
- You care about binary size, boot time, and zero external dependencies.
Reach for something else when:
- You need semantically optimal compression on unstructured text at any cost — use LLMLingua-2.
- You need persistent cross-session memory with LLM-driven fact extraction — use mem0, Letta, or Zep.
- You need real OCR / layout analysis on PDFs — use Docling, Marker, or Unstructured.
- You want provider-side cached billing rather than client-side compression — use Anthropic prompt caching or OpenAI prompt caching.
Sophon and those tools are orthogonal. A real stack will often run Sophon in front of provider caching, not instead of it.
Install
Via npm (wraps the native binary)
npm install -g mcp-sophon
sophon --version
The postinstall script downloads the right prebuilt binary for your platform from the GitHub Releases page. Supported: macOS arm64/x64, Linux arm64/x64, Windows x64.
Prebuilt binary
Grab the archive for your platform from the
Releases page and
put sophon on your PATH.
Build from source
git clone https://github.com/lacausecrypto/mcp-sophon
cd mcp-sophon/sophon
cargo build --release -p mcp-integration
# default build at target/release/sophon (~7.2 MB, regex extractors only)
# opt into 11-language AST extraction (~25 MB):
cargo build --release -p mcp-integration --features codebase-navigator/tree-sitter
Requires Rust 1.75+.
Quick start
As an MCP server
{
"mcpServers": {
"sophon": {
"command": "sophon",
"args": ["serve"]
}
}
}
CLI
sophon compress-prompt --prompt ./system.txt --query "how do I handle errors in Rust" --max-tokens 500
sophon compress-history --input ./history.json
sophon stats --period session
sophon serve # MCP stdio server
# Output compression + CLI hooks
sophon exec -- git status # run + compress output
sophon exec -- cargo test # failures only, ~90 % smaller
sophon compress-output --cmd "git diff" --input diff.txt
# Transparent hook installation for Claude Code
sophon hook install --agent claude --global
sophon hook status # show the 20 rewrite rules
sophon hook uninstall --agent claude --global
Programmatic (one-shot JSON-RPC)
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"compress_prompt","arguments":{"prompt":"<rust>use Result and the ? operator</rust><web>fetch()</web>","query":"rust errors","max_tokens":500}}}' \
| sophon serve
Workspace layout
.
├── README.md ← you are here
├── BENCHMARK.md ← every number, every caveat (the source of truth)
├── LICENSE ← MIT
├── server.json ← MCP registry manifest
├── .github/workflows/ ← CI + release automation
├── npm/ ← npm wrapper package
└── sophon/ ← Rust workspace
├── Cargo.toml
├── sophon.toml ← default runtime config
└── crates/
├── sophon-core/ shared types, token/hash helpers
├── prompt-compressor/ compress_prompt
├── memory-manager/ compress_history, update_memory, persistence
├── delta-streamer/ read_file_delta, write_file_delta
├── fragment-cache/ encode_fragments, decode_fragments
├── semantic-retriever/ chunker + HashEmbedder + linear k-NN + JSONL store
├── output-compressor/ command-aware stdout/stderr compression
├── cli-hooks/ transparent command rewriter + agent installer
├── codebase-navigator/ tree-sitter/regex extractors + PageRank + digest
└── mcp-integration/ stdio server, tool schemas, CLI
Configuration
Runtime defaults live in sophon/sophon.toml.
Environment variables:
SOPHON_MEMORY_PATH— JSONL file for persistent session memory (e.g.~/.sophon/memory/default.jsonl).SOPHON_RETRIEVER_PATH— directory for the semantic retriever store (e.g.~/.sophon/retriever). When set,compress_historyaccepts an optionalqueryparameter and returns top-k retrieved chunks alongside the compressed summary. This is the code path that drives the +13-pt LOCOMO retrieval gain in BENCHMARK.md § 3.7.SOPHON_FRAGMENT_MAX_WINDOW— override the fragment detector window size.SOPHON_CONFIG— path to asophon.tomlconfig file.
Per-call overrides are available on every MCP tool argument set
(max_tokens, recent_window, include_index, …).
Honest limitations
Every limitation is documented and measured in BENCHMARK.md § 6.6. At a glance:
- No multimodal ingestion. Images, PDFs, audio, and raw table parsing are out of scope. Run Docling / Marker / Unstructured / LlamaParse upstream and feed clean text in.
compress_historyis heuristic. No LLM in the summarization path — it's a join + keyword index + recent window. Good from ~20 messages up; short histories are passed through unchanged so the payload never grows.HashEmbedderis deterministic, not semantic. Good enough for the LOCOMO retrieval gain measured in § 3.7, not a replacement for BGE-M3 / nomic-embed on MTEB-grade semantic retrieval.- 11 AST languages, not every language. Enabling tree-sitter is
opt-in (
--features codebase-navigator/tree-sitter) to keep the default build free of C compilation. Languages outside the 11 supported still fall back to the regex extractor. - No cross-session memory by default. Set
SOPHON_MEMORY_PATHto opt into JSONL persistence; otherwise memory is in-process only.
Contributing
See CONTRIBUTING.md. PRs especially welcome for:
- Swapping
HashEmbedderfor a real embedder viafastembed-rs(BGE-small / nomic-embed) behind a feature flag - Python and TypeScript bindings
- More grammars for
navigate_codebase - Running the real
mem0library on LOCOMO to replace themem0-litesurrogate in § 7.8.e
Run the full test suite with:
cd sophon && cargo test --workspace
# with the tree-sitter feature:
cd sophon && cargo test --features codebase-navigator/tree-sitter
209 tests workspace-wide, all reproducible.
License
MIT — see LICENSE. Free to use, fork, modify, and ship.