devdocs rag mcp
一个本地MCP服务器,为Claude Code提供RAG驱动的文档搜索。将任何文档语料库索引到本地向量数据库中,然后在Claude Code会话中进行语义搜索——没有外部API,没有网络暴露。
将任何文档语料库(HTML、Markdown或PDF)编入本地向量数据库,并在Claude Code会话中进行语义搜索。
______________________________________________________________________
运作原理
Documentation (HTML, PDF, Markdown)
|
v
Ingestion pipeline
(parse → chunk → embed → store)
|
v
ChromaDB (local)
|
v
FastMCP RAG Server Claude Code服务器在stdio上作为Claude Code的子进程运行。当Claude需要文档时,它会调用其中一个MCP工具(search_docs, list_collections等),其使用Nomic Embed Text V2在本地嵌入查询,并从ChromaDB返回排名块。
______________________________________________________________________
需求
- Python 3.11+
- 紫外线 (包管理器)
______________________________________________________________________
设置
git clone https://github.com/your-username/devdocs-rag-mcp.git
cd devdocs-rag-mcp
uv sync --extra dev验证安装:
uv run python -c "from devdocs_rag.server import mcp; print('OK')"______________________________________________________________________
命令
以下三个uv命令可用 uv sync:
| 命令 | 目的 |
|---|---|
uv run crawl-docs | 抓取网站并将HTML保存到 data/raw// |
uv run ingest-docs | 将本地文件摄取到命名的ChromaDB集合中 |
uv run devdocs-rag-server | 启动MCP服务器(由Claude Code使用) |
爬行
# Crawl a site — defaults to the seed URL's domain as the allowed prefix
uv run crawl-docs my-docs https://example.com/docs
# Multiple seed URLs (comma-separated)
uv run crawl-docs react-docs https://react.dev/learn,https://react.dev/reference
# Restrict crawling to a URL subtree
uv run crawl-docs react-docs https://react.dev/learn --allowed-prefix https://react.dev/learn
# Tune crawl behaviour
uv run crawl-docs my-docs https://example.com/docs --limit 200 --depth 3 --delay 1.0文件保存到 data/raw// 作为平面HTML文件。作为第一个参数传递的集合名称将成为目录名称,并用作建议的 --collection 下一步的价值。
摄入
# Ingest a directory of HTML/Markdown/PDF files into a named collection
uv run ingest-docs data/raw/my-docs/ --collection my_docs
# Let the pipeline infer doc_type from path segments (api_reference, guide, etc.)
uv run ingest-docs data/raw/my-docs/ --collection my_docs --infer-doc-type
# Tag every file with a single doc type
uv run ingest-docs data/raw/my-docs/api/ --collection my_docs --doc-type api_reference
# Drop and re-ingest from scratch
uv run ingest-docs data/raw/my-docs/ --collection my_docs --drop摄取是幂等的——重新运行会替换相同文件的现有块。
______________________________________________________________________
运行服务器
通过MCP Inspector进行交互式开发和工具测试:
uv run fastmcp dev inspector src/devdocs_rag/server.py______________________________________________________________________
连接到克劳德代码
编辑 .mcp.json 在项目根目录下为您的机器设置正确的绝对路径,然后向Claude Code注册:
claude mcp add devdocs-rag --scope local或者将Claude Code指向 .mcp.json 直接以项目根目录打开此目录。Claude Code会自动接收它。
验证服务器是否已注册:
claude mcp list
claude mcp get devdocs-rag连接后,Claude Code可以调用 search_docs, list_collections, collection_stats, get_doc_context,以及 ingest_docs 直接在会议期间。
______________________________________________________________________
配置
所有设置都通过前缀为的环境变量进行控制 DEVDOCS_.把它们放进去 .mcp.json 在...之下 env,或在运行脚本之前导出它们。
| 变量 | 默认值 | 描述 |
|---|---|---|
DEVDOCS_CHROMA_DB_PATH | ./data/chroma | ChromaDB存储文件的位置 |
DEVDOCS_EMBEDDING_MODEL | nomic-ai/nomic-embed-text-v2-moe | 拥抱脸部模型ID |
DEVDOCS_EMBEDDING_BACKEND | sentence-transformers | sentence-transformers 或 ollama |
DEVDOCS_CHUNK_SIZE | 800 | 每个区块的目标令牌 |
DEVDOCS_CHUNK_OVERLAP | 100 | 连续块之间的重叠 |
DEVDOCS_DEFAULT_N_RESULTS | 5 | 默认搜索结果数 |
DEVDOCS_LOG_LEVEL | INFO | 日志级别(仅限stderr) |
______________________________________________________________________
项目结构
devdocs-rag-mcp/
├── pyproject.toml # Dependencies and entry points
├── .mcp.json # MCP server registration for Claude Code
│
├── src/devdocs_rag/
│ ├── server.py # FastMCP server — all tool definitions
│ ├── config.py # Configuration (env vars + defaults)
│ ├── embedding.py # EmbeddingModel wrapper
│ ├── store.py # DocStore — ChromaDB wrapper
│ ├── ingest/
│ │ ├── pipeline.py # Orchestrates load → chunk → embed → store
│ │ ├── loaders.py # Document loaders (HTML, PDF, Markdown)
│ │ ├── chunkers.py # Two-pass hybrid chunking strategy
│ │ └── metadata.py # Metadata enrichment
│ └── utils/
│ └── logging.py # Stderr-only logging setup
│
├── scripts/
│ ├── ingest.py # CLI for ingestion (uv run ingest-docs)
│ └── crawl_docs.py # General-purpose website crawler (uv run crawl-docs)
│
├── tests/ # pytest test suite
├── data/chroma/ # ChromaDB persistent storage (gitignored)
└── data/raw/ # Raw documentation files (gitignored)______________________________________________________________________
检查数据库
在终端中交互式浏览集合(使用箭头键导航, s 搜索):
uv run chroma browse samsung_tv --path data/chroma或者直接从Python查询:
# Collection summary
uv run python -c "
from devdocs_rag.embedding import EmbeddingModel
from devdocs_rag.store import DocStore
store = DocStore(embedding_model=EmbeddingModel())
s = store.collection_stats('samsung_tv')
print('docs:', s.doc_count, '| types:', s.doc_types)
" 2>/dev/null
# Manual search
uv run python -c "
from devdocs_rag.embedding import EmbeddingModel
from devdocs_rag.store import DocStore
store = DocStore(embedding_model=EmbeddingModel())
for r in store.search('samsung_tv', 'remote control key events', n_results=3):
print(f'score={r.relevance_score:.3f}', r.content[:200])
" 2>/dev/null______________________________________________________________________
添加新文档集
每个文档集都有一个独立的名称 收集 在ChromaDB中。集合是孤立的——添加React Native文档对Samsung TV集合没有影响,Claude可以搜索其中之一或两者。
第一步——获取文档
您需要将文档作为本地文件(HTML、Markdown或PDF)。如何获得它们取决于来源:
选项A:使用内置爬虫
uv run crawl-docs react-native https://reactnative.dev/docs/getting-started保存到 data/raw/react-native/.使用 --allowed-prefix 为了将爬行限制到子树, --limit 限制页数,以及 --depth 以控制递归深度。
选项B:克隆文档仓库
许多项目在GitHub仓库中以Markdown的形式发布文档:
git clone --depth=1 https://github.com/sveltejs/svelte.dev data/raw/svelte第二步——摄入一个命名集合
# Ingest with per-file doc_type inference (recommended)
uv run ingest-docs data/raw/react-native/ --collection react_native --infer-doc-type
# Or apply a single doc_type to everything
uv run ingest-docs data/raw/svelte/documentation/ --collection svelte --doc-type guide这 --infer-doc-type 标志将每个文件分类为 api_reference, guide, spec等。当源站点使用标准目录结构时非常有用。使用 --doc-type 当所有文件类型相同或路径不结构化时。
摄入是幂等的——重新运行会更新现有的块。
步骤3——验证集合
# Check what was indexed
uv run python -c "
from devdocs_rag.embedding import EmbeddingModel
from devdocs_rag.store import DocStore
store = DocStore(embedding_model=EmbeddingModel())
s = store.collection_stats('react_native')
print('docs:', s.doc_count, '| types:', s.doc_types)
" 2>/dev/null
# Test a search
uv run python -c "
from devdocs_rag.embedding import EmbeddingModel
from devdocs_rag.store import DocStore
store = DocStore(embedding_model=EmbeddingModel())
for r in store.search('react_native', 'how to use FlatList', n_results=3):
print(f'score={r.relevance_score:.3f}', r.content[:200])
" 2>/dev/null步骤4——在Claude代码中使用它
无需重新启动服务器。新的集合可以通过现有的MCP工具立即获得:
search_docs("how do I handle navigation?", collection="react_native")
list_collections() ← confirms the new collection is present您可以使用以下命令搜索特定收藏 collection 参数,或省略它以一次搜索所有索引集合。
______________________________________________________________________
运行测试
uv run pytest tests/
# RAG accuracy evaluation
uv run python evals/run_eval.py______________________________________________________________________
堆栈
| 组件 | 选择 |
|---|---|
| MCP框架 | FastMCP |
| 矢量存储 | ChromaDB |
| 嵌入模型 | 标称嵌入文本V2(305M参数,本地) |
| 嵌入运行时 | 句子转换器 |
| 文档解析 | 非结构化+BeautifulSoup |
| 分块 | LangChain文本拆分器 |
| 包管理器 | uv |
