Add MCP server for AI-assisted Stiftung data access
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 <noreply@anthropic.com>
This commit is contained in:
21
app/mcp_server/.env.example
Normal file
21
app/mcp_server/.env.example
Normal file
@@ -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
|
||||
302
app/mcp_server/README.md
Normal file
302
app/mcp_server/README.md
Normal file
@@ -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=<geheimes-token-readonly>
|
||||
MCP_TOKEN_EDITOR=<geheimes-token-editor>
|
||||
MCP_TOKEN_ADMIN=<geheimes-token-admin>
|
||||
|
||||
# Pflicht: Das aktive Token für diese Sitzung
|
||||
MCP_AUTH_TOKEN=<das-token-das-gerade-verwendet-wird>
|
||||
|
||||
# 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=<db-passwort>
|
||||
```
|
||||
|
||||
## 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=<dein-token> python -m mcp_server
|
||||
```
|
||||
|
||||
Oder mit dem Start-Skript:
|
||||
```bash
|
||||
MCP_AUTH_TOKEN=<dein-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": "<dein-token>",
|
||||
"MCP_TOKEN_READONLY": "<readonly-token>",
|
||||
"MCP_TOKEN_EDITOR": "<editor-token>",
|
||||
"MCP_TOKEN_ADMIN": "<admin-token>",
|
||||
"DB_HOST": "localhost",
|
||||
"DB_PORT": "5432",
|
||||
"POSTGRES_DB": "stiftung",
|
||||
"POSTGRES_USER": "stiftung",
|
||||
"POSTGRES_PASSWORD": "<db-passwort>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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": "<dein-token>",
|
||||
"MCP_TOKEN_READONLY": "<readonly-token>",
|
||||
"MCP_TOKEN_EDITOR": "<editor-token>",
|
||||
"MCP_TOKEN_ADMIN": "<admin-token>",
|
||||
"DB_HOST": "localhost",
|
||||
"DB_PORT": "5432",
|
||||
"POSTGRES_DB": "stiftung",
|
||||
"POSTGRES_USER": "stiftung",
|
||||
"POSTGRES_PASSWORD": "<db-passwort>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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": "<dein-token>",
|
||||
"MCP_TOKEN_READONLY": "<readonly-token>",
|
||||
"MCP_TOKEN_EDITOR": "<editor-token>",
|
||||
"MCP_TOKEN_ADMIN": "<admin-token>",
|
||||
"DB_HOST": "localhost",
|
||||
"DB_PORT": "5432",
|
||||
"POSTGRES_DB": "stiftung",
|
||||
"POSTGRES_USER": "stiftung",
|
||||
"POSTGRES_PASSWORD": "<db-passwort>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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": "<dein-token>",
|
||||
"MCP_TOKEN_READONLY": "<readonly-token>",
|
||||
"MCP_TOKEN_EDITOR": "<editor-token>",
|
||||
"MCP_TOKEN_ADMIN": "<admin-token>",
|
||||
"DB_HOST": "localhost",
|
||||
"DB_PORT": "5432",
|
||||
"POSTGRES_DB": "stiftung",
|
||||
"POSTGRES_USER": "stiftung",
|
||||
"POSTGRES_PASSWORD": "<db-passwort>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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": "<dein-token>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Generisch (jeder MCP-kompatible Client)
|
||||
|
||||
Transport: **stdio** (Standard)
|
||||
|
||||
```bash
|
||||
# Direkt starten
|
||||
cd /pfad/zum/projekt/app
|
||||
MCP_AUTH_TOKEN=<token> \
|
||||
MCP_TOKEN_READONLY=<readonly> \
|
||||
MCP_TOKEN_EDITOR=<editor> \
|
||||
MCP_TOKEN_ADMIN=<admin> \
|
||||
DB_HOST=localhost \
|
||||
POSTGRES_DB=stiftung \
|
||||
POSTGRES_USER=stiftung \
|
||||
POSTGRES_PASSWORD=<pw> \
|
||||
python -m mcp_server
|
||||
```
|
||||
|
||||
## Datenschutz
|
||||
|
||||
- Alle Aktionen werden im AuditLog erfasst (Quelle: `mcp:<rolle>`)
|
||||
- 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
|
||||
3
app/mcp_server/requirements.txt
Normal file
3
app/mcp_server/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
# MCP Server Dependencies
|
||||
# Install alongside the main Django app requirements
|
||||
mcp>=1.0.0
|
||||
18
app/mcp_server/start.sh
Normal file
18
app/mcp_server/start.sh
Normal file
@@ -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=<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
|
||||
Reference in New Issue
Block a user