Skip to main content
Glama
rag-mcp-server

rag-mcp-server

by q6066697

rag-mcp-server

An MCP server that wraps the production RAG pipeline (rag-eval-service) into the standard Model Context Protocol for agents — hybrid search (dense embeddings + BM25 + RRF) becomes a tool that any MCP client can call: Claude Desktop, Claude Code, or your own agent.

Architecture

Client (Claude Desktop / Claude Code / любой MCP-клиент)
    |
    v  MCP over stdio (JSON-RPC)
FastMCP server  (rag_mcp_server/server.py)
    |
    +--> search_documents(query, top_k)
    +--> get_document(doc_id)
    +--> rerank_results(query, doc_ids)
    |
    v
Hybrid retrieval  (rag_mcp_server/core/retrieval.py)
    |
    +---> Dense retriever  --- OpenAI text-embedding-3-small ---> Qdrant (cosine, 1536d)
    |                                                                 |
    +---> Sparse retriever -- BM25 (rank-bm25 / BM25Okapi) ----------+
    |                                                                 |
    |                                 +-------------------------------+
    |                                 v
    |                        Reciprocal Rank Fusion (k=60)
    |                                 |
    +---------------------------------v
                              Top-k документов --> клиент (LLM формирует ответ)

Qdrant by default runs in embedded mode (a file on disk, no separate process) — the server is self-contained and requires no external infrastructure for a demo. If desired, you can switch to a full Qdrant server via docker-compose.yml (see below).

Related MCP server: RAG MCP Server

What this is and why

This is an MCP wrapper, not a reinvention of the retrieval logic: the hybrid search (dense + BM25 + RRF) is ported from rag-eval-service almost unchanged. What this wrapper adds:

  • Protocol instead of HTTP API — the tools are visible to any MCP client (Claude Desktop, Claude Code) without writing a custom HTTP client and without the need to keep the service always up behind REST.

  • Self-contained demo mode — embedded Qdrant instead of a Docker container, so then git clone → working tool takes the minimum number of steps.

  • doc_id/title schema and document-level result aggregation (rather than chunk-level) — for the needs of an LLM client that calls search_documents → get_document instead of working with raw chunks.

  • Docstring contracts written for the LLM consumer of the tool (see rag_mcp_server/server.py), not for a human reading the API documentation.

How to run locally

Requirements: Python 3.10+ and an OpenAI API key (for embeddings).

git clone https://github.com/q6066697/rag-mcp-server.git
cd rag-mcp-server

python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt  # или: pip install -e ".[dev]"

cp .env.example .env
# впишите свой OPENAI_API_KEY в .env

Build the index (one-time; reads data/, embeds chunks through OpenAI and loads them into embedded Qdrant):

python -m rag_mcp_server.core.indexing

(Optional) real Qdrant instead of embedded mode:

docker-compose up -d
# затем в .env: QDRANT_MODE=server

Start the server (stdio transport):

python -m rag_mcp_server.server

Check via MCP Inspector (the built-in inspector from mcp[cli]; opens a web UI for calling tools manually):

mcp dev rag_mcp_server/server.py

Tests (require no live Qdrant/OpenAI — vector search and cross-encoder are mocked):

pytest

How to connect in Claude Desktop / Claude Code

Add it to claude_desktop_config.json (Claude Desktop: Settings → Developer → Edit Config; Claude Code: .mcp.json in the project or claude mcp add):

{
  "mcpServers": {
    "rag-mcp-server": {
      "command": "/absolute/path/to/rag-mcp-server/.venv/bin/python",
      "args": ["-m", "rag_mcp_server.server"],
      "cwd": "/absolute/path/to/rag-mcp-server",
      "env": {
        "OPENAI_API_KEY": "sk-..."
      }
    }
  }
}

After restarting the client, the search_documents, get_document, and rerank_results tools should appear in the list of available tools.

Examples of calling the tools

search_documents

search_documents(query="что такое Reciprocal Rank Fusion", top_k=3)
[
  {
    "doc_id": "reciprocal-rank-fusion.md",
    "title": "Reciprocal Rank Fusion",
    "snippet": "RRF сливает несколько ранжированных списков без нормализации сырых score — документ на позиции r получает вклад 1/(k+r)…",
    "score": 0.0328
  },
  {
    "doc_id": "hybrid-search.md",
    "title": "Hybrid Search",
    "snippet": "Гибридный поиск комбинирует dense-эмбеддинги и BM25, чтобы ловить и семантическое сходство, и точные термины…",
    "score": 0.0301
  }
]

get_document

get_document(doc_id="reciprocal-rank-fusion.md")
"# Reciprocal Rank Fusion (RRF)\n\nRRF — метод слияния нескольких ранжированных списков результатов…"

rerank_results

rerank_results(
    query="как оценивать качество ретривера",
    doc_ids=["eval-retrieval-metrics.md", "reranking.md", "hybrid-search.md"]
)
[
  {
    "doc_id": "eval-retrieval-metrics.md",
    "title": "Evaluating Retrieval Quality",
    "snippet": "Метрики retrieval — hit@k, recall@k, MRR, nDCG@k — измеряют, находит ли поиск релевантные документы…",
    "score": 4.81
  },
  {
    "doc_id": "reranking.md",
    "title": "Reranking",
    "snippet": "Cross-encoder реранкинг переупорядочивает шортлист кандидатов, читая query и passage вместе…",
    "score": 1.02
  }
]

Repository structure

