mcpField
C
compendio-mcp

compendio-mcp

本地服务
github.com/RuloGB记忆与知识55 周前更新

关于 compendio-mcp

compendio-mcp 将项目 Markdown 文档编入本地索引,通过 MCP 为 Agent 提供混合检索和按章节读取。它使用 SQLite 与本地嵌入模型,支持自动同步及多语言文档,无需查询时联网。

主要功能

  1. 01索引项目 Markdown 文档
  2. 02混合关键词与语义检索
  3. 03按章节读取文档内容
  4. 04自动同步文档变更
  5. 05支持多语言本地搜索

适用场景

  1. 01快速定位项目文档中的相关段落
  2. 02检索多个文档目录中的规范与提案
  3. 03减少向 Agent 提供整篇文档的需要

MCP 相关

它作为本地 MCP 服务提供文档概览、片段搜索和文档读取三个工具。MCP 客户端可逐步从语料概览转向搜索,再读取所需章节。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"rulogb-compendio": {
"command": "npx",
"args": [
"-y",
"compendio-mcp"
]
}
}
}
启动命令npx -y compendio-mcp

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

安装包
npmcompendio-mcp1.7.2

工具

3

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

此工具无需参数。

详细介绍

compendio-mcp — 以尽可能少的令牌,将项目文档提供给任意 Agent

以尽可能少的令牌,将项目文档提供给任意 Agent。
作为 MCP 服务公开的本地 RAG 检索层。你的 Agent 不再使用 grep 搜索并倾倒整个文件,而是直接找到相关段落。

npm 许可证 node 平台:macOS | Linux | Windows

MCP 徽章

Glama 上的 compendio-mcp MCP 服务

功能介绍 • 要求 • 快速开始 • 配置 • MCP 工具 • CLI • 工作原理 • 增量同步 • 多语言 • 完整文档


问题

你的 Agent 不知道你的文档。因此它只能尽力而为:先用 grep 搜索,再用 cat 读取一个 400 行的文件,只为回答一个答案就在某个段落里的问题。查了三个文件后,上下文窗口里塞满了噪声,答案依然只是猜测。

附加整个 docs/ 文件夹并不能解决问题——只不过是把浪费提前了。关键字搜索也无济于事:没人会用文档中的确切措辞来提问。

在 OpenCode 中两次提出相同问题。不使用 Compendio 时,Agent 会列出整个仓库、搜索两次并打开三个文件。使用 Compendio 时,只需执行一次搜索并阅读一个章节。

相同的问题、相同的模型,两个答案都正确——区别在于得到答案的成本。
6 次工具调用 • 29 秒 • 32,301 个令牌  →  2 次工具调用 • 12 秒 • 17,684 个令牌。
数据取自 OpenCode 自带的耗时标签和费用提示框,语料库包含 81 份文档。

## Compendio 的功能

Compendio 为 Markdown 文档建立索引,并为任意 AI Agent 提供 3 种工具,让它们精准查找和阅读所需内容。

  • 🔍 混合检索,而非 grep — 关键词搜索可找到确切术语,语义搜索可找到改述内容。Compendio 会同时运行两种搜索并合并结果。
  • ✂️ 设计上节省词元 — 浏览每篇文档约需 10 个词元,搜索只需查找少量片段,阅读时只需读取一个章节。无需读取整个语料库。
  • 🔒 100% 本地运行 — 只需一个 SQLite 文件,在 CPU 上生成嵌入,查询时零网络调用。无需 API 密钥、Docker 或服务,任何数据都不会离开你的设备。
  • ♻️ 保持最新 — 运行中的服务会自动检测文档修改。无需监视进程,也无需手动反复重建索引。
  • 🗣️ 支持多语言 — 可为任何语言的文档建立索引。嵌入模型支持多语言,搜索也不区分变音符号。请参阅多语言。
  • 🧩 零配置 — 适用于任何包含 .md 文件的文件夹。无需必填的 frontmatter,也无需配置文件。如果你的团队已有需要强制执行的分类体系,也可以选择使用文档约定。

要求

  • Node.js ≥ 22.12。
  • 无其他要求。

快速开始

1. 安装。

npm install -g compendio-mcp

更新现有安装:

compendio update

2. 在客户端中将其注册为 MCP 服务:

compendio install-mcp <agent>

支持的 Agent:claude、claude-desktop、cursor、vscode、opencode、codex、zed。

如需手动安装,或要用于此命令不支持的 Agent(Windsurf、Cline、Gemini CLI),请参阅手动安装。

3. 在项目根目录中构建一次索引:

compendio index

就这么简单。无需配置文件,Compendio 会自动发现包含 Markdown 文件的顶层文件夹,无需隐藏的 docs/ 默认目录。将 .compendio/ 添加到你的 .gitignore。

为什么需要这一步。 服务也会在启动时建立索引,所以严格来说,你可以跳过这一步——但首次运行会下载并缓存嵌入模型(几十 MB),触发下载的人需要等待。在这里运行,就能在终端中支付这笔开销,并看到进度条,而不必等到 Agent 首次调用工具时才开始。从那以后,所有操作都会离线进行,索引也会自动保持最新(见下文)。

Windows 注意事项。 某些 MCP 客户端无法直接启动 compendio.cmd 垫片。如果服务因 ENOENT 而无法启动,请使用 "command": "npx" 和 "args": ["compendio-mcp", "serve"]。

配置

完全可选——即使没有配置文件,Compendio 也能正常工作。只有在需要覆盖设置时,才在项目根目录创建 compendio.config.json:

{
  "docsDir": ["docs"],
  "exclude": ["INDEX.md"],
  "db": ".compendio/compendio.db",
  "embeddings": { "provider": "local", "model": "Xenova/multilingual-e5-small" },
  "chunk": { "minTokens": 100, "maxTokens": 480 },
  "search": { "k": 5 },
  "sync": { "throttleMs": 30000 },
  "convention": {
    "mode": "loose",
    "excludedStatuses": [],
    "frontmatterFields": { "type": "type", "module": "module", "status": "status" }
  }
}
键用途
docsDir一个或多个明确指定的文档根目录,相对于项目根目录。始终是数组,不支持单个字符串形式。省略此项或设为 [],即可使用发现模式
exclude索引时跳过的条目:精确路径、裸文件名(在任何位置匹配),或目录前缀(例如,"adr/superseded" 会跳过其下的所有内容)
dbSQLite 索引文件的写入位置
search.k每次搜索默认返回的片段数
chunk片段大小范围,以令牌数为单位
sync.throttleMs自动同步轮次之间的最短间隔,以毫秒为单位(30000 = 30 秒)。这是一个下限,而非计时器——仅限制 serve 的自动触发,不限制手动运行的 compendio sync——参见增量同步
convention可选的文档分类体系——见下文

只声明 convention 块中的部分字段时,会逐字段与默认值合并;未提及的其他字段不会被清除。frontmatterFields 可将 type/module/status 映射到非标准的 frontmatter 键(例如,{ "status": "estado" } 会将西班牙语文档中的 estado: 字段作为 status 读取)。

每个数值键(search.k、chunk.minTokens、chunk.maxTokens、sync.throttleMs)只有在值为大于 0 的有限数时才会生效——search.k 还必须是整数。其他任何值,包括 "480" 这样的带引号数字,都会回退到默认值,效果与未设置该键完全相同,并会报告回退情况:每个 CLI 命令都会将其输出到 stderr,MCP 客户端则会在 docs_overview 的响应中收到报告。embeddings、chunk 或 convention.frontmatterFields 下无法识别的键(例如拼写错误的 maxtokens)也会以相同方式报告。配置无误时不会输出任何报告。

多个文档根目录

声明多个根目录,即可将多个文件夹(如 adr/、rfcs/ 和规范目录)编入同一个可搜索语料库:

{ "docsDir": ["docs", "openspec"], "exclude": ["INDEX.md", "openspec/changes/archive"] }

每个文档的 path 都会添加其根目录的别名作为前缀——别名就是目录本身的名称,因此 docs/x.md 和 openspec/specs/y.md 都会显示为真实的项目相对路径。单个显式根目录和自动发现的根目录也遵循这一规则:路径为 openspec/specs/y.md,而不是 specs/y.md。search_docs、docs_overview、read_doc 和生成的 INDEX.md 都使用这种带前缀的格式;将返回的 path 原样传给 read_doc,始终可以正确解析。

声明的根目录不能冲突:两个根目录解析到同一目录、一个根目录嵌套在另一个根目录中(无论声明顺序如何),或两个根目录具有相同的目录名(因而别名相同),都会在编入任何内容之前被拒绝。已声明但无法读取的根目录(例如路径拼写错误,或某些检出版本中才有的文件夹)会被报告并跳过;同步会继续处理其余根目录,只有当所有已声明的根目录都失败时才会抛出错误。从 docsDir 中移除某个根目录后,下次同步时会删除其中的文档,效果与删除这些文件本身相同。

在自动发现模式下,Compendio 会在每次 index、sync 和 serve 同步时重新扫描顶层文件夹,选取其任意子目录中包含 .md 文件的文件夹,跳过符号链接内容以及 .git、.compendio、node_modules、dist、build 和 coverage 等生成目录或内部目录,并在项目根目录写入 INDEX.md。自动发现采用失败即关闭策略:顶层配置 JSON 格式错误、候选目录树无法读取、遍历或读取失败,或先前已编入索引的自动发现根目录在同步前消失或变成符号链接/联接点,都会在修改索引之前中止。如果先前已编入索引的根目录仍是可读取的目录,即使其中最后一个 Markdown 文件已被删除,也仍会遍历该目录,以便正常处理文件删除。符号链接检查会在扫描/遍历时使用 lstat/realpath,但这并非内核级沙箱;检查与读取之间的文件系统竞态不在处理范围内。--dir <path>(见下文)表示显式模式:它会用指定目录替换整组已声明/自动发现的根目录,并在该目录内写入 INDEX.md。

兼容你的 SDD 框架

规范驱动开发框架会将规划产物保存在 Markdown 中,而这正是 Compendio 会编入索引的内容。将 docsDir 指向框架写入文件的文件夹:

框架配置索引内容
Spec Kit{ "docsDir": ["specs", ".specify"] }specs/NNN-feature/ 下的功能规范、计划和任务,以及 .specify/memory/constitution.md 中的项目章程
OpenSpec{ "docsDir": ["openspec"] }openspec/project.md、能力规范和进行中的变更
Kiro{ "docsDir": [".kiro"] }.kiro/specs/ 下每项功能的 requirements.md/design.md/tasks.md,以及 .kiro/steering/
BMAD{ "docsDir": ["docs"] }PRD、架构、拆分后的史诗和用户故事
框架 + 你自己的文档{ "docsDir": ["docs", "openspec"] }两者都会作为一个可搜索语料库

.specify/ 和 .kiro/ 等隐藏目录会照常编入索引,无论它们是声明的根目录还是通过发现模式找到的目录——会被跳过的是根目录内部以点开头的条目,而不是根目录本身。因此,即使完全没有配置文件,Spec Kit 或 Kiro 项目也已能编入索引。

复制配置前,值得了解以下三点:

  • 根目录的别名取自其目录名,而非你声明的路径。 .kiro/specs 的别名是 specs,因此其中的文档会以 specs/auth/design.md 的形式返回。这也意味着它会与顶层 specs/ 根目录冲突,不能与 Spec Kit 一起使用——应改为声明 .kiro,正如表格中的配置。
  • BMAD 的输出文件夹可配置。 docs 是默认值;BMAD v6 会从自己的配置中读取 output_folder,因此应声明实际设置的目录。
  • 模板会产生干扰。 .specify/templates/ 中存放的是占位脚手架,而不是项目知识。如果你不希望它们出现在搜索结果中,可以添加 "exclude": [".specify/templates", ".specify/scripts"]。
文档约定(可选)

通过 convention.mode 选择两种模式:

  • loose(默认,无需配置)——不会因文件缺少元数据而拒绝文件。标题取自首个 H1(若没有则使用易读的文件名),模块根据文件夹推断;如果存在 frontmatter,则读取 type/status,否则不设置。
  • strict(可选启用)——一种检查器:每份文档都必须包含 H1,以及非空的 type/module/status,并根据项目声明的列表进行验证。未通过检查的文件会被跳过并报告,但不会导致运行中断。
{
  "convention": {
    "mode": "strict",
    "types": ["functional", "adr", "api", "qa", "guide"],
    "statuses": ["draft", "current", "deprecated"],
    "excludedStatuses": ["draft", "deprecated"]
  }
}

