mcpField
S
Sarup

Sarup

本地服务
github.com/PHUICMTAI 与智能体03 天前更新

关于 Sarup

Sarup 是面向泰语的上下文压缩 MCP 服务,适用于 Claude Code 和其他 MCP 客户端。它压缩较长的泰语和英语文本,同时缓存原文以便逐字节恢复;部分模式可选用 Ollama,并支持离线回退。

主要功能

  1. 01压缩泰语和英语文本
  2. 02通过哈希恢复缓存的原文
  3. 03提供五种压缩模式
  4. 04保留代码围栏并压缩 JSON
  5. 05自动压缩较大的工具输出
  6. 06统计会话节省的令牌

适用场景

  1. 01缩减模型上下文中的长工具输出
  2. 02有损压缩后恢复原文
  3. 03为 Claude Code 压缩泰语文档
  4. 04查看会话累计节省量

MCP 相关

它向 MCP 客户端提供压缩、原文恢复和会话统计工具。Claude Code 的可选 Hook 还会压缩较大的工具输出,并保存原文以供恢复。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"phuicmt-sarup": {
"command": "uvx",
"args": [
"sarup"
]
}
}
}
启动命令uvx sarup

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypisarup0.2.0

工具

3

收录的工具列表 · 更新于 2 天前

参数类型必填说明
modeenum否散文压缩策略。'extractive'(默认):离线 TF-IDF,逐字摘取子集,约 1ms。'semantic':嵌入中心性,压缩率最佳(需要 Ollama)。'abstractive':本地 LLM 改写(需要 Ollama,速度较慢)。'pipeline':依次执行 semantic -> abstractive,以最大限度节省内容。'auto':Ollama 可用时使用 semantic,否则使用 extractive。所有模式均可通过 sarup_retrieve 100% 恢复。如果因缺少 Ollama 或模型而回退,结果会包含说明所需安装内容的 'setup' 字段。extractive | semantic | abstractive | pipeline | auto
querystring否可选的上下文查询。与此查询相关的句子会获得更高评分,因此更可能被保留。
contentstring是要压缩的内容
losslessboolean否仅应用无损转换(空白字符/JSON 压缩)。默认值为 false。
target_rationumber否保留的散文比例(0.3–0.7)。默认值为 0.5。

详细介绍

总结 · Sarup

面向泰语的 Claude Code 上下文压缩工具。 一个真正能压缩泰语(减少 50–78% token)的 MCP 服务,并缓存每份原文, 确保内容永不丢失。衡量指标也切中要点:Claude 是否仍能正确回答。

CI  PyPI  License: MIT  Python  MCP  tests

สรุป 意为“总结”。Headroom 会将泰语交给 noop 处理(节省 0%),因为它的空白字符分词器无法识别泰语词语边界。Sarup 使用 PyThaiNLP 分词,因此既能压缩泰语,也能压缩英语——并缓存每份原文,确保内容永不丢失。

目录

亮点

  • 🇹🇭 真正的泰语压缩——使用 PyThaiNLP newmm 进行词语分词,而非依赖空白字符。
  • ♻️ 保证无损——每次压缩都会缓存原文;verified: true 可证明往返还原后逐字节一致。
  • 🎚️ 五种模式:从离线运行、耗时 1 ms 的 TF-IDF,到节省 78% 的级联模式。
  • 🧠 可选的本地 LLM——通过 Ollama 使用嵌入 + 改写,并可自动回退到离线模式。
  • 📏 真实可信的指标:运行时使用真正的分词器(tiktoken);已发布的数据则使用 Claude 自带的分词器和泰语 QA 评测(Claude 还能正确回答吗?)。
  • 🕳️ 清晰标示缺失内容:每处被删去的句子都会以 […] 标记,促使 Claude 检索信息,而不是把附近的事实误当成答案。
  • 🔌 感知内容类型——内置 JSON 精简、日志去重和代码围栏原样保留功能。
  • 🛟 不会影响 Claude 的正常工作——它是 MCP 工具,不是 API 代理;如果服务停止,工具只会消失,Claude 仍可继续工作。

为何安全——双层保障

层级内容保障
压缩视图模型使用的精简文本有损 · 体积小 · 成本低
检索存储以稳定哈希为键保存的原文无损 · 可恢复

激进的有损压缩之所以安全,是因为只需调用一次 sarup_retrieve(hash),就能取回原文。这就是“最大限度节省”和“100% 准确率”能够并存的原因——它们属于不同的层级。

工作原理

两个入口共用一个引擎:模型读取的低成本压缩视图,以及能够逐字节还原原文的无损 检索存储。

