porta-rag-mcp
README.md
# porta-rag-mcp — RAG knowledge base как MCP-tools для AI-клиента
MCP-сервер, который выставляет **RAG-базу знаний** (поиск по документам) как
**tools** для любого AI-клиента — Claude Desktop, Cursor, VS Code, ChatGPT.
AI-агент сам решает когда искать по базе и как использовать найденное.
Архитектура — «обёртка»: тонкий слой [FastMCP](https://gofastmcp.com) над
RAG-движком, реализующим фиксированный интерфейс (`retrieve` / `query` /
`get_stats` / `diagnostic`). Код RAG-движка не зависит от MCP и не меняется.
> **Демо-домен:** база знаний по ВЭД (таможенные процедуры, ТН ВЭД, документы
> для импорта/экспорта). Система доменно-независима — на входе любые текстовые
> документы в `rag_data/docs/`.
---
## Почему это интересно
Это пересечение **RAG** ( retrieval-слой) и **MCP** (стандарт подключения AI к
внешним инструментам). Главное — **оптимизация токенов**: поиск разделён на два
режима:
| Tool | LLM | Назначение | Токены |
|---|---|---|---|
| `search_knowledge_base` | **нет** | retrieval-фаза RAG: топ-k чанков | дёшево |
| `ask_knowledge_base` | да | поиск + связный LLM-ответ с цитатами | дороже |
`search_knowledge_base` — это RAG «без LLM»: чистый retrieval, возвращает
релевантные фрагменты без вызова чат-модели. Для справочных lookups модель
предпочитает его; `ask_knowledge_base` (с генерацией) — только когда нужен
связный ответ. Это та самая оптимизация из бенчмарков
(RAG ≈ $0.005/запрос vs MCP-only ≈ $0.17/запрос).
---
## Tools (все read-only — ничего не меняют в индексе)
| Tool | Параметры | Возвращает |
|---|---|---|
| `search_knowledge_base` | `question, top_k=3` | `[{source, text, chunk_id, sim}, ...]` |
| `ask_knowledge_base` | `question, top_k=3` | `{answer, sources, empty, not_found, latency_ms}` |
| `kb_stats` | — | `{available, collection_count, files, models, ...}` |
| `kb_diagnostic` | — | `{available, store, chunks, embed_model, ...}` |
---
## Два бэкенда
### 1. Demo (в этом репо) — TF-IDF, без ключей и LLM
`rag_engine.py` в корне репо — минимальный TF-IDF бэкенд на numpy. Запускается
standalone, без API-ключей и без LLM. `ask_knowledge_base` в demo-режиме собирает
ответ из топ-чанков с цитатами (без генерации). **Это для демонстрации
MCP-обёртки**, не для продакшена.
### 2. Production — FAISS + BM25 + rerank (Porta)
В продакшене этот же `mcp_porta_rag.py` работает рядом с production-`rag_engine.py`
(FAISS + BM25 + rerank, эмбеддинги BGE-M3/e5, чат-модель DeepSeek/Qwen).
`mcp_porta_rag.py` **не меняется** — он импортирует `rag_engine` с тем же
интерфейсом. Достаточно положить production-`rag_engine.py` рядом и положить
документы/индекс в `rag_data/`.
---
## Установка и запуск
```bash
pip install -r requirements.txt # fastmcp, numpy
# 1. самопроверка бэкенда
python3 rag_engine.py
# 2. дебаг в MCP Inspector (браузерный UI, кликаешь tools мышкой)
fastmcp dev mcp_porta_rag.py
# 3. stdio-сервер для AI-клиента
fastmcp run mcp_porta_rag.py
```
Документы: положи `.txt`/`.md` в `rag_data/docs/` — они индексируются при первом
запросе (lazy). `.env` не требуется для demo-бэкенда.
---
## Подключение к Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"porta-rag": {
"command": "python3",
"args": ["/path/to/porta-rag-mcp/mcp_porta_rag.py"]
}
}
}
```
Перезапустить Claude Desktop → модель видит 4 tools. Пример запроса:
«найди в базе, какие документы нужны для импорта» → Claude вызывает
`search_knowledge_base` и получает релевантные фрагменты.
---
## Гибрид с Notion (опционально)
Если в тот же конфиг добавить официальный `notion-mcp-server`, Claude сможет
комбинировать tools обоих серверов:
«найди в ВЭД-базе про код ТН ВЭД 0702 и запиши саммари в Notion»
→ `search_knowledge_base` (этот сервер) + `create_page` (Notion).
MCP-серверы не связаны друг с другом напрямую — они оба подключены к одному
AI-клиенту, который оркестрирует между ними.
---
## Структура
```
.
├── mcp_porta_rag.py # MCP-сервер (FastMCP): 4 read-only tools
├── rag_engine.py # demo TF-IDF бэкенд (без ключей/LLM)
├── rag_data/docs/ # исходные документы (.txt/.md)
│ ├── customs_procedures.txt
│ ├── tn_ved_payments.txt
│ └── ved_documents.txt
├── requirements.txt # fastmcp, numpy
└── README.md
```
## Интерфейс RAG-бэкенда (для замены на production)
```python
def retrieve(question: str, k: int = 3, user_id=None) -> list[dict]
# -> [{"source": str, "text": str, "chunk_id": int, "sim": float}, ...]
def query(question: str, k: int = 3, model=None, user_id=None, history=None) -> dict
# -> {"answer": str, "sources": list, "empty": bool, "not_found": bool, "latency_ms": int}
def get_stats(user_id=None) -> dict
# -> {"available": bool, "empty": bool, "collection_count": int, "files": [...], ...}
def diagnostic() -> dict
```
## Стек
| Слой | Технология |
|---|---|
| MCP | FastMCP 3.x (Python), stdio / Streamable HTTP |
| RAG (demo) | TF-IDF + косинус, numpy, без ключей |
| RAG (prod) | FAISS + BM25 + rerank, эмбеддинги BGE-M3/e5, DeepSeek/Qwen |
## Лицензия
MIT.This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues