Skip to main content
Glama
niels-2005

Company Documents MCP Server

by niels-2005
README.md
# Company Documents MCP Server

Interner FastMCP-Server für die Suche in Unternehmensdokumenten. Der Server ist
für den Betrieb in einem privaten Unternehmensnetz vorgesehen und darf nicht
direkt aus dem Internet erreichbar sein.

## Voraussetzungen und Konfiguration

| Variable | Pflicht | Standard | Zweck |
| --- | --- | --- | --- |
| `MCP_AUTH_TOKEN` | ja | – | Gemeinsamer Bearer-Token für MCP-Clients |
| `OPENAI_API_KEY` | ja | – | API-Schlüssel für Embeddings |
| `MCP_HOST` | nein | `127.0.0.1` | Bind-Adresse des MCP-Servers |
| `MCP_PORT` | nein | `8000` | Port des MCP-Servers |
| `MCP_ALLOWED_HOSTS` | nein | `127.0.0.1,localhost` | Kommagetrennte erlaubte `Host`-Header für `/mcp` |
| `MCP_CHROMA_DIR` | nein | `.data/mcp-server/chroma` | Persistentes Chroma-Datenverzeichnis |
| `MCP_CACHE_DIR` | nein | `.cache/mcp-server` | Persistenter Antwort-Cache |
| `MCP_LOG_DIR` | nein | `logs` | Verzeichnis für Betriebs- und Qualitätslogs |

Secrets gehören ausschließlich in die Laufzeitumgebung bzw. eine nicht
versionierte `.env`-Datei.

## Betrieb

Der FastMCP-Lifespan öffnet beim Start das lokale Chroma-Datenverzeichnis. Ist
es nicht verfügbar, beendet sich der Prozess. Der Server stellt folgende
interne Health-Endpunkte bereit:

- `GET /healthz` – Prozess läuft.
- `GET /readyz` – Chroma antwortet aktuell; andernfalls `503`.
- `/mcp` – authentifizierter MCP-HTTP-Endpunkt.

Starten:

```bash
uv run mcp-server
```

Die VM-Firewall muss den MCP-Port auf das Unternehmensnetz bzw. VPN begrenzen.
HTTP ohne TLS ist nur unter dieser Bedingung zulässig. Bei externem Zugriff ist
ein HTTPS-Reverse-Proxy erforderlich.

Für direkten Zugriff von einem privaten Rechner auf eine VM muss der Server auf
allen VM-Schnittstellen lauschen und ihre IP als erlaubten Host kennen:

```bash
MCP_HOST=0.0.0.0
MCP_ALLOWED_HOSTS=127.0.0.1,localhost,VM_IP
```

Danach ist der authentifizierte MCP-Endpunkt unter
`http://VM_IP:8000/mcp` erreichbar. Ein Reverse Proxy, HTTPS und CORS sind
nicht erforderlich, solange die VM-Firewall den Port ausschließlich für das
private LAN oder VPN freigibt und kein Browser-JavaScript den Endpunkt direkt
anspricht.

## Caching und Ingest

Identische Aufrufe von `search_company_document` werden 24 Stunden im
Datei-Cache gespeichert. Das spart OpenAI-Embedding- und Chroma-Abfragen. Nach
einem erfolgreichen Ingest wird der gesamte Cache gelöscht, damit neue oder
geänderte Antworten sofort sichtbar sind:

```bash
uv run ingest-documents
```

Bei einem fehlgeschlagenen Ingest bleibt der bestehende Cache unverändert. Den
MCP-Service vor einem manuellen Ingest stoppen: Der eingebettete
`PersistentClient` verwendet denselben Datenpfad und wird als Einzelprozess
betrieben. Das mit `MCP_CHROMA_DIR` konfigurierte Verzeichnis ist der persistente
Chroma-Bestand und muss auf der VM zusammen mit den übrigen Betriebsdaten
gesichert werden (z. B. `/var/lib/mcp-server/chroma`).

## Beobachtbarkeit und Störungen

Der Server schreibt täglich rotierende JSONL-Dateien nach `logs/`:

- `server.jsonl` enthält Betriebsereignisse ohne Token, Suchanfragen oder
  Antworten.
- `quality.jsonl` enthält für jeden Tool-Aufruf Zeit, Call-ID, Frage, Antwort
  bzw. Fehlerstatus und Dauer. Diese Datei ist für Qualitätsauswertungen gedacht
  und enthält interne Daten.

Audit- und Betriebslogs werden 30 Tage aufbewahrt. Das Logverzeichnis ist nur
für den Service-Benutzer lesbar. Temporäre OpenAI- und lokale I/O-Fehler
bei der Suche werden mit Exponential Backoff und Jitter innerhalb von 30
Sekunden erneut versucht; danach erhält der Client einen klaren temporären
Fehler.

Die Qualitätsdaten sind bewusst von den Betriebslogs getrennt. Ein späterer
Ausbau kann die Tagesdateien nach S3 übertragen.

Für Chroma wird kein Docker- oder Compose-Dienst benötigt.

## Docker

Das Produktionsimage enthält den bereits ingestierten Chroma-Bestand. Es ist
damit vertraulich zu behandeln und darf nur in einer freigegebenen internen
Registry gespeichert werden: Es enthält Dokumentinhalte und Embeddings.

Vor einem Build muss der lokale Chroma-Bestand aktuell sein. Nach einer
Dokumentänderung den Service stoppen, ingestieren und ein neues Image bauen:

```bash
uv run ingest-documents
docker build -t mcp-server:latest .
```

Der Container benötigt die Secrets ausschließlich zur Laufzeit. Die lokale
`.env`-Datei wird nicht in das Image kopiert. Für den Zugriff von einem zweiten
Rechner im privaten Netz die VM-IP bei den erlaubten Hosts eintragen und den
Port veröffentlichen:

```bash
docker run --detach --name mcp-server \
  --env-file .env \
  --env MCP_HOST=0.0.0.0 \
  --env MCP_ALLOWED_HOSTS=127.0.0.1,localhost,VM_IP \
  --publish 8000:8000 \
  mcp-server:latest
```

Der MCP-Endpunkt ist dann `http://VM_IP:8000/mcp`. Die VM-Firewall muss Port
8000 auf das private Netz bzw. VPN begrenzen.

Chroma ist absichtlich im Image und wird nicht über ein Volume bereitgestellt:
Ein Datenupdate erfolgt durch einen neuen Ingest und Image-Build. Cache und
Logs werden im beschreibbaren Layer des Containers gespeichert. Sie bleiben bei
`docker stop` und `docker start` desselben Containers erhalten, werden aber bei
`docker rm` oder einem Container-Neuaufbau verworfen.