rag-mcp-server/
├── rag_mcp_server/
│   ├── server.py          # точка входа, FastMCP инстанс, регистрация tools
│   ├── core/
│   │   ├── retrieval.py   # портированная гибридная логика поиска (dense + BM25 + RRF + rerank)
│   │   └── indexing.py    # загрузка корпуса, чанкинг, индексация в Qdrant
│   └── config.py          # конфигурация из .env
├── data/                  # bootstrap-корпус (15 markdown-доков, копия из rag-eval-service)
├── tests/
│   └── test_server.py     # unit-тесты на MCP tools (мокают поиск)
├── docker-compose.yml     # опциональный Qdrant-сервер
├── pyproject.toml / requirements.txt
├── .env.example
└── LICENSE (MIT)

Source of the retrieval logic

The hybrid search (rag_mcp_server/core/retrieval.py, core/indexing.py) is ported from rag-eval-service — the eval harness also lives there (NFCorpus/BEIR benchmark, a custom golden set, and hit@k/recall@k/MRR/nDCG metrics), which is intentionally missing from this repository: rag-mcp-server is a thin protocol wrapper around an already validated retrieval pipeline, not a re-evaluation of it.

What would be added next

  • Docker for the MCP server itself — right now only Qdrant is wrapped in a container; deploying the server itself requires its own Dockerfile.

  • SSE/HTTP transport — stdio assumes a local process on the same machine as the client; for remote access (multiple users, cloud deployment), SSE or Streamable HTTP transport from the MCP SDK is needed.

  • Authorization — stdio has none by design (a trusted process run locally); moving to a network transport will require an API key / OAuth at the server level.

  • Incremental indexing — core.indexing currently recreates the whole collection; for a growing corpus, you need to upsert only changed documents.

  • Real Qdrant by default in CI/production — embedded mode is fine for demos and tests, but concurrency multiple processes require a running server.

Available Tools

3 tools
get_documentA

Возвращает полный текст документа из корпуса по его doc_id.

Используй этот инструмент после search_documents(), когда сниппета недостаточно и нужен полный текст найденного документа — например, чтобы процитировать точную формулировку или прочитать раздел, который не попал в сниппет.

Args: doc_id: Идентификатор документа, как он возвращается в поле "doc_id" у search_documents() (совпадает с именем файла в корпусе, например "hybrid-search.md").

Returns: Полный текст документа (markdown). Если doc_id не найден в корпусе, вместо ошибки возвращается строка со списком доступных doc_id, чтобы клиент мог сразу повторить вызов с корректным значением.

Inputs: doc_id (required). Returns: result

rerank_resultsA

Переранжирует переданный список документов-кандидатов относительно query с помощью cross-encoder модели, которая читает пару (query, документ) вместе — точнее, чем независимое векторное сходство, но дороже по compute, поэтому применяется к уже отфильтрованному шортлисту, а не ко всему корпусу.

Используй этот инструмент, когда уже есть список кандидатов (например, из search_documents() или собранный вручную из нескольких запросов) и нужно уточнить их порядок релевантности перед тем, как процитировать top-N пользователю. Для поиска по всему корпусу используй search_documents() — этот инструмент только переупорядочивает уже известные doc_id и не находит новые документы.

Args: query: Запрос, относительно которого переранжируются документы. doc_ids: Список doc_id кандидатов (см. search_documents/ get_document). Неизвестные doc_id молча пропускаются.

Returns: Список [{"doc_id": str, "title": str, "snippet": str, "score": float}, ...], отсортированный по убыванию cross-encoder score. score здесь — необязательно вероятность и несравним по шкале со score из search_documents() (RRF-скор).

Inputs: query (required), doc_ids (required). Returns: result

search_documentsA

Гибридный поиск (dense-эмбеддинги + BM25, слитые через Reciprocal Rank Fusion) по проиндексированному корпусу markdown-документов о RAG, поиске и LLM-инфраструктуре.

Используй этот инструмент, когда нужно найти релевантные документы или факты по теме или вопросу пользователя, прежде чем отвечать — вместо того, чтобы полагаться на собственные знания. Одинаково хорошо работает и для семантических запросов на естественном языке ("как оценивать качество ретривера"), и для точных терминов/аббревиатур ("RRF", "BM25"), поскольку сочетает векторный и лексический поиск.

Args: query: Запрос на естественном языке или ключевые слова. top_k: Сколько документов вернуть (по умолчанию 5, максимум 20).

Returns: Список словарей, отсортированный по убыванию релевантности — [{"doc_id": str, "title": str, "snippet": str, "score": float}, ...]. doc_id — идентификатор документа, который нужно передать в get_document(), чтобы получить его полный текст, или в rerank_results(), чтобы уточнить порядок кандидатов.

Inputs: query (required), top_k. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.7/5.0

    Scored across 3 tools

    Disambiguation5/5

    Tools have clear boundaries: search_documents retrieves candidates, get_document fetches full text by ID, rerank_results reorders given IDs. No overlap in purpose, and each description explicitly states when to use it.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern (search_documents, get_document, rerank_results) in snake_case. Naming convention is uniform and predictable.

    Tool Count5/5

    Three tools is well-scoped for a focused retrieval server: search, fetch full content, and re-rank. Each tool serves a distinct step in the pipeline without redundancy, fitting the typical 3-15 range.

    Completeness5/5

    The tool surface covers the full read-only retrieval workflow: hybrid search with snippets, full document access, and optional cross-encoder re-ranking. No missing operations are needed for the stated purpose.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      B
      maintenance
      Enables any MCP-compatible AI assistant to search, filter, and retrieve information from a local document collection using a hybrid search pipeline with vector, BM25, reranking, and LLM enrichment.
      4
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      Provides RAG-based knowledge retrieval and document management as MCP tools, supporting hybrid search, reranking, and retrieval process visualization.
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables agent tools like Claude Code and GitHub Copilot to perform knowledge retrieval using hybrid search (BM25 + dense) with reranking, via MCP protocol.
      -