Skip to main content
Glama
SodaShikenn

doc-search

Official
by SodaShikenn

doc-search — Hybrid Search + RAG Chat for Document Repositories

A hybrid search engine combining keyword search (BM25) × vector search (semantic search) for an internal document repository (glossary, review criteria, design documents), plus a RAG chat (Claude API, model selection, streaming output) built on top of it.

The UI design follows SodaShikenn/LLM-RAG_KBQA (left sidebar: model selection / knowledge settings / conversation history; right: chat + Send / Cancel).

Four ways to use it:

  1. RAG chat (/) — Pick a model and ask a question. Search → stream answers with citations

  2. Search explorer (/search.html) — Incremental search, KW/VEC/RRF score display

  3. CLIdocsearch search "..."

  4. MCP server — Registered as a tool for Claude Code (Agentic RAG)

Setup (lightweight: no ML dependencies, ~30MB)

cd doc-search
brew install uv        # 未導入の場合
uv venv --python 3.12 .venv
uv pip install -p .venv/bin/python -r requirements.txt
cp .env.example .env   # ANTHROPIC_API_KEY を記入(チャット用)

Only when using a local embedding model (e5 / bge-m3), add the heavy ML stack:

uv pip install -p .venv/bin/python -r requirements-local.txt

Related MCP server: LLMDoc

Usage

# 1) インデックス構築
.venv/bin/python -m docsearch index sample_docs                    # 自動選択
.venv/bin/python -m docsearch index /path/to/docs --embedder voyage  # クラウド埋め込み

# 2) サーバー起動 → http://127.0.0.1:8765
.venv/bin/python -m docsearch serve --port 8765

# 3) CLI検索
.venv/bin/python -m docsearch search "解約率" --mode vector

Even without an API key, you can verify the chat UI behavior with the "Demo (offline)" model.

Choosing an embedding model (--embedder)

name

Location

Weight

Characteristics

voyage

Cloud

Zero local dependencies

voyage-3.5. Anthropic's recommended embedding partner. Top-tier quality. Requires VOYAGE_API_KEY. Note that document text is sent externally, so approval is needed

e5

Local

~470MB + torch

multilingual-e5-small. Fully local, a safe default for Japanese/English support

e5-large

Local

~2.2GB + torch

Higher-accuracy version of e5

bge-m3

Local

~2.3GB + torch

The strongest local-class multilingual model. However, it is the opposite of "lightweight" and CPU inference is also slow

hash

Local

Zero dependencies

Character-hash (no semantic search, degraded mode)

How to choose: If you want both quality and lightweight setup, go with voyage (when cloud is permitted). If it must be fully local, use e5; for higher accuracy, bge-m3 (if you can tolerate the weight). BM25 (lexical matching) always runs locally, so the embedding's role is only to absorb "paraphrases" — model differences only matter there, and bge-m3's multi-vector/sparse features are unnecessary in this setup.

How chat (RAG) works

質問 → 検索の深さ(effort)を解決(auto は確信度シグナルで自動判断)
     → 検索実行(hard は選択モデルがクエリを言い換え → 全変種を検索して RRF 融合)
     → system プロンプトに参照資料として注入([n] path:line 付き)
     → Claude API へストリーミング要求(output_config.effort も連動)
     → data: {status|sources|delta|done|error} を SSE 配信
     → UI が逐次描画 + 「なぜこの検索をしたか」の説明 + 引用チップ。会話は localStorage

Search depth (effort) — hiding hybrid/keyword/vector

Users don't choose IR terminology. They only choose "how thoroughly to search," and what was actually done is shown in Japanese below the answer (e.g., "Auto → Thorough — no keyword matches… generated paraphrases and searched deeply").

effort

Behavior

When to use

Auto (auto)

Probes once, then auto-selects easy/medium/hard based on confidence

Default. Use this when unsure

Easy (easy)

One hybrid search, top 4 results. Model effort is also low

Direct term lookup. Fastest and cheapest

Medium (medium)

Standard hybrid search, 6 results

Previous default behavior

Thorough (hard)

The selected model generates 3 paraphrases → searches with all queries and fuses via RRF, 10 results. Model effort is high

Questions where the wording differs from the documents (e.g., "pay for overtime" → overtime premium)

Auto decision signals: presence of keyword matches, strength of vector similarity, and top matches from both searches. If paraphrase generation is unavailable (Demo model / no key set), hard automatically degrades to "expanded result count." The raw search modes (keyword/vector/hybrid) remain available to engineers in /search.html and the CLI.

  • Models: Claude Opus 5 (default) / Sonnet 5 / Haiku 4.5 / Demo (offline)

  • Opus 5 enables server-side refusal fallback (when the model declines to answer for safety, it automatically falls back to an alternative model within the same request)

  • The generation API uses the official Anthropic SDK. The key is ANTHROPIC_API_KEY in .env

Integration with Claude Code (MCP / Agentic RAG)

.mcp.json (in the target repository or home directory):

{
  "mcpServers": {
    "docsearch": {
      "command": "/ABSOLUTE/PATH/doc-search/.venv/bin/python",
      "args": ["-m", "docsearch.mcp_server"],
      "env": { "DOCSEARCH_INDEX": "/ABSOLUTE/PATH/doc-search/index" }
    }
  }
}