excludedStatuses 会按生命周期状态将文档从搜索结果中隐藏——草稿和已弃用页面不会再干扰结果。有关本仓库自身文档所遵循的完整约定,请参阅 docs/documentation-convention.md。

MCP 工具

采用渐进式披露设计:低成本地了解概况 → 低成本地搜索 → 只读取所需内容。

1. docs_overview() — 语料库概览。按类型和模块统计,并为每份文档提供一行说明。每份文档约 10 个令牌。

2. search_docs({ query, type?, module?, tags?, k?, include_excluded? }) — 返回排名靠前的 k 个片段(默认为 5 个,每份文档最多 2 个),每个片段包含路径、章节、摘录和得分。type 是由项目自行定义的开放字符串,并非固定列表。

3. read_doc({ path, section? }) — 读取一个章节或整份文档。对于包含章节且较大的文档(估算令牌数超过约 6,000),会返回精简的 H2/H3 标题大纲,而不是正文,让 Agent 只读取所需章节。若路径不存在,则会返回最相似的 3 个路径,而不是报错,让 Agent 自行纠正,无需盲目重试。

CLI

命令功能
compendio serve通过 stdio 启动 MCP 服务
compendio install-mcp <agent>在指定 Agent 的配置中注册 compendio-mcp
compendio update将 compendio-mcp 更新到 npm 上的最新版本
compendio index完整重建索引
compendio sync从终端运行一次增量同步——仅同步内容发生变化的文档,并实时显示进度。请参阅增量同步
compendio search "..."支持筛选条件的混合搜索:--type、--module、--tags、-k、--all
compendio overview已索引语料库的概览
compendio index-md生成或更新一个合并的 INDEX.md:在发现模式下生成项目根目录中的 INDEX.md,或在第一个显式指定的根目录/--dir 根目录中生成 INDEX.md——每份文档占一行
compendio eval根据 goldenset 衡量检索质量

全局选项 -C, --root <dir>:项目根目录。在 index、sync 或 search 中添加 --lexical,可完全跳过嵌入。index/index-md 上的 --dir <path> 会用该目录替换已配置的 docsDir——不会将其添加进去,且生成的索引仍采用带前缀的路径形式(<dirname>/x.md)。sync 没有 --dir:在增量同步过程中,用这种方式移除根目录会删除其中的文档,而不只是跳过它们(请参阅 compendio sync --help)。

工作原理

docs/**/*.md
     │
     ├─▶ split into fragments at heading boundaries, then bounded to maxTokens
     │
     ├─▶ index each fragment twice ─┬─ full-text (keywords)
     │                              └─ embeddings (meaning)
     │
     └─▶ one file: .compendio/compendio.db

在查询时,系统会分别搜索两个索引,并通过 倒数排名融合合并排名——这是一种基于排名的合并方式,无需盲目调试权重。Agent 会收到数量最少且相关的片段。

Compendio 负责 RAG 中的检索部分。它从不调用大模型,也不会生成任何内容:它会找到正确的段落,然后不再介入。

如果嵌入模型不可用,Compendio 不会崩溃,而是降级为仅关键词搜索,并在响应中说明这一点。

增量同步

你工作期间,文档会不断变化,Compendio 会自动跟上,也可以按需同步。索引有四种刷新方式:

触发方式执行内容
服务启动(compendio serve)执行一次增量同步,在传输连接前启动。首次工具调用会等待同步完成,因此绝不会基于尚未加载的索引作答
任意 MCP 工具调用(search_docs、docs_overview、read_doc)执行一次增量同步,但仅当距离上次同步已过 30 s(默认 sync.throttleMs 为 30000)时才会执行。否则,调用将基于当前索引继续处理
compendio sync从终端手动运行一次增量同步,并显示实时进度。sync.throttleMs 不会限制此命令——无论距离上次同步过去多久,每次调用都会执行一次全新的同步。建议在一次性添加大量文档后运行此命令。
compendio index从头开始完整重建:删除索引并重新创建

它不是定时器。 没有后台定时任务,也没有文件监视器。同步由你的 Agent 发起工具调用或由你运行 compendio sync 来触发;节流间隔是两次自动触发之间的最短间隔,而非执行计划:无人查询的服务不会同步,而一秒内突发的十次调用最多也只会触发一次同步。并发调用会加入正在运行的同步,而不是另行启动一次。

