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:
12
.mcp.json
Normal file
12
.mcp.json
Normal file
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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