What Is caveman-shrink and How Does It Compress MCP Server Tool Descriptions?
caveman-shrink is an MCP middleware proxy that intercepts JSON-RPC responses from upstream servers and compresses textual fields—primarily tool descriptions—to reduce token consumption while preserving code snippets, URLs, and structural integrity.
The caveman-shrink utility is part of the JuliusBrussee/caveman open-source toolkit. It acts as a transparent line-delimited JSON-RPC proxy that sits between Claude-style clients and MCP servers, reducing context window usage by shrinking verbose description strings before they reach the language model.
Architecture and Entry Point
The executable is a Node.js script located at src/mcp-servers/caveman-shrink/index.js. It is invoked as caveman-shrink <upstream-command> [...upstream-args].
The script spawns the upstream MCP server using child_process.spawn at line 45, creating a middleman process that handles both request forwarding and response transformation. MCP communication uses line-delimited JSON-RPC, which caveman-shrink buffers and parses before forwarding transformed payloads to the client.
Response Transformation Pipeline
The core transformation happens in transformResponse(msg) (lines 73-108). This function walks through the response object looking for top-level arrays including tools, prompts, resources, and resourceTemplates.
For each item found, every field listed in the CAVEMAN_SHRINK_FIELDS environment variable is examined. If the field contains a string, the text is passed to compress() imported from the companion module compress.js (line 30). When compression occurs, the item is mutated in-place, and optional debug logging (controlled by CAVEMAN_SHRINK_DEBUG=1) prints before/after byte lengths to stderr.
If none of the top-level arrays contain target fields, the system calls compressDescriptionsInPlace(r, fields) at line 106. This recursively walks arbitrary nested objects to compress any stray description fields, ensuring deeply-nested tool schemas get shrunk.
Compression Logic in compress.js
The compression functions reside in src/mcp-servers/caveman-shrink/compress.js. The module exports two critical functions:
compress(text)— Returns an object{ compressed, delta }wherecompressedis the shortened version of the input text. The algorithm strips redundant whitespace, collapses long URLs, and applies token-budget heuristics while preserving structural elements.compressDescriptionsInPlace(obj, fields)— Recursively traverses any plain object, finds keys matching the specified fields list, and replaces their string values with compressed versions.
The compression deliberately preserves code blocks, URLs, file system paths, and identifier tokens so downstream parsers and tool call handlers continue to function correctly.
Configuration Options
Control compression behavior through environment variables:
| Variable | Purpose | Default |
|---|---|---|
CAVEMAN_SHRINK_FIELDS |
Comma-separated list of field names to compress (e.g., description,summary) |
description |
CAVEMAN_SHRINK_DEBUG |
Set to 1 to emit per-field compression statistics on stderr |
unset |
Export these variables before launching the proxy, or place them in a .env file for convenience.
Implementation Examples
Wrapping a Filesystem MCP Server
Register the proxy in your Claude configuration:
{
"mcpServers": {
"fs-shrunk": {
"command": "npx",
"args": [
"caveman-shrink",
"npx",
"@modelcontextprotocol/server-filesystem",
"/my/project"
]
}
}
}
Enabling Debug Output and Extra Fields
export CAVEMAN_SHRINK_FIELDS="description,summary"
export CAVEMAN_SHRINK_DEBUG=1
npx caveman-shrink npx @modelcontextprotocol/server-filesystem /some/path
Debug lines showing compression deltas will appear on stderr.
Programmatic Spawning
As implemented in the installer logic at bin/install.js:
const { spawn } = require('child_process');
const args = [
'caveman-shrink',
'npx',
'@modelcontextprotocol/server-filesystem',
'/some/path'
];
const proc = spawn('npx', args, { stdio: 'inherit' });
Before and After Compression
Input from upstream server:
{
"result": {
"tools": [
{
"name": "search",
"description": "Search the entire code base for the supplied query string and return a list of matching files."
}
]
}
}
After caveman-shrink processing:
{
"result": {
"tools": [
{
"name": "search",
"description": "Search the entire code base for the query string; return matching files."
}
]
}
}
Summary
- caveman-shrink acts as a transparent MCP proxy that reduces token usage by compressing description fields in JSON-RPC responses.
- The main entry point at
src/mcp-servers/caveman-shrink/index.jsspawns upstream servers and processes line-delimited JSON-RPC messages. transformResponse()andcompressDescriptionsInPlace()handle the transformation logic, targeting fields specified inCAVEMAN_SHRINK_FIELDS.- Compression logic in
src/mcp-servers/caveman-shrink/compress.jspreserves code blocks, URLs, and identifiers while removing redundant whitespace. - Configuration via environment variables allows customization of which fields to compress and enables debug logging for monitoring compression ratios.
Frequently Asked Questions
What fields does caveman-shrink compress by default?
By default, caveman-shrink only compresses fields named description. You can modify this by setting the CAVEMAN_SHRINK_FIELDS environment variable to a comma-separated list of field names (e.g., description,summary,notes).
Does caveman-shrink modify incoming requests to the server?
No. According to the implementation in src/mcp-servers/caveman-shrink/index.js (lines 23-25), stdin data from the client is piped straight through to the upstream server unchanged. Only responses from the server to the client are transformed.
How do I debug compression statistics?
Set the environment variable CAVEMAN_SHRINK_DEBUG=1 before launching the proxy. This enables logging of before/after byte lengths for each compressed field to stderr, helping you monitor token reduction in real-time.
Will compression break tool execution or code examples?
No. The compression algorithm in compress.js is designed to preserve structural integrity. It specifically maintains code blocks, URLs, file paths, and identifier tokens, ensuring that downstream MCP clients can still parse and execute tool calls correctly.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →