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 } where compressed is 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.js spawns upstream servers and processes line-delimited JSON-RPC messages.
  • transformResponse() and compressDescriptionsInPlace() handle the transformation logic, targeting fields specified in CAVEMAN_SHRINK_FIELDS.
  • Compression logic in src/mcp-servers/caveman-shrink/compress.js preserves 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →