Przejdź do treści
Marcin Baniowski Connecting people with machines
← Wróć do notatek

MCP do dokumentacji technicznej z algorytmem BM25

Problem

Pisanie dokumentacji to jeden z najmniej lubianych obowiązków w IT — i jeden z najlepszych przypadków użycia LLM-ów. Po skończonej pracy chat opisuje, co zostało zrobione, według ustalonego schematu i wrzuca markdown do repo. Problem w tym, że taka taśmowa produkcja szybko staje się trudna do ogarnięcia — szczególnie dla innych członków zespołu, a otwieranie repo za każdym razem jest mało praktyczne, jeśli i tak pracujemy głównie z czatem.

Model Context Protocol (MCP) rozwiązuje ten problem — to otwarty standard, który pozwala podłączyć dowolne źródło danych jako "tool" dostępny dla LLM-a. Bez przerywania flow developmentu można odpytać dokumentację (np. jak bezpiecznie postawić tę aplikację w naszej infrastrukturze?), a model sam dobierze parametry zapytania.

docs-mcp to serwer MCP w Go, który klonuje wskazane repo z GitHuba, indeksuje dokumenty algorytmem BM25 i udostępnia je jako narzędzia MCP (search, get document, list). Cały setup to jedno go build i trzy zmienne środowiskowe.

Dlaczego zdalny MCP (HTTP) zamiast stdio?

MCP definiuje kilka transportów — lokalny stdio i wariant HTTP. docs-mcp implementuje ten drugi: zwykły JSON-RPC over HTTP POST. W trybie stdio każdy developer musi mieć lokalnie sklonowane repo, token i uruchomiony proces. Tu serwer działa centralnie — klient potrzebuje tylko URL-a:

{
  "mcpServers": {
    "infra-docs": {
      "url": "https://docs-mcp.internal:8000/mcp"
    }
  }
}

Dlaczego BM25 zamiast embeddingów?

Typowy RAG pipeline w Pythonie wymaga:

  • Modelu embeddingowego (np. sentence-transformers) — ~500 MB–2 GB RAM na sam model
  • Bazy wektorowej (FAISS, Chroma, Qdrant)
  • Pythona z zależnościami (torch, transformers, numpy)

docs-mcp używa BM25 — klasycznego algorytmu information retrieval opartego na statystyce słów (TF-IDF z normalizacją długości dokumentu). To podejście:

Python + embeddingi docs-mcp (Go + BM25)
RAM na indeks 500 MB – 2 GB+ (model + wektory) ~10–50 MB (odwrócony indeks w pamięci)
Zależności torch, transformers, numpy, vector DB Tylko stdlib Go + go-git
Czas startu Sekundy–minuty (ładowanie modelu) < 1 s (tokenizacja + budowa indeksu)
Obraz Docker 2–5 GB ~30 MB (statyczna binaryka)

BM25 nie rozumie synonimów ani semantyki — jeśli dokumentacja mówi "bucket" a pytasz o "storage", nie znajdzie dopasowania. docs-mcp łagodzi to dwoma mechanizmami boostingu: trafienia w nazwę pliku/ścieżkę oraz w tagi z YAML frontmattera:

---
tags: [vpn, staging, wireguard, network]
---
# Konfiguracja VPN do środowiska staging

To prosty, ale skuteczny "ludzki override" dla ograniczeń BM25 — autor dokumentu może dopisać synonimy i terminy domenowe, których nie ma w treści, a które realnie pojawiają się w pytaniach. W praktyce, w dokumentacji wewnętrznej, ludzie szukają konkretnymi terminami ("S3", "terraform", "deploy") i ten dodatek wystarczy, żeby trafność była na poziomie, który nie wymaga embeddingów.

Dla zespołu z kilkuset plikami Markdown to wystarczające rozwiązanie za ułamek kosztu operacyjnego.

Jak to działa w praktyce?

  1. Serwer klonuje repo (shallow clone, jedna gałąź)
  2. Parsuje Markdown, dzieli na chunki, buduje indeks BM25
  3. Co SYNC_INTERVAL sekund (domyślnie 30 min) robi git pull i przebudowuje indeks
  4. Opcjonalnie GitHub webhook triggeruje natychmiastowy sync po pushu

Developer w Cursorze pyta: "jak skonfigurować VPN do staging?" → AI wywołuje tool search_docs → BM25 zwraca najlepiej dopasowane fragmenty → AI odpowiada w kontekście aktualnej dokumentacji zespołu.