flowchart TD
    M["🧑 Manual<br/>sarup_compress()"]:::entry --> R
    A["⚙️ Automatic<br/>PostToolUse hook<br/>(Read · Bash · Grep)"]:::entry --> R

    R{"Sarup compress<br/>extractive · semantic · abstractive · pipeline"}:::engine
    R -- "compressed view<br/>50–78% fewer tokens" --> V["📄 Model context"]:::lossy
    R -. "cache original" .-> S[("🗄️ Retrieval store<br/>hash → original")]:::lossless

    V -. "need full detail?" .-> RET["🔑 sarup_retrieve(hash)"]:::lossless
    RET --> S
    S == "byte-for-byte ✓" ==> V

    classDef entry fill:#e0e7ff,stroke:#6366f1,color:#111
    classDef engine fill:#fde68a,stroke:#d97706,color:#111
    classDef lossy fill:#fef3c7,stroke:#f59e0b,color:#111
    classDef lossless fill:#bbf7d0,stroke:#16a34a,color:#111
  • 手动——模型自行调用 sarup_compress / sarup_retrieve。
  • 自动——钩子会拦截较大的工具输出,将原文缓存到 SARUP_DB_PATH, 并以压缩视图 + 检索哈希替代。源代码会跳过不处理;较小的输出则保持原样传递。

工具

工具用途
sarup_compress(content, target_ratio?, lossless?, query?, mode?)压缩;返回压缩文本、哈希、令牌指标、verified、token_method。
sarup_retrieve(hash)逐字节还原原始内容。
sarup_stats()累计会话节省量。

sarup_compress 参数

参数类型默认值含义
contentstring—要压缩的文本(必填)。
target_rationumber0.5保留的正文比例(0.1–0.9)。
losslessbooleanfalse仅应用无损转换(空白字符/JSON 压缩)。
querystring""你需要从文本中获取的内容;与其匹配的句子会被保留。知道需求时请始终传入:在相同大小下,它将 QA 评测结果从 69% 提升到了 100%。
modestringextractive参见下方模式。

压缩模式

模式方法需要 Ollama节省¹速度¹输出
extractive (默认)TF-IDF 评分 + 事实加权 + n-gram 去重否52.7%约 1 ms原文子集
semantic嵌入中心性 + 余弦去重是63.8%约 2 s原文子集
abstractive本地 LLM 改写是44.4%约 8 s改写文本
pipeline级联:语义 → 抽象是78.2%约 6 s改写文本
autoOllama 正常运行时使用语义模式,否则使用抽取式模式可选63.8%约 2 s子集

¹ 在一段包含 10 个句子的泰语段落(522 个令牌)上测得,改写模型为 gemma4:12b。通过存储机制,所有模式的内容都能 100% 还原;Ollama 模式在后端不可用时会平稳降级为抽取式模式。(gemma4:e4b:pipeline 为 82.2%;2026 年 6 月,gemma3:12b:88.1%。)

抽取式和语义模式的输出是输入句子的原文子集;每当句子被省略时,都会在单独一行显示 […]。包含具体信息(数字、泰语数字、X-Api-Key 等标识符)的句子得分高于一般陈述,因为问题通常会询问这些内容。

实测结果

$ .\.venv\Scripts\python.exe bench\benchmark.py

sample                      before   after   savings   verify
Thai prose                     522     247    52.7%       OK
Thai prose (aggressive)        522     189    63.8%       OK
English prose                  105      60    42.9%       OK
JSON (lossless)                 67      44    34.3%       OK
Logs                           563     300    46.7%       OK
TOTAL                         1779     840    52.8%    ALL OK   → 100% recoverable

Mode comparison (Thai prose, 522 tok):
  extractive 52.7% (1ms) · semantic 63.8% (2.1s) · auto 63.8% (2.1s)
  abstractive 44.4% (8.3s) · pipeline 78.2% (5.8s)      ← gemma4:12b

令牌数通过 tiktoken cl100k_base 计算。它是 OpenAI 的分词器,会低估 Claude 的令牌数,尤其是泰语;bench\benchmark.py --claude 会添加一列 Claude 自带分词器的结果(Anthropic count_tokens,需要 API 密钥)。

Claude 还能答对吗?

只有事实得以保留,减少 Token 才有意义。bench\eval_qa.py 会压缩 8 份泰语文档 (事故报告、会议记录、API 文档、人事政策、产品规格、支持聊天、README、销售 报告;一半是每行一句,另一半是密集段落),然后仅根据压缩后的内容向 Claude Opus 5.5 提出 32 个问题,并以确定性方式评分:

$ .\.venv\Scripts\python.exe bench\eval_qa.py        # uses your local `claude` login

mode               claude tok   saved  correct  abstain  wrong
──────────────────────────────────────────────────────────────
original                 4601    0.0%     100%       0%      0
extractive:0.5           3204   30.4%      69%      31%      0
extractive:0.3           1969   57.2%      44%      56%      0
semantic:0.5             3214   30.1%      62%      38%      0
extractive:0.5+q         3207   30.3%     100%       0%      0
abstractive:0.5          2697   41.6%      91%       9%      0     ← gemma4:12b
pipeline:0.5             1854   59.8%      59%      41%      0     ← gemma4:12b

(gemma4:e4b 的得分相同:抽象式压缩为 91%,流水线为 59%,错误率为 0。)

  • 错误率为 0 是安全保障:事实被删除时,Claude 会如实表示不知道(弃答),并会在实际使用中调用 sarup_retrieve。它不会根据剩余内容猜测。
  • 弃答 是盲目压缩的实际代价:在 0.5 的设置下,大约三分之一的具体问题需要往返检索。知道自己要找什么?将其作为 query 传入(+q 行)。
  • 抽象式压缩能以每个 Token 保留最多事实(节省 42% 时保留 91%),因为改写可以在删去文字的同时保留所有数字;抽取式压缩则只能整句删除。它每份文档需要花费数秒,因此请通过 sarup_compress 使用,而不是通过钩子。
  • 两次评测中,改写都没有把事实转述错,但 8 份文档无法证明改写永远不会出错,因此原文始终可以通过一次 sarup_retrieve 调用获取。
  • 这里的 Token 数量来自 Claude 自身(取自回答调用的用量),包含约 40 个 Token 的 [sarup: …] 页脚。对于这些较短(约 570 个 Token)的文档,页脚占比很高;而对于钩子实际压缩的大型输出,占比则会降低。
  • 8 份文档只是小样本;不同模式之间相差几个问题属于随机波动。

在本次评测推动修复之前(2026 年 10 月):密集的泰语段落完全没有被压缩(未安装句子切分器所需的模型),extractive:0.5 的回答正确率为 59%,且有一个错误但信心十足的答案;semantic:0.5 的正确率为 47%。

示例

对一段泰语文本执行真实的 sarup_compress 调用(mode="auto",Ollama 已启动 → 使用语义模式):

// → sarup_compress(content="…518-token Thai paragraph…", mode="auto")
{
  "compressed": "จุดเด่นที่สำคัญที่สุดคือมันไม่มีทางทำให้ Claude พัง…",
  "hash": "caa568140bec0ff734937cf5",
  "original_tokens": 518,
  "compressed_tokens": 154,
  "tokens_saved": 364,
  "savings_percent": 70.3,
  "transforms": ["semantic_extractive", "embeddings", "thai"],
  "lossy": true,
  "verified": true,                    // round-trip proven byte-for-byte
  "token_method": "tiktoken:cl100k_base"
}

模型会继续基于 154 个 Token 的视图工作;只需一次调用即可获取完整的 518 个 Token 原文:

// → sarup_retrieve(hash="caa568140bec0ff734937cf5")
{ "content": "…the exact original text, restored byte-for-byte…" }

安装

作为 Claude Code 插件安装(最简单)

需要 uv:插件通过 uvx 运行 Sarup,并会在首次使用时获取 Python 和依赖项。无需克隆。在 Claude Code 中:

/plugin marketplace add PHUICMT/sarup
/plugin install sarup@sarup

这会安装 MCP 服务、自动压缩钩子和 /sarup:sarup-setup 技能。 缓存位于插件的数据目录中,因此插件更新后仍会保留。首次启动时,uvx 构建环境需要几秒钟。也可以改用 Shell:

claude plugin marketplace add PHUICMT/sarup,然后执行 claude plugin install sarup@sarup。

Ollama 为可选项。不使用它也能离线运行:钩子和默认的 extractive 模式不会调用它;若请求 semantic、abstractive 或 pipeline,则会回退到抽取式模式,并提供一个 setup 字段说明需要安装什么。 sarup_stats 会显示可用内容,而 /sarup:sarup-setup 会引导你添加 Ollama 和下文所列的模型。

从 PyPI 安装(适用于任意 MCP 客户端)

该软件包在 PyPI 上的名称为 sarup。使用 uv 时无需手动安装;只需让任意 MCP 客户端运行 uvx sarup:

{
  "mcpServers": {
    "sarup": {
      "command": "uvx",
      "args": ["sarup"],
      "env": { "SARUP_DB_PATH": "/home/me/.sarup-cache.db" }
    }
  }
}

