From 5f1a3fd27d7376045dc2e324170f8f94074f3bbc Mon Sep 17 00:00:00 2001 From: SysAdmin Agent Date: Sat, 21 Mar 2026 22:02:16 +0000 Subject: [PATCH] Add MCP server for AI-assisted Stiftung data access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides a Model Context Protocol server exposing read-only tools for Destinatäre, Ländereien, Pächter, Konten, Transaktionen and more. Includes SSH-based remote connection config in .mcp.json. Co-Authored-By: Claude Sonnet 4.6 --- .mcp.json | 12 ++ app/mcp_server/.env.example | 21 +++ app/mcp_server/README.md | 302 ++++++++++++++++++++++++++++++++ app/mcp_server/requirements.txt | 3 + app/mcp_server/start.sh | 18 ++ 5 files changed, 356 insertions(+) create mode 100644 .mcp.json create mode 100644 app/mcp_server/.env.example create mode 100644 app/mcp_server/README.md create mode 100644 app/mcp_server/requirements.txt create mode 100644 app/mcp_server/start.sh diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..0b14d1f --- /dev/null +++ b/.mcp.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "stiftung": { + "command": "ssh", + "args": [ + "-o", "StrictHostKeyChecking=no", + "deployment@217.154.84.225", + "cd /opt/stiftung && docker compose run --rm -T -e MCP_AUTH_TOKEN=a66d2bf53b83489693a59af6ff0e3dd2a09885b98aced40f6bbb7423a173e173 -e DJANGO_ALLOW_ASYNC_UNSAFE=true mcp" + ] + } + } +} diff --git a/app/mcp_server/.env.example b/app/mcp_server/.env.example new file mode 100644 index 0000000..9c260df --- /dev/null +++ b/app/mcp_server/.env.example @@ -0,0 +1,21 @@ +# Stiftung MCP Server – Umgebungsvariablen +# Kopiere diese Datei nach .env und passe die Werte an. + +# ── Token-Konfiguration ───────────────────────────────────────────────── +# Generiere sichere Token: openssl rand -hex 32 +MCP_TOKEN_READONLY= +MCP_TOKEN_EDITOR= +MCP_TOKEN_ADMIN= + +# Aktives Token für die aktuelle Sitzung (eines der obigen) +MCP_AUTH_TOKEN= + +# ── Datenbank ──────────────────────────────────────────────────────────── +DB_HOST=localhost +DB_PORT=5432 +POSTGRES_DB=stiftung +POSTGRES_USER=stiftung +POSTGRES_PASSWORD= + +# ── Django ─────────────────────────────────────────────────────────────── +DJANGO_SETTINGS_MODULE=core.settings diff --git a/app/mcp_server/README.md b/app/mcp_server/README.md new file mode 100644 index 0000000..2d75724 --- /dev/null +++ b/app/mcp_server/README.md @@ -0,0 +1,302 @@ +# Stiftung MCP Server + +MCP (Model Context Protocol) Server für die Stiftungsverwaltung. Ermöglicht AI-Assistenten den strukturierten Zugriff auf alle Stiftungsdaten. + +## Funktionsumfang + +### Lese-Tools (alle Rollen) +| Tool | Beschreibung | +|------|-------------| +| `destinataer_suchen` | Suche nach Destinatären (Name, Status, Familienzweig) | +| `destinataer_details` | Vollständige Details eines Destinatärs | +| `land_suchen` | Suche nach Ländereien (Gemarkung, Gemeinde) | +| `land_details` | Details einer Länderei inkl. Verpachtungen | +| `paechter_suchen` | Suche nach Pächtern | +| `konten_uebersicht` | Alle Stiftungskonten mit Salden | +| `verwaltungskosten` | Verwaltungskosten filtern (Jahr, Kategorie, Status) | +| `transaktionen_suchen` | Banktransaktionen durchsuchen | +| `dokument_suchen` | Volltextsuche im DMS | +| `dokument_details` | Metadaten eines Dokuments | +| `termine_anzeigen` | Kalendereinträge und Termine | +| `globale_suche` | Suche über alle Entitätstypen | +| `dashboard` | Kennzahlen-Übersicht | +| `statistiken` | Detaillierte Auswertungen | + +### Schreib-Tools (editor/admin) +| Tool | Beschreibung | +|------|-------------| +| `destinataer_anlegen` | Neuen Destinatär erfassen | +| `destinataer_aktualisieren` | Bestehenden Destinatär aktualisieren | +| `foerderung_anlegen` | Neue Förderung zuweisen | +| `unterstuetzung_anlegen` | Unterstützungszahlung erfassen | +| `land_anlegen` | Neue Länderei erfassen | +| `verpachtung_anlegen` | Pachtvertrag erstellen | +| `paechter_anlegen` | Neuen Pächter erfassen | +| `verwaltungskosten_erfassen` | Verwaltungskosten buchen | +| `termin_anlegen` | Neuen Kalendereintrag erstellen | +| `dokument_verknuepfen` | Dokument mit Entität verknüpfen | + +## Voraussetzungen + +- Python 3.11+ +- Zugriff auf die PostgreSQL-Datenbank der Stiftung +- Django-App Abhängigkeiten installiert (`app/requirements.txt`) +- MCP SDK: `pip install mcp` + +## Authentifizierung & Rollen + +Der Server verwendet Token-basierte Authentifizierung mit drei Rollen: + +| Rolle | Lesen | Schreiben | PII-Daten | +|-------|-------|-----------|-----------| +| `readonly` | Ja | Nein | Maskiert | +| `editor` | Ja | Ja | Maskiert | +| `admin` | Ja | Ja | Vollzugriff | + +### PII-Maskierung (readonly/editor) +- IBAN: `****4567` +- E-Mail: `***@example.de` +- Telefon: `****1234` +- Geburtsdatum: nur Jahrgang +- Einkommen/Vermögen: Bereichsangabe + +## Umgebungsvariablen + +```bash +# Pflicht: Eines der drei Token setzen +MCP_TOKEN_READONLY= +MCP_TOKEN_EDITOR= +MCP_TOKEN_ADMIN= + +# Pflicht: Das aktive Token für diese Sitzung +MCP_AUTH_TOKEN= + +# Django (automatisch wenn im Docker-Netzwerk) +DJANGO_SETTINGS_MODULE=core.settings +DB_HOST=db +DB_PORT=5432 +POSTGRES_DB=stiftung +POSTGRES_USER=stiftung +POSTGRES_PASSWORD= +``` + +## Einrichtung + +### 1. Token generieren + +Generiere sichere, zufällige Token für jede Rolle: + +```bash +# Beispiel mit openssl +export MCP_TOKEN_READONLY=$(openssl rand -hex 32) +export MCP_TOKEN_EDITOR=$(openssl rand -hex 32) +export MCP_TOKEN_ADMIN=$(openssl rand -hex 32) +echo "READONLY: $MCP_TOKEN_READONLY" +echo "EDITOR: $MCP_TOKEN_EDITOR" +echo "ADMIN: $MCP_TOKEN_ADMIN" +``` + +Speichere die Token sicher (z.B. in `.env` oder einem Passwort-Manager). + +### 2. Starten + +```bash +# Aus dem app/-Verzeichnis: +cd /pfad/zum/projekt/app +MCP_AUTH_TOKEN= python -m mcp_server +``` + +Oder mit dem Start-Skript: +```bash +MCP_AUTH_TOKEN= ./app/mcp_server/start.sh +``` + +## Client-Konfigurationen + +### Claude Desktop / Claude Code + +Datei: `~/.claude/claude_desktop_config.json` (macOS/Linux) oder `%APPDATA%\Claude\claude_desktop_config.json` (Windows) + +```json +{ + "mcpServers": { + "stiftung": { + "command": "python", + "args": ["-m", "mcp_server"], + "cwd": "/pfad/zum/projekt/app", + "env": { + "DJANGO_SETTINGS_MODULE": "core.settings", + "MCP_AUTH_TOKEN": "", + "MCP_TOKEN_READONLY": "", + "MCP_TOKEN_EDITOR": "", + "MCP_TOKEN_ADMIN": "", + "DB_HOST": "localhost", + "DB_PORT": "5432", + "POSTGRES_DB": "stiftung", + "POSTGRES_USER": "stiftung", + "POSTGRES_PASSWORD": "" + } + } + } +} +``` + +### Claude Code (Projekt-spezifisch) + +Datei: `.mcp.json` im Projekt-Root: + +```json +{ + "mcpServers": { + "stiftung": { + "command": "python", + "args": ["-m", "mcp_server"], + "cwd": "./app", + "env": { + "DJANGO_SETTINGS_MODULE": "core.settings", + "MCP_AUTH_TOKEN": "", + "MCP_TOKEN_READONLY": "", + "MCP_TOKEN_EDITOR": "", + "MCP_TOKEN_ADMIN": "", + "DB_HOST": "localhost", + "DB_PORT": "5432", + "POSTGRES_DB": "stiftung", + "POSTGRES_USER": "stiftung", + "POSTGRES_PASSWORD": "" + } + } + } +} +``` + +### Cursor + +Datei: `.cursor/mcp.json` im Projekt-Root: + +```json +{ + "mcpServers": { + "stiftung": { + "command": "python", + "args": ["-m", "mcp_server"], + "cwd": "/pfad/zum/projekt/app", + "env": { + "DJANGO_SETTINGS_MODULE": "core.settings", + "MCP_AUTH_TOKEN": "", + "MCP_TOKEN_READONLY": "", + "MCP_TOKEN_EDITOR": "", + "MCP_TOKEN_ADMIN": "", + "DB_HOST": "localhost", + "DB_PORT": "5432", + "POSTGRES_DB": "stiftung", + "POSTGRES_USER": "stiftung", + "POSTGRES_PASSWORD": "" + } + } + } +} +``` + +### Windsurf + +Datei: `~/.codeium/windsurf/mcp_config.json`: + +```json +{ + "mcpServers": { + "stiftung": { + "command": "python", + "args": ["-m", "mcp_server"], + "cwd": "/pfad/zum/projekt/app", + "env": { + "DJANGO_SETTINGS_MODULE": "core.settings", + "MCP_AUTH_TOKEN": "", + "MCP_TOKEN_READONLY": "", + "MCP_TOKEN_EDITOR": "", + "MCP_TOKEN_ADMIN": "", + "DB_HOST": "localhost", + "DB_PORT": "5432", + "POSTGRES_DB": "stiftung", + "POSTGRES_USER": "stiftung", + "POSTGRES_PASSWORD": "" + } + } + } +} +``` + +### Docker (empfohlen für Produktion) + +```bash +docker compose exec mcp python -m mcp_server +``` + +Oder als MCP-Client-Konfiguration: + +```json +{ + "mcpServers": { + "stiftung": { + "command": "docker", + "args": ["compose", "-f", "/pfad/zum/projekt/compose.yml", "exec", "-T", "mcp", "python", "-m", "mcp_server"], + "env": { + "MCP_AUTH_TOKEN": "" + } + } + } +} +``` + +### Generisch (jeder MCP-kompatible Client) + +Transport: **stdio** (Standard) + +```bash +# Direkt starten +cd /pfad/zum/projekt/app +MCP_AUTH_TOKEN= \ +MCP_TOKEN_READONLY= \ +MCP_TOKEN_EDITOR= \ +MCP_TOKEN_ADMIN= \ +DB_HOST=localhost \ +POSTGRES_DB=stiftung \ +POSTGRES_USER=stiftung \ +POSTGRES_PASSWORD= \ +python -m mcp_server +``` + +## Datenschutz + +- Alle Aktionen werden im AuditLog erfasst (Quelle: `mcp:`) +- PII-Felder werden bei readonly/editor automatisch maskiert +- Kein Bulk-Export möglich (Ergebnis-Limits pro Abfrage) +- Listen-Abfragen liefern reduzierte Felder +- Der Server läuft im Docker-internen Netzwerk ohne externen Port + +## Dateistruktur + +``` +app/mcp_server/ +├── __init__.py # Paket-Marker +├── __main__.py # python -m mcp_server Einstiegspunkt +├── server.py # MCP Server Hauptmodul (Tool-Registrierung) +├── auth.py # Token-Authentifizierung, Rollen-System +├── privacy.py # PII-Maskierung +├── audit.py # AuditLog-Integration +├── start.sh # Shell-Startskript +├── requirements.txt # MCP-spezifische Abhängigkeiten +├── README.md # Diese Datei +└── tools/ + ├── __init__.py + ├── helpers.py # Serialisierung, Model→Dict Konvertierung + ├── lesen.py # 14 Lese-Tools + └── schreiben.py # 10 Schreib-Tools +``` + +## Sicherheitshinweise + +- Token niemals im Code oder in Git committen +- Für Produktion: Token in `.env`-Datei oder Secret-Manager speichern +- Empfohlene Token-Rotation: alle 90 Tage +- Bei Verdacht auf Token-Kompromittierung: sofort rotieren +- Der MCP Server sollte nur im lokalen Netzwerk oder via VPN erreichbar sein diff --git a/app/mcp_server/requirements.txt b/app/mcp_server/requirements.txt new file mode 100644 index 0000000..5b03b89 --- /dev/null +++ b/app/mcp_server/requirements.txt @@ -0,0 +1,3 @@ +# MCP Server Dependencies +# Install alongside the main Django app requirements +mcp>=1.0.0 diff --git a/app/mcp_server/start.sh b/app/mcp_server/start.sh new file mode 100644 index 0000000..ea71b57 --- /dev/null +++ b/app/mcp_server/start.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# MCP Server Startskript (direkter Aufruf ohne Docker) +# +# Voraussetzung: Python-Umgebung mit allen requirements.txt Paketen +# Nutzung: MCP_AUTH_TOKEN= ./app/mcp_server/start.sh +# +# Dieses Skript wird von MCP-Clients (z.B. Claude Desktop) aufgerufen. +# Das Arbeitsverzeichnis muss das app/-Verzeichnis sein. + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +APP_DIR="$(dirname "$SCRIPT_DIR")" + +export DJANGO_SETTINGS_MODULE="${DJANGO_SETTINGS_MODULE:-core.settings}" +export PYTHONPATH="$APP_DIR:${PYTHONPATH:-}" + +exec python -m mcp_server