Skip to main content
Glama

hybrid-rag-mcp

CI Python 3.11+ License: MIT

Serve MCP com RAG híbrido (Qdrant vetorial + BM25 léxico via RRF), agente multi-step com fallback offline via Ollama e transporte stdio ou streamable HTTP.

Foco: indexar documentos técnicos (Markdown, TXT, PDF) e responder perguntas com fontes citadas, de forma 100% local — o padrão que conecta LLMs a bases locais/corporativas em 2026/2027.

Destaques

  • Busca híbrida: embedding (Qdrant local, sem Docker) + BM25 próprio (idf suavizado), fundidos por RRF.

  • Agente multi-step: se o contexto da 1ª busca for insuficiente, o modelo sinaliza [MORE_CONTEXT], o agente gera uma busca de follow-up e repete com memória incremental de fontes.

  • Re-ranking opcional: cross-encoder (Ollama /api/rerank, ex. bge-reranker-v2-m3) com degradação graciosa.

  • Fallback resiliente: provedor de nuvem (OpenAI-compatible) na frente, Ollama local como reserva quando a API cai.

  • Persistência: os chunks ficam no Qdrant; o índice BM25 é restaurado no startup sem re-ingestão.

  • Rastreabilidade: trace por passo do agente + audit.jsonl (pergunta, provedor, iterações, latência, fontes).

  • Mensurável: pipeline de avaliação recall@k / nDCG@k com gate de qualidade no CI.

  • Dois transportes: stdio (RPC local) e streamable HTTP (http://host:port/mcp).

Related MCP server: rag-mcp

Arquitetura

flowchart LR
    C[Cliente MCP<br/>stdio ou HTTP] -->|tools: ingest / search / ask| M[MCP Server<br/>hybrid-rag-mcp]
    M --> AGE[Agente multi-step<br/>loop com [MORE_CONTEXT]]
    M --> I[ingest]
    I --> C1[Chunker<br/>seções + sentenças]
    C1 --> E[Embeddings<br/>Ollama bge-m3]
    E --> Q1[(Qdrant local<br/>busca vetorial)]
    C1 --> K[BM25 próprio<br/>busca léxica]
    AGE --> RET[Busca híbrida]
    RET --> Q1 & K
    Q1 & K --> RRF[RRF fusion]
    RRF --> RR[Reranker opcional<br/>Ollama /api/rerank]
    RR --> LLM[FallbackLLM<br/>nuvem -> Ollama]
    LLM --> AUD[audit.jsonl<br/>trace + iterações + fontes]

Métricas (gate de qualidade no CI)

Pipeline de avaliação sobre 36 queries — 12 curadas manualmente em eval/dataset.jsonl + 24 geradas automaticamente de documentos reais (eval/dataset.real.jsonl, veja Corpus). Gatilho do CI: falha se recall@1 < 0.8.

k

recall@k

nDCG@k

1

0.833

0.833

3

1.000

0.836

5

1.000

0.907

Números honestos sobre texto real: recall@1 = 0.833, mas a fonte certa está sempre no top-3. Rode localmente com python -m hybrid_rag_mcp.eval.

Corpus

  • examples/corpus/11 documentos: 5 fictícios (operations/security/database/infra/events) + 6 livros reais de domínio público (Project Gutenberg): Chekhov, Machado de Assis, Aluísio Azevedo, Eça de Queirós, Jane Austen e Conan Doyle, misturando PT e EN.

  • tools/fetch_corpus.py — baixa o catálogo do Gutenberg e gera o dataset de avaliação automaticamente: cada consulta é um trecho real do documento e o documento esperado é a fonte exata desse trecho (ground-truth auto-supervisionado, sem curadoria manual).

Como rodar

Pré-requisitos: Python 3.11+, Ollama de pé (ollama serve).

# 1. Modelos locais (uma vez)
ollama pull bge-m3        # embeddings
ollama pull qwen3:8b      # geração (ou outro)
ollama pull bge-reranker-v2-m3   # opcional: somente Ollama >= 0.36

# 2. Instalar
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# 3. Indexar + responder (uso direto da engine)
python -c "
from hybrid_rag_mcp.rag.engine import RAGEngine
rag = RAGEngine()
print(rag.ingest())                                    # indexa examples/corpus
print(rag.search('Qual a porta padrão do servidor?'))  # busca híbrida
print(rag.ask('De quantas em quantas horas são os backups?'))  # agente com fontes
"

Como cliente MCP

stdio: cliente de exemplo — python examples/client.py "Qual a porta padrão?"

HTTP:

# terminal 1
python -m hybrid_rag_mcp --transport http --host 127.0.0.1 --port 8000

# terminal 2
python examples/client_http.py "Qual a porta padrão?"

Registre em qualquer cliente MCP (Claude Desktop, editores, agentes):

{
  "mcpServers": {
    "hybrid-rag": {
      "command": ".venv/bin/python",
      "args": ["-m", "hybrid_rag_mcp"],
      "env": { "PYTHONPATH": "src" }
    }
  }
}

Fallback para nuvem (opcional)

Copie .env.example para .env e preencha CLOUD_BASE_URL + CLOUD_API_KEY + CLOUD_MODEL (qualquer endpoint OpenAI-compatível). A nuvem assume prioridade; o Ollama responde automaticamente se a API falhar ou ficar offline.

Ferramentas MCP

Tool

Descrição

ingest

Indexa md/txt/pdf de um diretório nos dois índices (Qdrant + BM25).

search

Busca híbrida (RRF, com re-ranking opcional) retornando trechos + fontes.

ask

Agente multi-step: recupera, gera, detecta contexto insuficiente, refaz a busca e responde citando fontes (com audit log).

Estrutura

src/hybrid_rag_mcp/
├── server.py          # Servidor MCP (stdio + streamable HTTP)
├── config.py          # Configuração via .env (pydantic-settings)
├── eval.py            # Avaliação recall@k / nDCG@k
├── rag/
│   ├── agent.py       # Loop multi-step (memória de fontes, [MORE_CONTEXT])
│   ├── chunker.py     # Chunking por seções markdown + sentenças
│   ├── engine.py      # Orquestração: ingest → search → ask + audit
│   ├── hybrid.py      # Fusão RRF + re-ranking
│   └── ingestion.py   # Leitura de md/txt/pdf
├── providers/
│   ├── embed.py       # Embeddings via Ollama
│   ├── llm.py         # FallbackLLM (nuvem → Ollama)
│   └── rerank.py      # Cross-encoder opcional (degradação graciosa)
└── stores/
    ├── vector.py      # Qdrant embarcado (sem Docker, persistente)
    └── lexic.py       # BM25 com idf suavizado

Qualidade

  • 21 testes unitários (pytest) sem rede/Ollama — chunking, RRF, BM25, persistência, métricas de eval e loop do agente.

  • CI em 2 jobs: test (ruff + pytest + smoke stdio/HTTP) e eval (Ollama real + gate recall@1 >= 0.8).

  • docker-compose.yml intencionalmente ausente: roda só com pip install (Qdrant embarcado).

Available Tools

3 tools
askC

Responde a pergunta com RAG usando o provedor disponível (fallback offline via Ollama).

ParametersJSON Schema
NameRequiredDescriptionDefault
top_kNo
questionYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It mentions a fallback offline via Ollama, which is useful, but does not explain whether the operation is read-only, whether it requires prior ingestion, or how provider selection behaves beyond the fallback.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single clear, efficient sentence that front-loads the core functionality and includes a behavioral note about the fallback. No unnecessary words, though it slightly sacrifices detail for brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has two parameters, no annotations, and a vague description. It lacks usage guidance, parameter semantics, and behavioral details such as return format or prerequisites, making it incomplete for an agent to call correctly in varied contexts.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description does not add meaning for either parameter. It implies 'question' is the input, but 'top_k' is completely undocumented in both the schema and description, leaving the agent without semantic guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool answers a question using RAG, which is a specific verb and resource. It does not explicitly differentiate from sibling 'search', but the phrase 'Responde a pergunta com RAG' gives enough identity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use 'ask' versus sibling tools 'search' or 'ingest'. The description does not mention any conditions, prerequisites, or exclusions, leaving the agent to infer usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ingestA

Indexa documentos (md/txt/pdf) de um diretório nos índices vetorial e BM25.

ParametersJSON Schema
NameRequiredDescriptionDefault
corpus_dirNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the main write behavior (indexing into vector and BM25 stores) but does not mention side effects, such as whether existing documents are replaced, whether indexing is incremental, if the directory is read recursively, or any permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no wasted words. It front-loads the action and packs in file types and target indexes efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and an output schema, the description covers the core purpose and parameter meaning. Gaps remain around usage timing, reindexing behavior, and directory handling, but these are not severe enough to render it unusable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. 'de um diretório' clarifies that corpus_dir is the source directory, adding meaning to the parameter name alone. However, it does not explain the default behavior, path format, or how recursive/required the directory is.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Indexa' - indexes), a clear resource (documents md/txt/pdf from a directory), and the target (vector and BM25 indexes). This clearly differentiates it from siblings 'search' and 'ask', which are query operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied: call this tool to index documents before searching or asking. However, there is no explicit guidance on when to use it versus alternatives, prerequisites, or scenarios where it should not be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 3 tool updatesv0.1.0
    • First observedask
    • First observedingest
    • First observedsearch

TDQS

A3.6/5.0

Scored across 3 tools

Disambiguation5/5

Cada ferramenta tem um propósito claramente distinto: ingestão, busca híbrida e geração de resposta. 'search' e 'ask' podem parecer próximos, mas as descrições deixam explícito que um retorna trechos/fontes e o outro produz uma resposta via RAG.

Naming Consistency5/5

Os três nomes seguem o mesmo padrão de verbos imperativos simples: ingest, search, ask. Não há mistura de estilos ou convenções conflitantes.

Tool Count5/5

Com três ferramentas, o servidor cobre exatamente o fluxo central de um RAG híbrido sem excesso ou carência. O escopo é enxuto e cada ferramenta é necessária.

Completeness4/5

O ciclo principal — ingerir, buscar e responder — é completo e funcional. Faltam operações secundárias como remover/atualizar documentos ou listar o índice, mas o agente consegue realizar as tarefas centrais sem becos sem saída.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Enables indexing local documents (PDF, Markdown, text, code) into a knowledge base and querying them via semantic search using local embeddings, all running privately on your machine.
    4
    -
  • A
    license
    A
    quality
    C
    maintenance
    Enables semantic search and question answering over a knowledge base using hybrid retrieval and grounded answers, all running offline with no API keys.
    4
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Indexes your project's markdown documentation and exposes it to AI agents via local hybrid search (lexical + semantic) with progressive disclosure tools.
    3
    555 npm
    5
    MIT