Skip to main content
Glama
fayna-digital

fayna-rag-mcp

Official

{"type": "text"}# fayna-rag-mcp — local knowledge base with RAG and MCP

Python License Status

Developed by Fayna Digital Author: Volodymyr Shevchenko


Problem: the team collects documentation (policies, manuals, notes) in files and quickly loses natural-language access to it — searching by file name or Ctrl+F does not scale, and sending internal documents to a cloud LLM service is not always acceptable for privacy reasons.

Solution: a local RAG pipeline (FAISS + multilingual embeddings) based on a local LLM (Ollama) — and the same search/Q&A exposed as an MCP server, so any MCP client (Claude Desktop/Code, etc.) or an external automated workflow can use it via simple REST routes. No data leaves the machine it runs on.

Result: five MCP tools and four REST routes for semantic search, RAG Q&A with sources, document reading, and offline cataloging — ready to connect to Claude or n8n in minutes, with no cloud dependencies.

Features

Tool (MCP)

Purpose

read_document(file_path)

read a full file from the database (with a path-traversal guard within DOCUMENTS_DIR)

list_documents()

list all documents (.txt, .md, .pdf, .docx)

search_documents(query)

FAISS semantic search → top-relevant chunks

ask_knowledge_base(question)

RAG answer: FAISS-retrieve + Ollama LLM, with sources

show_catalog()

read-only catalog of document tags (topic/type/language/audience)

REST route

Body

What it does

POST /search

{"query": …}

FAISS-retrieve → {results:[{source,text}]}

POST /ask

{"question": …}

RAG answer → {answer, sources}

POST /find

{"query": …}

exact substring search over .md/.txt in the corpus

POST /hybrid

{"query": …}

hybrid: Cyrillic↔Latin transliteration + token-match, semantic selection

Related MCP server: Solarium

Stack

Python 3.10+ · FAISS (faiss-cpu) · sentence-transformers · tiktoken · Ollama · FastMCP · Tesseract/poppler/Whisper for multi-format ingest · Docker.

RAG Pipeline

docs/ → load (.txt/.md/.pdf/.docx) → chunk (tiktoken) → embed (mpnet) → FAISS → retrieve → Ollama → answer + sources
  • Chunking — by tiktoken tokens (cl100k_base), not characters. Default CHUNK_SIZE=700 tokens, CHUNK_OVERLAP=100 tokens.

  • Embeddings: paraphrase-multilingual-mpnet-base-v2 — a multilingual model (UA/PL/EN/RU and others) so search works regardless of query language.

  • LLM: any Ollama model, default qwen2.5:7b.

  • Index: FAISS IndexFlatIP (cosine similarity), TOP_K=5.

Quick start

pip install -r src/requirements.txt

# Przykład: demo-korpus na kilka dokumentów (sample-docs/)
export DOCUMENTS_DIR=./sample-docs
python -m src.main build-index      # → src/index/index.faiss + chunks.pkl

# Interaktywne Q&A (CLI)
python -m src.main

# Serwer MCP (transport z env MCP_TRANSPORT: stdio|http)
python -m src.mcp.server

Tests:

pip install -r tests/requirements-dev.txt
pytest -q

Docker

docker compose up -d

Default values in docker-compose.yml/Dockerfile are designed for Ollama running on the host (via host.docker.internal); adjust OLLAMA_URL to your own network (bridge address on Linux, separate Ollama container, etc.).

Configuration (src/config.py, everything via env)

Env

Default

Description

DOCUMENTS_DIR

./docs

knowledge base root

EMBEDDING_MODEL

paraphrase-multilingual-mpnet-base-v2

embedding model

OLLAMA_MODEL

qwen2.5:7b

LLM for RAG answers

OLLAMA_URL

http://localhost:11434/api/generate

Ollama endpoint

CHUNK_SIZE / CHUNK_OVERLAP

700 / 100

tokens (tiktoken), not characters

TOP_K

5

how many chunks retrieve returns

MCP_TRANSPORT

stdio

stdio (for a local MCP client) or http → FastMCP streamable-http

MCP_HOST / MCP_PORT

0.0.0.0 / 8765

address when MCP_TRANSPORT=http

Connecting to an MCP client (e.g., Claude Code) — via its MCP server configuration, with the command python -m src.mcp.server (stdio) or the container URL (http).

Structure

src/
├── config.py         # wszystkie env-zmienne + domyślne
├── main.py           # CLI: build-index | interaktywne Q&A
├── assistant.py       # CompanyKBAssistant (LLM decyduje czy wołać MCP-toolki)
├── catalog.py         # offline-klasyfikacja dokumentów przez Ollama → JSON+HTML
├── ingest.py           # multi-formatowy ingest: OCR skanów, vision-opis diagramów, Whisper-transkrypcja
├── rag/
│   ├── ingest.py      # load_document (.txt/.md/.pdf/.docx)
│   ├── chunk.py        # chunk_text (tiktoken cl100k_base, overlap)
│   ├── embed.py         # embed_chunks (sentence-transformers)
│   ├── build_index.py   # build_index → FAISS + pickle
│   └── query.py          # retrieve / build_prompt / ask
└── mcp/
    ├── server.py     # FastMCP: 5 MCP-toolków + 4 trasy REST
    └── client.py      # MCPClient (JSON-RPC przez subprocess)

Multi-format ingest (OCR of scans via Tesseract, description of drawings/diagrams via a vision model, audio/video transcription via Whisper) — a separate, dependency-heavier path, not needed for the basic text corpus above.

License

MIT — see LICENSE. © Fayna Digital.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers