doc-search-mcp
Local MCP server that indexes PDFs, EPUBs, HTML, Markdown and text files and makes them searchable by LLM coding agents — keyword (FTS5/BM25), semantic, and hybrid search, entirely on your own machine.
Install / Use
claude mcp add nburns -- npx -y github:nburns/doc-search-mcpIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
AI & Machine LearningSupported Platforms
Our assessment of doc-search-mcp
doc-search-mcp scores 81/100 on our quality scale, 730th of 956 AI & Machine Learning skills we index.
Its MCP Server is 9.5 KB long, well organised into 18 sections with 8 code examples: a thorough specification that gives an agent plenty to work with.
It has 3 GitHub stars, so there is little community track record yet; judge it on its content.
Maintenance, license and trust
- The repository was last updated about 2 months ago, so doc-search-mcp is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 80/100, with 2 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
doc-search-mcp compared with similar skills
All 4 of these similar skills score higher than doc-search-mcp; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| doc-search-mcp (this skill)by nburns | 81 | 3 | 2mo ago | MCP Server |
| claude-memby thedotmack | 100 | 101.9k | today | CLAUDE.md |
| Agent-Reachby Panniantong | 100 | 100.2k | today | CLAUDE.md |
| Understand-Anythingby Egonex-AI | 100 | 87.2k | 8d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 76.7k | today | CLAUDE.md |
Frequently asked questions
- How do I install doc-search-mcp?
- Run
claude mcp add nburns -- npx -y github:nburns/doc-search-mcp. The install tabs above show the steps for each supported agent. - Which AI agents does doc-search-mcp work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is doc-search-mcp safe to use?
- It declares no license and scores 80/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is doc-search-mcp still maintained?
- The repository was last updated about 2 months ago, so doc-search-mcp is actively maintained.
Skill content
View source on GitHubdoc-search-mcp
A local MCP server that indexes PDFs, EPUBs, HTML and text files and makes them searchable via MCP tools. Designed for LLM coding agents that need to query large local document collections without uploading them to the cloud.
Features
- Indexes PDFs (with TOC detection), EPUBs, HTML, Markdown, and plain text
- Keyword search via FTS5/BM25 and semantic search via vector embeddings
- Hybrid search merging both with Reciprocal Rank Fusion
- Documents organized into named categories
- Same content at multiple paths shares one index record (deduplication by checksum)
- Async indexing, one job per file, with progress tracking via job IDs
- Re-running an index is cheap and idempotent: unchanged files cost one
stat - Startup health checks with per-file change detection
- Accessible over a local network via SSE transport
Install
git clone git@github.com:nburns/doc-search-mcp.git
cd doc-search-mcp
uv sync
uv run doc-search-mcp
Requires Python 3.10+. All dependencies are installed by default — no extras needed.
Connect to Claude Code
Start the server, then register it:
claude mcp add --transport sse --scope user doc-search http://localhost:8080/sse
Or, to share it with everyone working in a repo, commit a .mcp.json at that repo's root:
{
"mcpServers": {
"doc-search": {
"type": "sse",
"url": "http://localhost:8080/sse"
}
}
}
Use the machine's hostname or IP instead of localhost if connecting from another machine.
In a new Claude Code session, run /mcp to confirm the server is connected and its tools are listed.
No auth or TLS. Only expose on trusted local networks.
Configuration
Config file lives at ~/.doc-search/config.toml. All settings are optional — defaults work out of the box.
[server]
transport = "sse" # sse | stdio
host = "0.0.0.0"
port = 8080
[storage]
backend = "sqlite" # sqlite is the only implementation
db_path = "~/.doc-search/index.db"
[embeddings]
backend = "auto" # auto | fastembed | sentence-transformers | ollama | none
model = "nomic-ai/nomic-embed-text-v1.5"
ollama_url = "http://localhost:11434"
# cache_dir = "~/.doc-search/models" # unset = fastembed's temp dir, re-downloaded on reboot
enable_cpu_mem_arena = false # true trades ~30GB memory spikes for throughput
[search]
default_mode = "auto" # auto | keyword | semantic | hybrid
default_limit = 10
rerank = false
[chunking]
target_tokens = 400
overlap_tokens = 50
max_toc_depth = 2
max_file_size_mb = 500
[performance]
extraction_workers = 0 # 0 = auto (CPU count)
embedding_batch_size = 32
embedding_queue_size = 256
max_concurrent_jobs = 3
embedding_max_padded_tokens = 16384 # batch size x longest chunk; this is what bounds peak memory
extraction_timeout = 1800 # seconds per file; covers large OCR jobs
[startup]
check_on_startup = true # read-only integrity check, runs after the port opens
[profiling]
enabled = true # one memory sample per interval to the log below
interval_s = 60
path = "~/.doc-search/mem-profile.jsonl"
Environment variable overrides:
| Env var | Setting |
|---------|---------|
| DOC_SEARCH_DB | storage.db_path |
| DOC_SEARCH_BACKEND | storage.backend |
| DOC_SEARCH_POSTGRES_URL | storage.postgres_url (accepted, but no Postgres backend exists yet) |
| DOC_SEARCH_EMBEDDER | embeddings.backend |
| DOC_SEARCH_OLLAMA_URL | embeddings.ollama_url |
| DOC_SEARCH_EMBED_CACHE | embeddings.cache_dir |
| DOC_SEARCH_CPU_MEM_ARENA | embeddings.enable_cpu_mem_arena |
| DOC_SEARCH_DEFAULT_MODE | search.default_mode |
| DOC_SEARCH_PORT | server.port |
| DOC_SEARCH_MEMPROFILE | profiling.enabled |
| DOC_SEARCH_MEMPROFILE_INTERVAL | profiling.interval_s |
| DOC_SEARCH_MEMPROFILE_PATH | profiling.path |
Embeddings
Backend auto-detection order:
DOC_SEARCH_EMBEDDERenv var if set- CUDA available →
sentence-transformers - Default →
fastembed(CPU, no PyTorch required) ollama— opt-in via confignone— keyword-only search, no vectors
Set backend = "none" to skip embedding entirely and use keyword search only. This makes indexing much faster and is a good default for technical documentation with precise terminology.
MCP Tools
Indexing
| Tool | Args | Description |
|------|------|-------------|
| index_path | path, category | Scan a file or directory and queue one job per file needing work. Returns the scan summary and its job IDs. Safe to re-run — unchanged files are skipped, so this is also how you re-index after edits. |
| remove_document | path, category | Remove a path from the index. Also how you force a rebuild of one file. |
Search
| Tool | Args | Description |
|------|------|-------------|
| search | query, category, mode, limit, file_type, path_prefix | Search documents. |
| search_in_document | query, path, category, limit | Search within one file. |
| get_chunks | ids, category | Retrieve chunks by ID to expand context around a result. |
Documents
| Tool | Args | Description |
|------|------|-------------|
| list_documents | category | All indexed docs with metadata. |
| list_categories | — | Categories with doc/chunk counts and last indexed timestamp. |
| get_stats | category | DB size, document count, chunk count. |
Jobs
| Tool | Args | Description |
|------|------|-------------|
| get_job_status | job_id | Progress report for one file's job. The 8-character prefix is accepted anywhere a job_id is. |
| list_jobs | status, path_prefix, limit | Live jobs merged with DB history. Filter by path_prefix to follow a single import. |
| cancel_job | job_id | Cancel one queued or running job. There is no bulk cancel — restart the server to stop a large import. |
| resume_job | job_id | Re-run a failed or cancelled job. Files already indexed are skipped. |
Maintenance
| Tool | Args | Description |
|------|------|-------------|
| check_index | category | Full health report — changed, missing, and unindexed files. |
| acknowledge_warnings | ids | Suppress known warnings until next startup. |
| get_config | — | Current config and active backend. Read-only; edit config.toml and restart to change it. |
| inspect_pdf | path | Per-page extraction stats for one PDF: which pages carry text, character/word counts, TOC structure. Use to check coverage before or after indexing. |
Supported Formats
| Format | Notes |
|--------|-------|
| PDF | TOC-aware chunking; falls back to per-page if no TOC. Image-only PDFs are automatically OCR'd via tesseract if available. |
| EPUB | Per-chapter extraction |
| HTML | .html/.htm; one section per <h1>-<h6>. Scripts, styles and site furniture (nav, header, footer, aside, form) are dropped. Both suffixes store file_type = html |
| Web archive | .webarchive (Safari "Save As → Web Archive"). The saved page is extracted exactly as HTML above; embedded images, stylesheets, scripts and iframes are skipped. Stores file_type = webarchive, and titles the document from the page's own <title> plus its originating host |
| Markdown | Heading-aware splitting on ## |
| Plain text | Paragraph block splitting |
OCR for image-only PDFs
If a PDF has no text layer, the extractor automatically falls back to OCR using tesseract. Install the system binary to enable it:
sudo apt install tesseract-ocr # Debian/Ubuntu
brew install tesseract # macOS
Without tesseract, image-only PDFs fail with a clear error rather than silently producing an empty index entry.
Running it as a service
deploy/install.sh installs three system units (not user units — a user manager is torn down at logout, which took the server offline for 24 hours once):
| Unit | Role |
|------|------|
| doc-search-mcp.service | The server, running as the doc-search system account |
| doc-search-sweep.timer | Fires every 30 minutes, Persistent=true |
| doc-search-sweep.service | Oneshot: calls index_path over the watched tree, exits once jobs are queued |
To watch another tree, add an ExecStart= line to the sweep unit.
CLI helpers
mcp_call.py calls a single tool against a running server (DOC_SEARCH_URL, DOC_SEARCH_TIMEOUT override the target). The Makefile wraps the common ones:
make import SRC=~/books CATEGORY=reading # index a tree (SRC=, never PATH= — Make inherits PATH)
make list CATEGORY=reading # list indexed documents
make jobs STATUS=running # list jobs; SRC=<prefix> filters to one import
make status JOB=1a2b3c4d # progress for one job (8-char prefix is fine)
make sweep # run the incremental sweep now
make memprofile N=20 # summarise the last N memory samples
make help # all targets
Dev
uv run pytest # tests
uv run ruff check src # lint
uv run ruff format src # format
uv run --with mypy mypy src/doc_search_mcp/ # type check
uv run pyright # second type check
Both type checkers are clean; keep them that way.
Run the server from a checkout:
uv run doc-search-mcp # production mode
uv run doc-search-mcp --reload # auto-reload on source changes
uv run doc-search-mcp --port 9090 # override port
AGENTS.md covers the architecture: the job model, the shared embedding pipeline, and the memory findings behind the current defaults.
Related Skills
claude-mem
101.9kPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More
Agent-Reach
100.2kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
Understand-Anything
87.2kGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.
headroom
76.7kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