在不使用插件的情况下于 Claude Code 中配置:claude mcp add sarup -s user -- uvx sarup。钩子命令为 uvx --from sarup sarup-hook --db <same file as SARUP_DB_PATH>。也可以使用 pip install sarup,它会将 sarup 和 sarup-hook 添加到 PATH。

从克隆的仓库安装

一条命令(创建虚拟环境、安装所有内容、为所有项目注册 MCP 服务,且可重复执行):

.\scripts\setup.ps1 -All      # Windows  (-All also adds the hook, the /sarup-setup skill, pulls Ollama models)
./scripts/setup.sh --all      # Linux / WSL / macOS

提示:-All/--all 会安装全局 /sarup-setup 技能,因此在任何其他机器上,只需在 Claude Code 中输入 /sarup-setup,它就会引导你完成安装。(也可以单独运行 scripts/install-skill.ps1 / install-skill.sh。)

卸载同样干净利落(仅移除 Sarup 添加的内容;-Purge/--purge 还会删除虚拟环境和缓存):

.\scripts\uninstall.ps1       # Windows
./scripts/uninstall.sh        # Linux / WSL / macOS
手动安装
py -3.11 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"

可选的本地大模型模式(semantic / abstractive / pipeline)需要 Ollama:

ollama pull nomic-embed-text     # embeddings → semantic mode
ollama pull gemma4:12b           # rewrite → abstractive / pipeline, 7.6 GB (or gemma4:e4b / gemma3:12b)

注册到 Claude Code

一键设置(推荐)。 自动检测此机器上的路径,探测 Ollama(选择最佳模式和模型),并将配置合并到 .mcp.json / .claude/settings.json 中,不会覆盖已有内容(会先创建 .bak 备份):

.\.venv\Scripts\python.exe scripts\install.py --with-hook --pull
  • 没有 Ollama?它会配置离线 extractive 模式,仍可正常使用。
  • Ollama 正在运行?它会为 sarup_compress 自动选择 nomic-embed-text(语义模式)和最佳的已安装改写模型(gemma4:12b → gemma4:e4b → gemma3:12b → qwen3)。 无论哪种情况,钩子都会保持为 extractive(每次工具调用时都会运行)。--pull 会获取所有缺失的模型。
  • 可重复执行,安全无虞;使用 --global 则会写入 ~/.claude。

手动设置——也可以自行将其添加到 MCP 配置中(例如 .mcp.json 或 ~/.claude.json)。 将 <SARUP_DIR> 替换为克隆此仓库的绝对路径(上述安装程序会自动填入):

{
  "mcpServers": {
    "sarup": {
      "command": "<SARUP_DIR>/.venv/Scripts/python.exe",
      "args": ["-m", "sarup.server"],
      "env": { "SARUP_DB_PATH": "<SARUP_DIR>/.sarup-cache.db" }
    }
  }
}

在 Linux/macOS 上,解释器路径为 <SARUP_DIR>/.venv/bin/python。

或者通过 stdio 直接运行:

.\.venv\Scripts\python.exe -m sarup.server

自动压缩钩子

完全跳过手动工具调用:安装 PostToolUse 钩子,即可在大型 Read/Bash/Grep 输出进入上下文之前对其进行压缩,并缓存原文以供检索。为安全起见,会跳过源代码读取。完整设置说明见 hooks/README.md。

已于 2026 年 10 月修复。 早期版本会将压缩后的文本作为普通字符串返回。 Claude Code 只接受符合工具自身格式的 updatedToolOutput(Bash 使用 {stdout, stderr, …},Read 使用 {type, file: {content, …}}),并会静默丢弃字符串,因此该钩子在任何界面中都不会生效。现在它会保留每种工具的格式;已在 CLI(2.1.289)上验证:模型会收到压缩后的内容和检索哈希。若要查看钩子在你的构建版本中的行为,请将 SARUP_HOOK_LOG 设置为文件路径(每次调用记录一行 JSON)。

插件会为你完成这些设置。从克隆的仓库安装时,将 <SARUP_DIR> 替换为你的克隆路径,或运行 install.py --with-hook:

{
  "hooks": {
    "PostToolUse": [
      { "matcher": "Read|Bash|Grep",
        "hooks": [{ "type": "command",
          "command": "<SARUP_DIR>/.venv/Scripts/sarup-hook --db <SARUP_DIR>/.sarup-cache.db" }] }
    ]
  }
}

隐私与数据

