# What Is caveman-shrink and How Does It Compress MCP Server Tool Descriptions?

> Discover caveman-shrink, the MCP middleware proxy that compresses tool descriptions in JSON-RPC to minimize token usage while safeguarding code and URLs.

- Repository: [Julius Brussee/caveman](https://github.com/JuliusBrussee/caveman)
- Tags: deep-dive
- Published: 2026-07-08

---

**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`](https://github.com/JuliusBrussee/caveman/blob/main/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`](https://github.com/JuliusBrussee/caveman/blob/main/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`](https://github.com/JuliusBrussee/caveman/blob/main/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:

```json
{
  "mcpServers": {
    "fs-shrunk": {
      "command": "npx",
      "args": [
        "caveman-shrink",
        "npx",
        "@modelcontextprotocol/server-filesystem",
        "/my/project"
      ]
    }
  }
}

```

### Enabling Debug Output and Extra Fields

```bash
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`](https://github.com/JuliusBrussee/caveman/blob/main/bin/install.js):

```javascript
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:

```json
{
  "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:

```json
{
  "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`](https://github.com/JuliusBrussee/caveman/blob/main/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`](https://github.com/JuliusBrussee/caveman/blob/main/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`](https://github.com/JuliusBrussee/caveman/blob/main/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`](https://github.com/JuliusBrussee/caveman/blob/main/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.