caveman-mcp 深度解析Caveman 项目中 stdio JSON-RPC 压缩工具服务器的设计、协议细节与容错不变量【免费下载链接】caveman why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman在 Caveman 这个用原始人说话减少 65% token的 Claude Code skill 项目中mcp/目录实现了一个薄型stdio JSON-RPC 适配器它把压缩引擎engine以五个 MCP 工具的形式暴露给任意 MCP 宿主Claude Code、Cursor 等。它只负责 MCP 协议帧framing所有压缩逻辑都以进程内链接方式交给引擎完成无子进程、无版本漂移它是纯本地组件不打开任何网络连接且报告的所有数据都标注为inferred推断绝不出现verified已验证。读完本文你可以掌握一个 MCP 服务器从 JSON-RPC 帧循环、协议协商、大小限制到可恢复压缩 反恢复风暴台账的完整实现路径以及stdout 即协议通道这一约束下的工程取舍。一、定位只拥有协议帧不拥有压缩mcp/AGENTS.md 给出的核心定义是这是一个 thin stdio JSON-RPC adapter。thin 是刻意的架构决策体现在三处可注入的 Engine 接口。engine_tools.go 中定义了Engine接口*engine.Engine满足它而测试注入 mock——这意味着协议帧本身可以在不跑真实压缩器的情况下被验证。接口方法集与五个工具一一对应type Engine interface { Compress(input []byte, opts engine.Options) (engine.Result, error) Retrieve(handle string) ([]byte, error) RetrieveQuery(handle, query string) ([]byte, error) Stats() (ccr.Stats, error) EncodeTOON(input []byte) ([]byte, error) DecodeTOON(input []byte) ([]byte, error) }本地-only。适配器不导入net/net/http/os/exec并且有一个专门的测试通过解析源码 AST 来强制执行这一点——TestZeroEgressNoNetworkImportsserver_test.go扫描mcp/与mcp/cmd/caveman-mcp下所有非测试 Go 文件的 import 列表若出现net、net/http、net/rpc、os/exec任一项即测试失败。这把零外联从口号变成了 CI 可验证的不变量。inferred-only。统计类输出永远携带basis:inferred、scope:session字符串verified从不出现在 MCP 结果中源码注释引用了 PRD §11.5 作为依据见 engine_tools.go。二、目录布局从协议层到可执行二进制文档列出的布局与实际文件一一对应文件职责server.goServerJSON-RPC 主循环、分发dispatch、大小上限、批量处理、panic 捕获protocol.goJSON-RPC 请求/响应/错误类型、ToolText/ToolRawText/ToolError辅助函数、ObjectSchema/StringProp的 inputSchema 构造engine_tools.goEngineTools(eng, log)五个工具的定义名称、描述、schema、handler与各自的 fail-open/fail-closed 语义cmd/caveman-mcp/main.go二进制入口打开共享文件 CCR 存储然后服务 stdin↔stdoutpackage.jsoncaveman-mcpnpm 包bin/caveman-mcp.mjs启动器 exec 预构建 Go 二进制mcp/README.md 补充了面向用户的安装方式Claude Code// .mcp.json / claude mcp config { mcpServers: { caveman: { command: npx, args: [-y, caveman-mcp] } } }MIT 许可的 npm 启动器在首次运行时下载匹配的 BSL-1.1 二进制见 BINARY_LICENSE.md校验密钥签名的 checksum 清单与产物 SHA-256并缓存在~/.caveman/bin下——不需要 Go 工具链也不需要全局安装 Caveman。若已有经过审查的二进制可以用环境变量覆盖CAVEMAN_MCP_BIN/path/to/caveman-mcp npx caveman-mcp许可边界清晰npm 启动器是 MIT下载的 Go 二进制遵循BINARY_LICENSE.md中命名的 BSL-1.1 条款AGENTS.md 标题即点明 commercial Go core MIT launcher。三、五个工具精确名称与行为语义mcp/AGENTS.md 强调五个工具名大小写敏感、精确匹配engine_tools.go 中以常量固化const ( ToolCompress caveman_compress ToolRetrieve caveman_retrieve ToolStats caveman_stats ToolToonEncode caveman_toon_encode ToolToonDecode caveman_toon_decode )3.1 caveman_compresslossy 但可逆且永不报错caveman_compress(input)返回压缩文本、推断的ratio和recovery_handle。行为契约fail-closed 指结果不可用时不产生坏结果此处表现为原样透传输入不可压缩、格式错误或压缩后并不更小 →原样返回ratio: 0recovery_handle: null——不是错误。引擎错误时只有当引擎返回了完全记账的字节级透传res.Output input且 token 数前后一致、无 handle才保留透传第三方Engine实现若带着 error 返回不安全/空结果则响亮失败为cave_compress_failed不让非空内容看起来零 token 成本engine_tools.go。实际返回的 JSON 载荷结构compressPayloadtype compressPayload struct { Compressed string json:compressed Ratio float64 json:ratio TokensBefore int json:tokens_before TokensAfter int json:tokens_after Basis string json:basis ContentType string json:content_type RecoveryHandle *string json:recovery_handle Method string json:method,omitempty LosslessToModel *bool json:lossless_to_model,omitempty }工具 schema 接受input必填、content_type可选引擎内容类型如json或toon和typecontent_type的别名handler 中优先取content_type为空时回退到type。3.2 caveman_retrieve字节级还原与最后手段定位caveman_retrieve(recovery_handle)返回字节级精确的原始内容。未知 handle →isError:truecave_snake_code实际实现为cave_unknown_handle绝不伪造载荷。从 engine_tools.go 的工具描述可以看到一个非常克制的产品判断retrieve 是LAST RESORT不是分页 API。理由是省略标记本身携带了计算自被替换单位的不变量… 340 rows elided (caveman): all statecharged; range amount5.00..199.99 …而每个被丢弃的单位都与仍可见的单位相似——因此计数、求和、单字段类问题通常不需要调用即可回答。工具描述明确要求每个 handle 只发一次宽查询而不是多次窄查询因为每次 retrieve 都会让模型重读整个会话前缀代价远超压缩省下的 token。handle 的归一化normalizeRecoveryHandle接受这套栈历史上暴露给 agent 的所有引用形态裸 handleccr_…Compress 返回的原始形式ccr:ccr_…内嵌在压缩内容中的标记ccr:ccr_…半剥离形式ccr://…原生运行时工具输出掩码full: ccr://id其 id 是类型化对象 id 而非 blob handle源码注释坦率地记录了背景缺少ccr://这一形态曾导致 inventory-mismatch 与 webhook-delivery-gaps 类任务在 2026-08-08 无解——agent 看到了一个恢复工具拒绝解析的引用。query参数可选但强烈建议提供查询会经 BM25 把恢复收窄到相关节空查询则是字节级全量恢复。返回的查询视图只含完整记录从不抽行且在有内容跳过处包括开头和结尾打印… [caveman: non-adjacent] …标记。关键实现细节caveman_retrieve是唯一声明ExemptResultCap: true的工具——它豁免 16 MiB 结果上限。因为共享 gateway 存储没有对应天花板一个合法可超过上限的原始字节流若因大小被 fail-closed 掉被省略的内容就永远不可恢复了。3.3 caveman_stats会话级推断统计无参调用返回statsPayloadtokens_before、tokens_after、requests、ratio、basis:inferred、scope:session。引擎统计不可用时 fail-closed 为cave_stats_unavailable绝不输出未经标注的数字。3.4 / 3.5 TOON 编码对显式重编码失败大声caveman_toon_encode(input)显式的 JSON→TOON 重编码返回output、encoded、input_bytes、output_bytes及失败时的note。它不是代理路径上的 best-of 门只要编码合法就返回即使结果并不更小两个尺寸都给出让 agent 自己决定。不可编码的输入原样返回并附说明——绝不静默 no-op绝不发明编码。caveman_toon_decode(input)TOON→JSON。非法 TOON 返回isError:truecave_invalid_toon绝不把原始输入当 JSON 输出。mcp/README.md 汇总的工具表可作为宿主侧速查工具输入返回caveman_compressinputstring压缩文本、推断ratio、recovery_handle透传时为 nullcaveman_retrieverecovery_handlestring字节级原始内容未知 handle 报错caveman_stats—会话总量前后 token、ratio、basis:inferred、scope:sessioncaveman_toon_encodeinputJSON string显式 JSON→TOON 结果与尺寸不可编码时透传说明caveman_toon_decodeinputTOON string解码后的 JSON非法 TOON 报错四、协议层解剖stdout 即协议通道4.1 主循环只有 EOF 能结束会话mcp/AGENTS.md 的 Gotchas 第一条称之为un-killable transportstdio 服务器能扛住除 EOF 以外的一切。对照 server.go 的实现Serve主循环对每一行做如下处理超长行readLine以maxInboundBytes默认 16 MiBdefaultMaxInboundBytes 16 20为界超限部分仍会排空到下一个换行有界工作量、不缓冲然后回cave_payload_too_large并继续服务——注意这里回的是-32600codeInvalidRequest而非解析错误。非法 JSON 行回-32700parse error循环重新同步到下一换行绝不return。handler panic被invokeHandler里的recover()捕获 → fail-closed 的cave_tool_panicked工具错误分发路径handler 之外的 panic 被serveOne顶层recover()捕获 →-32603cave_internal_error。JSON-RPC 批量数组以[开头的行进入handleBatch逐成员分发非通知成员的响应收集为一个数组按规范回写全通知批次无响应空批次回-32600。无 id /id:null的请求isNotification判定为通知protocol.go永不回复——注释指出这是 issue #139 的子问题 #4。背后的产品逻辑写在文档里一个死掉的服务器比一个慢的服务器更糟——因为caveman wrap从安装期标记而非活着的 agent判断恢复能力若 MCP 进程死亡代理会持续省略内容而这些内容已没有caveman_retrieve可以展开。4.2 协议协商拒绝回显新版本是对的拒绝说话不是initialize的处理server.go实现了文档强调的不变量——协议协商绝不能报错func (s *Server) handleInitialize(req rpcRequest) rpcResponse { version : defaultProtocolVersion // 2024-11-05 // 若客户端请求的版本在 supportedProtocolVersions 中回显客户端版本 // 否则用本适配器实现的 2024-11-05 应答由客户端自行决定是否继续 ... }supportedProtocolVersions刻意只含2024-11-05一项——回显一个本进程并未实现的新版本语义会让客户端误判能力。历史教训也记录在源码注释里旧实现曾以-32602: unsupported protocol version应答导致 Claude Code 等所有已越过 2024-11-05 的客户端直接丢弃该服务器而如前所述caveman wrap依赖安装期标记于是代理持续省略、agent 却无工具可恢复。回归测试TestInitializeOffersItsOwnVersionToNewerClientsserver_test.go覆盖了2025-06-18、2025-03-26、9999-01-01和空串四种请求版本断言全部得到2024-11-05且无错误。4.3 工具调用分发与结果上限handleToolCallserver.go的分发细节参数解析失败 →-32602invalid params未知工具名不是 JSON-RPC 错误而是一个成功的响应里携带 fail-closed 工具错误cave_unknown_tool——宿主拿到isError:true的工具结果而不是协议层异常非豁免工具的结果超过maxResultBytes默认同样 16 MiB→ 整个结果被替换为cave_payload_too_large工具错误提示请求更窄的切片。protocol.go中的 JSON-RPC 错误码常量集-32700/-32600/-32601/-32602/-32603与ToolResult{Content []ToolContent, IsError bool}结构共同构成宿主可见的完整契约ToolError把错误序列化为{error: code, message: msg}文本并置IsError:true保证宿主不会把它误认为成功载荷。五、CCR 恢复存储跨进程 handle 解析cmd/caveman-mcp/main.go 的openRecoveryStore实现了文档描述的存储选择链CAVEMAN_MCP_EPHEMERAL1→ccr.OpenMemory()全新内存存储不落盘——用于测试或不需要代理恢复的会话CAVEMAN_CCR_DB环境变量 → 指定路径CAVEMAN_HOME/ccr.db再回退~/.caveman/ccr.db连 home 目录都拿不到时兜底内存存储。默认走共享文件存储是有意为之它与 Caveman 网关写的是同一个 store因此caveman_retrieve在这里能解析代理曾披露的 handle——这正是被包裹 agent 能在流式请求上恢复代理省略细节的机制。二进制另有version --json子命令输出构建版本schemacaveman.mcp.version.v1能力mcp_recovery、build_stamped_version而NewServerVersion构造器确保 initialize 里报告的版本与version --json不漂移server.go。启动序列本身也体现stdout 纯净日志器构造在slog.NewTextHandler(os.Stderr, ...)上srv.Serve(os.Stdin, os.Stdout)之前只允许 stderr 输出。六、诚实性不变量与容错策略mcp/AGENTS.md 的 Gotchas 一节是这个模块最有辨识度的工程哲学可以归纳为四条对称的不变量不变量语义源码/测试证据un-killable transport除 EOF 外任何异常都被应答并跳过server.go 主循环 recover 链issue #139fail-open引擎错误或输入畸形 → 字节级一致的透传永不成为协议错误compressTool的透传路径engine_tools.gofail-closed未知工具/handle →isErrorcave_snake_code未知 JSON-RPC 方法 →-32601handleToolCall与dispatch的 default 分支zero-egress不导入net/net/http/os/execTestZeroEgressNoNetworkImportsserver_test.go解析 import 强制执行两条容易混淆的方向值得单独说明fail-open 针对的是数据路径——压缩失败时内容无损通过宿主对话不中断fail-closed 针对的是能力声明——不能恢复的东西绝不假装恢复不存在的 handle 绝不返回伪造内容。两者合起来保证了透传的内容永远可用承诺的恢复永远可兑现。v1 的范围边界也被文档显式钉住stdio-only、仅字符串载荷引擎自行探测类型HTTP 传输与caveman mcp子命令属于 v2。七、反恢复风暴台账retrieve 的成本模型mcp/CLAUDE.md 的 Retrieve anti-storm 一节给出了一个重要的成本模型caveman_retrieve花掉的是整个 agent 回合——模型要重读整个会话前缀且每次 retrieve 返回的内容从此成为前缀的一部分。所以 N 次 retrieve 不是 N 个载荷的成本而是 N 个回合叠加在逐次增长的字幕上的成本。源码注释engine_tools.go引用了 2026-08-10 对 229 个本地 CaveBench stdout 文件的只读扫描34 个恢复会话、534 次恢复工具调用分布为 1 次 / 2–5 次 / 5 次 3 / 16 / 15 个会话p95 为 118、最大 14315 个高调用会话中有 8 个仍通过了精确任务评分器534 次调用中仅 3 个归一化(handle, query)对是完全重复。注释同时诚实地标注这是混杂的臂、任务与重复批次是描述性调用形态证据不是同任务对照实验也不验证任何普适阈值。在此证据之上EngineTools携带一个**每进程每会话**的恢复台账retrieveSession两条规则且任何一条都不许扣留本会话尚未给过的内容重复请求指回完全相同的(handle, query)query 经过与RetrieveQuery相同的 trim 归一化所以 与是同一次请求不再重发字节而是返回一行指针repeatNote这个精确的 recovery_handle 和 query 本会话早前已回答——内容逐字就在上方对话里去那里重读重复同样的查询不会带回任何新东西。超阈值全量兑付会话内不同恢复次数超过retrieveStormThreshold5作为历史运行时行为保留后下一次调用返回该 handle 的完整存储原文而非查询收窄视图并附fullPayoutNote说明——意图是避免更长的窄查询分页序列注释明确没有配对实验验证过该阈值的 token 或任务效果修改阈值需要那个实验。实现上retrieveSession用互斥锁保护map[string]boolkey 为handle \x00 TrimSpace(query)且nil *retrieveSession是安全的——禁用两条规则使没有会话概念的调用方保留旧语义engine_tools.go。mcp/CLAUDE.md 还记录了工具集本身的前缀成本注册此服务器会把五个工具 schema 放进被包裹 agent 的每次调用前缀——agent 基准中约 11,060 tokens/次调用201 次调用累计约 2.22M。这正是caveman wrap把注入放在execute.mcp表面旋钮auto|marker-only|true|false见packages/cli/src/index.ts之后的原因非 auto 表面下 wrap 抑制其两处注入点mcp install写入与配置型 agent 的 profilemcp.servers.caveman叠加层但从不卸载用户自行安装的服务器。文档的结论一句话在这里加第六个工具会让每个被包裹 agent 的每次调用税负都涨。八、构建、测试与约定文档约定的开发与验证方式make product-build PRODUCTmcp make product-test PRODUCTmcp配套约定与测试保障stdout 是协议通道——日志只准走 stderr且有专门测试守卫server.go 包注释日志仅写注入的 loggerstdout 专属于协议构造器对 nil logger 丢弃日志而非乱写。server_test.go 覆盖协议版本协商新旧客户端均不得报错、批量与通知语义、零外联 import 扫描、in-memory 全周期测试无磁盘无网络跑通压缩→恢复闭环。retrieve_integration_test.go 与 engine_tools_antistorm_test.go 分别覆盖恢复集成与反风暴台账行为cmd/caveman-mcp/main_test.go 覆盖二进制参数与存储选择tests/launcher.test.mjs 与 tests/package.test.mjs 在 npm 包层面验证启动器。测试数据mcp/testdata/包含 inventory_catalog_page.json、inventory_stock_page.csv、webhook_delivery_events_page.json——与源码注释中提到的 inventory-mismatch、webhook-delivery-gaps 真实失败场景对应。九、小结一个诚实的压缩工具的完整契约把 mcp/AGENTS.md 的骨架与源码对齐后caveman-mcp 的设计可以浓缩为五句话薄帧MCP/JSON-RPC 帧循环与压缩引擎彻底解耦Engine 可注入、帧可独立测试可恢复的 lossy压缩丢掉的每个字节都对应一个ccr_handlecaveman_retrieve字节级还原且豁免大小上限——省略永不成为数据丢失可杀不死的传输非法行、超长行、批量、panic 全部应答后继续只有 EOF 结束会话因为死服务器会让代理省略的内容永远不可展开双向诚实数据路径 fail-open透传不中断能力声明 fail-closed不伪造、不假装统计永远inferred成本自知工具 schema 前缀成本、retrieve 的整回合成本都被量化并写进决策——包括用台账抑制恢复风暴以及加第六个工具 全员涨税的约束。对想复用的开发者而言这个模块给出的参考实现是Serverserver.go本身与 Caveman 无耦合任何宿主只需提供[]Tool名称、描述、inputSchema、handler可选ExemptResultCap即可在自己的 stdio JSON-RPC 工具服务器上获得同样的行重同步、批量语义、panic 捕获、16 MiB 双向大小限制与 stdout 纯净保证。【免费下载链接】caveman why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考