为确保能够恢复,Sarup 会将原始内容缓存在存储中。请注意以下两点:

  • 设置 SARUP_DB_PATH 后,原文会以明文形式写入该 SQLite 文件(不加密)。请将其视为你压缩内容的缓存。
  • 如果压缩的工具输出中含有机密信息(例如 .env 内容或日志中的凭据),这些内容也会进入缓存。自动钩子会跳过源代码/配置文件读取,但 Bash 输出不受此限制——请仔细检查你处理的内容。

*.db 已加入 Git 忽略列表,因此缓存绝不会被提交。若要避免在磁盘上留下任何内容,请勿设置 SARUP_DB_PATH(仅存储在内存中;MCP 服务重启后会丢失缓存,且钩子不会替换输出——详见钩子文档)。

配置

变量默认值含义
SARUP_DB_PATH(内存中)用于持久化跨进程存储的 SQLite 路径。获取钩子内容时必需。
OLLAMA_HOSThttp://localhost:11434Ollama 端点。
SARUP_ABSTRACTIVE_MODEL已安装的最佳模型用于抽象式改写 / 流水线改写的模型。未设置时:依次选择已安装的 gemma4:12b、gemma4:e4b、gemma3:12b、qwen3。
SARUP_EMBED_MODELnomic-embed-text用于语义嵌入的模型。
SARUP_HOOK_MODEextractive钩子压缩模式。auto/semantic 需要 Ollama,每次工具调用耗时约 2 秒。
SARUP_HOOK_MIN_TOKENS400仅当输出至少包含这么多令牌时,钩子才会压缩(基于令牌计数,在不同语言间公平适用)。
SARUP_HOOK_LOG(关闭)用于追加记录的文件,每次钩子调用写入一行 JSON(事件、工具、大小、是否替换)。

项目结构

sarup/
├── src/sarup/
│   ├── server.py       # MCP stdio server — 3 tools
│   ├── compressor.py   # router + modes (extractive/semantic/abstractive/pipeline/auto)
│   ├── thai.py         # PyThaiNLP tokenization, sentence split, TF-IDF
│   ├── semantic.py     # embedding centrality + cosine dedup
│   ├── llm.py          # optional Ollama backend (generate + embed)
│   ├── tokens.py       # real token counting (tiktoken)
│   └── store.py        # CCR store: hash → original (memory + SQLite)
├── hooks/
│   ├── sarup_hook.py   # PostToolUse auto-compression hook
│   └── README.md       # hook install guide
├── bench/benchmark.py  # before/after measurement
├── tests/              # test_thai, test_mcp, test_hook, ...
├── README.md
└── STACK.md            # full stack + techniques

技术栈与技术

Python 3.11 · MCP · PyThaiNLP newmm · tiktoken · Ollama(可选)· SQLite · hatchling · pytest。

各模式背后的技术——TF-IDF 评分、嵌入中心性、级联流水线、内容路由和优雅降级——详见 STACK.md。

测试

.\.venv\Scripts\python.exe -m pytest tests/ -q

测试套件涵盖泰语 NLP、MCP 工具契约、所有模式(包括 Ollama 回退路径)、往返验证保证,以及自动压缩钩子(包括跨进程检索)。

质量评估单独进行,因为它需要模型:bench\eval_qa.py(参见 Claude 还能正确回答吗?)。默认使用本地 claude CLI 运行,也可使用 --backend api 并提供 Anthropic API 密钥;--dry-run 和 --limit 可降低检查成本;完整运行约需调用 Claude 170 次。

发布

  1. 在 pyproject.toml 和 server.json(其中两个位置)中更新 version。
  2. 推送匹配的标签:git tag v0.2.0 && git push origin v0.2.0。publish 工作流 会执行测试、构建,并通过可信发布上传到 PyPI(无需令牌)。
  3. 在 MCP 注册表中列出此版本:先运行 mcp-publisher login github,再运行 mcp-publisher publish(会读取 server.json;本 README 顶部的 mcp-name 注释可证明 PyPI 软件包归属该项目)。

插件无需执行这些操作:它直接从仓库安装,并随每次提交更新。

路线图

  • 将 QA 评估扩展到 8 份以上文档(长工具输出、日志、混合代码),再据此更改默认设置,例如从 auto 改为 semantic。
  • 升级到 mcp 2.x(目前固定为 <2:2.x 移除了 Server.list_tools)。
  • 可选支持 Typhoon 2.1 抽象式改写(受 Ollama 模板修复阻碍)。
  • 按内容自适应调整 target_ratio。
  • 已发布 PyPI 软件包(sarup)并列入 MCP 注册表(io.github.PHUICMT/sarup)。
  • 可作为 Claude Code 插件安装。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。