每次增量同步都会将内容哈希与已建立索引的内容进行比较,因此只有新增、更改和删除的文档需要处理——未更改的语料库不会产生任何开销。在 serve 中,如果同步失败,会将错误记录到 stderr,但工具仍会基于当前索引作答;compendio sync 没有这种回退机制,因此同样的失败会导致进程以非零状态码退出。

何时需要完整重建。 compendio index 是唯一会重新建立索引的命令:它会删除并重新创建整个数据库,也是权威的重建方式。在大规模重组后、怀疑索引已偏离实际情况时,或者——这个情况常常令人意外——更改 chunk.minTokens/chunk.maxTokens 后,都应使用它。无论是自动执行还是手动运行 compendio sync,增量同步都只根据内容哈希来识别文档,因此未编辑的文档会保留旧的片段边界,无论当前配置如何。只有完整重建索引(compendio index)才会对未更改的文件应用新的分块设置——请参阅 compendio sync --help,其中也会在最可能需要了解这一点时提醒你注意。

多语言

使用团队日常工作的任何语言编写文档即可,Compendio 不会介意:

  • 约定使用英语,语料库则不必如此。 工具参数(path、type、module、tags、section)、响应字段和工具描述都使用英语,因此任何 Agent 都能轻松读取。文档使用哪种语言与此无关:索引前会移除 frontmatter 键,而 FTS5 分词器不带特定语言的词干提取器。
  • 非英语 frontmatter 键会映射回对应字段。 如果文档使用 estado: 而非 status:,convention.frontmatterFields 会将其转换。
  • 重音符号会得到妥善处理。 搜索不区分变音符号,因此 validación 和 validacion 会匹配。区分重音的搜索会悄无声息地漏掉结果。
  • 嵌入模型支持多语言(Xenova/multilingual-e5-small),因此单语言和混合语言语料库的索引与检索效果相同。

ejemplos/ 中附带的参考语料库和评估集使用西班牙语——这是有意为之,用以证明英语代码库和工具约定也能无损检索非英语文档。

与 grep 相比,语义检索提升了多少?

使用 compendio eval 在示例语料库(ejemplos/:11 份文档、29 个分块、没有配置文件——即零配置路径本身)及其包含 22 个真实问题的黄金集上进行测量:

moderecall@5MRRfailures
hybrid1.000.9430
keyword-only0.950.8561
  • 当问题使用语料库中的术语时,关键词搜索已经表现出色。
  • 差距体现在改述和同义词上:«¿Qué endpoint hay que llamar para crear un lead?» 在没有嵌入的情况下会落到前 5 名之外,而语义检索会将其找回。与匹配文档完全没有词汇重叠的问题,只能靠语义检索解决。
  • 速度:模型预热后,混合搜索的响应时间为 5–20 ms。

compendio eval 可随时复现此表格;它也是调整分块和 k 的工具,无需猜测。

架构

六边形架构:核心不依赖 SQLite、transformers.js 或文件系统。

src/
├── domain/            # pure, no dependencies: model, chunking, ranking, convention policy
├── application/       # use cases
├── infrastructure/    # adapters: SQLite, markdown parsing, filesystem, embeddings
├── composition.ts     # composition root — start here to see the whole app
├── cli.ts             # input adapter: commander
└── server.ts          # input adapter: MCP server (stdio)

所有外部依赖都位于 src/domain/ports.ts 中的端口之后。替换向量存储或嵌入提供方,只需在一个适配器中局部修改,无需重写。

开发

npm install
npm run build       # compiles to dist/
npm test            # vitest: domain, adapters and integration
npm run typecheck   # tsc --noEmit
npm run dev -- ...  # CLI without compiling (tsx)

集成测试使用确定性嵌入提供方(无需下载),并针对真实的 ejemplos/ 语料库运行。

无需安装此软件包,即可使用 CLI 测试随附的示例语料库:

node dist/cli.js --root ejemplos index
node dist/cli.js --root ejemplos search "¿cuándo se considera duplicado un lead?"

此仓库附带一个 .mcp.json,用于提供 ejemplos/ 语料库,因此无需任何配置,就能通过 Claude Code 试用这些工具。

许可证

MIT © Raúl García Barciela

评论

支持 Markdown

第一次接触 MCP?

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

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