Caveman
Agent toolingMCP server

MCP server

caveman-mcp is a stdio JSON-RPC adapter that exposes the compression engine to any MCP host as three tools. It links the engine in-process, so MCP calls run the same compressors as the CLI.

The adapter owns MCP framing only. Compression, recovery, stats, and inferred ratios come from the engine. The server opens no network connection.

The three tools

A host that loads caveman-mcp sees three tools (exact, case-sensitive names):

text
caveman_compress(input: string, content_type?: string)
caveman_retrieve(recovery_handle: string, query?: string)
caveman_stats()
  • caveman_compress(input, content_type?) — runs the engine over a string and returns the compressed text, an inferred ratio, and a recovery_handle. content_type optionally forces a compressor, the same role --type plays on the CLI. Incompressible or malformed input is returned unchanged with ratio: 0 and recovery_handle: null.
  • caveman_retrieve(recovery_handle, query?) — returns the original for a handle disclosed by caveman_compress (or the compression proxy). With no query, it's the byte-exact original; with one, it narrows the result to the sections most relevant to it (BM25) instead of the whole thing. An unknown handle is an error, never a fabricated payload.
  • caveman_stats() — session totals: tokens before and after, the aggregate ratio, basis: "inferred", and scope: "session".

S4lossy · recoverable Compression is lossy but recoverable. Every drop the engine makes is stored under a content-addressed handle and is reachable through caveman_retrieve.

Configure your host

The adapter speaks MCP over stdio, so any host that launches a command and talks to it on stdin/stdout can use it. Point the host at your built binary:

json
{
"mcpServers": {
"caveman": {
"command": "/absolute/path/to/caveman-mcp"
}
}
}

The npx name is not live yet

You may see a {"command": "npx", "args": ["-y", "caveman-mcp"]} form in the source. That published name is reserved, not livenpx caveman-mcp does not resolve to this project yet. Until it does, run your own build: set CAVEMAN_MCP_BIN to its path, or point the host's command/args straight at the binary as shown above.

Build it

terminal
go build -o caveman-mcp ./public/mcp/cmd/caveman-mcp

That produces one binary. The host execs it and the binary serves tools on stdin/stdout. By default it opens the shared file recovery store — the same ~/.caveman/ccr.db the CLI and the compression proxy write to — so a caveman_retrieve call here can resolve a handle disclosed by another process (this is what lets an agent recover proxy-elided detail from a streaming request). Set CAVEMAN_MCP_EPHEMERAL=1 for a fresh in-memory store that touches no disk instead; handles from that store go away when the session ends.

How it stays honest

The adapter is built to fail in the safe direction in every case.

Fail open on input, fail closed on protocol

Fail open — if the engine errors or the input is malformed, caveman_compress returns the input byte-identical with ratio: 0. A compression problem never becomes a protocol error or a lost payload.

Fail closed — an unknown tool name or an unknown recovery_handle returns isError: true with a cave_snake_code, never a fabricated payload. An unknown JSON-RPC method returns -32601 (method not found).

Two more invariants hold by construction:

  • Zero-egress. The adapter imports no net, net/http, or os/exec. A source-parsing test fails the build if any of them appear. The tools cannot phone home because the code that would is not linked.
  • inferred-only. The string verified never appears in a result. caveman_stats always reports basis: "inferred". The open tools estimate; they do not certify.

Scope

Version one is stdio-only and handles string payloads — the engine detects the content type for you, so you pass raw text and it routes JSON, logs, code, diffs, and search results to the right compressor. There is no HTTP transport yet.