Tools: search_docs(query, mode, k) / docs_repo_info(). Since Claude Code itself handles query planning → re-search → file reading → cited answers, Agentic RAG works inside the editor, separate from the chat UI.

Swapping in real data (on a machine with access permissions)

This repository only contains placeholders (sample_docs). The link to real data and the internal repository is swapped on the machine that has access, without any code changes. Priority order:

  1. Environment variables (Docker uses these): in .env, set DOCSEARCH_DOCS_HOST=/path/to/real-docs (the mount source into the container) and DOCSEARCH_GITHUB_BASE=https://github.example.com/org/repo/blob/main

  2. Config file (local execution): cp datasource.example.json datasource.json then edit docs_dir / github_base / embedderdocsearch index (no arguments). datasource.json is gitignored, so pointers to the internal repository are never pushed

  3. Placeholder: if nothing is configured, sample_docs/ is indexed

The resolution logic is consolidated into a single function, get_datasource(), in docsearch/datasource.py.

Search results, citation chips, and [path:line] in answers become deep links to the corresponding lines on GitHub in the document repository (in the blob/<SHA-at-index-time>/path#L<line> format, so line anchors don't break even as the repository advances).

  • Auto-detected at index time from the docs repository's git remote (GHE also works)

  • If auto-detection fails (e.g., when docs are mounted in Docker), set DOCSEARCH_GITHUB_BASE=https://github.com/o/r/blob/main/docs in .env (or --github-base in the CLI)

Search engine design points

  • Japanese keyword search: CJK strings are expanded into bigrams and indexed in SQLite FTS5. On the query side, bigram phrase search handles adjacent matching (works without a morphological analyzer)

  • RRF fusion: BM25 scores and cosine similarity are scale-incompatible, so they are fused by rank

  • Breadcrumbs on chunks: The heading hierarchy is prepended to each chunk (in the glossary, headings = terms)

Interesting queries to try

Query

Expected result

消費税区分

Keyword search hits the glossary directly

解約率

Vector search discovers "churn rate" (paraphrase)

仕訳の二重登録を防ぐ仕組みは? (chat)

Answers citing idempotency / Idempotency-Key

テナント 漏えい

Tenant isolation from security review criteria

Deployment

Local resident (macOS / LaunchAgent)

bash deploy/install-launchd.sh    # ログイン時自動起動・クラッシュ時自動再起動
  • Logs: logs/docsearch.log / logs/docsearch.err.log

  • Stop and remove: launchctl bootout gui/$(id -u)/com.sodashikenn.docsearch && rm ~/Library/LaunchAgents/com.sodashikenn.docsearch.plist

  • macOS TCC note: If the repository is under a protected folder such as ~/Desktop, the python launched by launchd may be denied file access and enter a startup loop. In that case, grant python access permissions in "System Settings > Privacy & Security," or move the repository outside the protected area (e.g., to ~/dev/)

Docker (fastest way to share with another machine)

git clone https://github.com/SodaShikenn/doc-search.git && cd doc-search
cp .env.example .env               # ANTHROPIC_API_KEY を記入
docker compose up --build -d       # → http://127.0.0.1:8765
  • For a Mac without Docker (when not using Docker Desktop):

    brew install colima docker docker-compose && colima start
    mkdir -p ~/.docker/cli-plugins && ln -sfn $(brew --prefix)/opt/docker-compose/bin/docker-compose ~/.docker/cli-plugins/docker-compose
  • For fully local vector search (recommended on M-series Macs with spare memory): write WITH_LOCAL_ML=1 and DOCSEARCH_EMBEDDER=e5 in .env, then run docker compose up --build -d (image ~2-3GB, first run includes model download. Embedding model changes are detected at startup and automatically re-indexed)

  • Default slim image (~300MB): vector search uses the cloud if VOYAGE_API_KEY is set, otherwise degrades to hash (keyword search always works fully)

  • For real documents, replace ./sample_docs:/docs:ro in docker-compose.yml; to re-index after content updates, run DOCSEARCH_REINDEX=1 docker compose up -d

  • Keys are injected from the host's .env (not baked into the image)

  • There is no authentication. For public exposure, keep the local bind and use a reverse proxy (with auth) or VPN

Third-party

webui/vendor/ contains self-hosted third-party libraries, each under its own license: marked v13.0.2 (MIT) and DOMPurify 3.1.6 (Apache-2.0 OR MPL-2.0). Everything else is MIT (see LICENSE).

Limitations and future work

  • Indexing is full rebuild only (incremental updates not implemented)

  • Conversation history is stored in browser localStorage (no server-side persistence)

  • Evaluation: it would be good to compare hybrid vs. individual modes and embedding models using recall@k on question → correct-file pairs

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for semantic search across llms.txt documentation sources, with hybrid two-stage retrieval and automatic background refresh.
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for documentation search that automatically indexes web documentation sites and provides semantic, full-text, or hybrid search capabilities.
    11
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server for local RAG over personal notes, PDFs, and documents, enabling plain-English querying and hybrid search with multi-hop context expansion.
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for AgentDocs (agentdocs.eu): read, search, write, comment on & share Markdown docs.

  • Hosted MCP memory: save sessions/decisions once, search from Claude, Cursor, ChatGPT. EU-hosted FTS.

  • Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.

View all MCP Connectors

Latest Blog Posts

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/SodaShikenn/doc-search'

If you have feedback or need assistance with the MCP directory API, please join our Discord server