local-rag
local-rag-mcp
一个用于本地文档语料库语义搜索的只读 MCP 服务器——设备端嵌入(Ollama)、本地 Chroma 存储,数据不会离开主机。 专为语料库内容不能发送到云 API 的环境而构建,并以相同方式服务于所有 MCP 客户端(Claude Code、Codex,以及任何支持该协议的工具)。
这是 claude-code-session-memory 的 MCP 服务版姊妹项目:相同的嵌入模型、相同的指令前缀机制、相同的测量方法——一个检索底座,两个消费者。session-memory 的 README 包含了完整的评估故事(预先设定的基准、对抗性查询集、回归归因);本仓库将同样的纪律应用于服务器而非钩子。
工具
工具 | 功能 |
| 语义搜索:最多返回 k 个块,包含源路径、标题路径、余弦分数和文本 |
| 已索引文档的文本(上限 50k 字符)——刻意不是通用文件系统读取器 |
两者均标注为只读。失败时返回结构化的 {"error": ...} 负载——依赖故障只会降低工具能力,绝不会影响会话。
快速开始
git clone https://github.com/wesglockzin/local-rag-mcp
cd local-rag-mcp
python3 -m venv .venv && ./.venv/bin/pip install -r requirements.txt
ollama pull embeddinggemma
# Index the included sample corpus (or point RAG_CORPUS_DIR at your own)
./.venv/bin/python ingest.py
# Register with Claude Code — ABSOLUTE paths on both sides: the MCP client
# launches the server from its own working directory, so relative paths are
# the #1 install failure.
claude mcp add local-rag -- "$PWD/.venv/bin/python" "$PWD/server.py"然后向 Claude Code 询问语料库已知的内容——"sev-1 时谁会收到分页通知?"——并观察它调用 search_corpus。
配置通过三个环境变量完成:RAG_CORPUS_DIR(默认:./sample-corpus)、RAG_STORE_DIR(默认:~/.local-rag-mcp/store)、OLLAMA_HOST。
值得保留的设计决策
服务器是只读的,绝不创建存储。 摄取负责创建。一个只读服务器若悄悄初始化空存储,会把"你忘了摄取"变成"搜索返回空结果"——这是更糟糕的失败,因为它看起来像答案。
先嵌入后替换的摄取。 只有当每个新块都成功嵌入后,旧块才会被删除;文件中途遇到 Ollama 故障绝不会导致该文件从索引中缺失。
退役文档是预过滤,而非后过滤。 在 frontmatter 中带有
lifecycle: superseded的文档会在向量搜索之前通过where子句被排除,因此它永远不会占用结果槽位。摄取会在每个块上显式写入 lifecycle 键——在某些存储版本中,缺失的键会绕过$ne,因此缺失不是安全默认值。(此规则的原始版本是因为一次重新摄取静默擦除了标记,导致退役文档重新出现在结果中;现在有回归测试固定了它。)get_file对符号链接进行了加固。 只有已索引的路径可读,并且解析结果与摄取时不同的路径会被拒绝——否则任何能将语料库文件替换为符号链接的人都能通过服务器读取语料库之外的内容。如果文件在磁盘上不存在(语料库移动、不同机器),则按块顺序提供已索引的块文本。存储始终是机器本地的。 它是一个基于 SQLite 的实时数据库;云同步会进行整文件替换,没有事务感知能力,失败模式是未写入的机器上索引静默损坏。同步语料库和此配方;每台机器构建自己的存储。
每次摄取都会将语料库的 git 提交标记写入其输出,因此索引构建可以精确固定到产生它的语料库状态("存在未提交更改"本身就是一个警告标签)。
不对称嵌入前缀(EmbeddingGemma 文档中记录的查询/文档指令前缀)应用于搜索的两侧,与姊妹项目测量的机制一致——在那里,带前缀的检索比原始检索高出两位数,而混合带前缀/原始向量得分处于未校准的区间。
语料库约定
任何 *.md 文件目录都可以。三个可选的 frontmatter 键:
rag: false # exclude this file from the index entirely
rag_chunk: headings # heading-split a long document (default: whole-file)
lifecycle: superseded # keep the file, hide it from search提交的 sample-corpus/ 涵盖了所有三种情况以及一个纯文本文件——六个虚构的平台团队文档,由 tools/gen_sample_corpus.py 生成(CI 验证提交的语料库与生成器一致)。
测试
pip install pytest && python -m pytest -q无需 Ollama,无需存储:嵌入器被桩替换,集合是记录调用的假对象。测试覆盖了契约——参数验证、lifecycle 预过滤以 where 子句形式到达存储、只读不创建保证、符号链接拒绝、先嵌入后替换的顺序(包括嵌入器故障路径)、mtime 容差跳过,以及分块器的合并和超限拆分行为。
已知限制
信任模型: 服务器读取你指向的任何语料库,客户端将检索到的文本注入模型上下文。只索引你信任的内容——恶意文档是提示注入向量;服务器负责检索,不负责净化。Stdio MCP 没有认证层;它继承启动它的进程的信任。
分数仅在同一嵌入机制内可比较;校准的"弱匹配"下限是特定于语料库的(姊妹仓库记录了校准方法)。
一个存储,一个集合——多语料库路由不在本仓库范围内。
没有混合关键词+向量阶段;释义余量已在姊妹仓库中测量并记录。
许可证
MIT——参见 LICENSE。
作者
Wes Glockzin
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Securely search and manage workspace context files for AI agents and teams.
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wesglockzin/local-rag-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server