Vorbereitung und Setup: Das Grundgerüst bauen
Zeit, die Ärmel hochzukrempeln. Wir bauen jetzt das Grundgerüst für Deinen MCP Server.
Verzeichnisstruktur anlegen
Alles beginnt mit einer sauberen Struktur. Bei mir hat sich diese Aufteilung bewährt:
# Hauptverzeichnis erstellen
mkdir -p /var/deinverzeichnis/mcp/content-metadata-server
# Unterverzeichnisse anlegen
cd /var/deinverzeichnis/mcp/content-metadata-server
mkdir -p modules config logs docs/howto
# Python-Module vorbereiten
touch modules/__init__.py
touch modules/database.py
touch modules/security.py
touch modules/logging.py
# Hauptdatei
touch server.py
# Konfigurationsdateien
touch config/{database,credentials,security,logging}.json
echo "Struktur steht!"
Das war's schon. Keine Magie, nur eine klare Ordnung.
Virtual Environment einrichten
Python-Dependencies gehören in ein Virtual Environment. Das erspart Dir später viel Ärger mit Version-Konflikten:
cd /var/deinverzeichnis/mcp/content-metadata-server
python3 -m venv venv
# Aktivieren
source venv/bin/activate
# Kontrolle
which python
# Sollte zeigen: /var/deinverzeichnis/mcp/content-metadata-server/venv/bin/python
Wenn Du das venv vergisst zu aktivieren, wirst Du es spätestens beim ersten Import-Fehler merken.
Dependencies installieren
Die drei Pakete, die wir wirklich brauchen:
source venv/bin/activate
pip install fastmcp==2.11.1
pip install pymysql==1.4.6
pip install cryptography==45.0.5
# Kurze Kontrolle
pip list | grep -E "(fastmcp|pymysql|cryptography)"
Was macht welches Paket?
FastMCP 2.11.1 ist das Herzstück. Das ist das Framework, das Deinen Python-Code in einen MCP Server verwandelt. Es kümmert sich um die gesamte Kommunikation mit Claude, registriert Deine Funktionen als Tools und verarbeitet die JSON-RPC Nachrichten. Ohne FastMCP müsstest Du das komplette MCP-Protokoll selbst implementieren.
PyMySQL 1.4.6 ist Deine Verbindung zur MariaDB/MySQL Datenbank. Es ist ein reiner Python-Connector (kein C-Code), was die Installation einfacher macht. PyMySQL übersetzt Deine Python-Befehle in SQL-Queries und gibt Dir die Ergebnisse als Python-Objekte zurück. Es unterstützt Prepared Statements, was für die Sicherheit essentiell ist.
Cryptography 45.0.5 brauchst Du für die sichere Verbindung zur Datenbank. PyMySQL nutzt es für SSL/TLS-Verschlüsselung und für die Authentifizierung mit modernen MySQL-Auth-Plugins. Auch wenn Du nur localhost verwendest, manche MariaDB-Setups verlangen trotzdem verschlüsselte Authentifizierung.
Basis-Konfigurationsdateien
Jetzt kommen die Config-Files. Die sind das Herz des Systems, also nimm Dir Zeit dafür.
database.json
{
"connections": {
"karlkratz_de": {
"host": "localhost",
"port": 3306,
"database": "karlkratz_de",
"user": "content_reader",
"charset": "utf8mb4",
"connect_timeout": 10,
"read_timeout": 30
}
},
"defaults": {
"charset": "utf8mb4",
"connect_timeout": 10,
"read_timeout": 30,
"autocommit": false
},
"target_table": "content_metadata"
}
Was bedeutet das alles?
- "connections": Hier definierst Du alle Datenbankverbindungen. Du kannst mehrere haben.
- "karlkratz_de": Der Name Deiner Connection. Den verwendest Du später im Code.
- "host": Wo läuft die Datenbank? Bei localhost ist sie auf dem gleichen Server.
- "port": Standard-Port für MariaDB/MySQL. Ändere das nur, wenn Deine DB anders konfiguriert ist.
- "database": Der Name der Datenbank, auf die Du zugreifen willst.
- "user": Mit welchem Benutzer verbindest Du Dich? Hier der Read-Only User.
- "charset": utf8mb4 unterstützt alle Unicode-Zeichen, auch Emojis.
- "connect_timeout": Nach 10 Sekunden ohne Verbindung gibt's einen Fehler.
- "read_timeout": Eine Query darf maximal 30 Sekunden laufen.
- "defaults": Diese Werte gelten für alle Connections, außer Du überschreibst sie.
- "autocommit": false bedeutet, Änderungen müssen explizit committed werden.
- "target_table": Mit welcher Tabelle arbeitet dieser Server hauptsächlich.
credentials.json
{
"database_users": {
"content_reader": {
"password": "HIER_KOMMT_DEIN_PASSWORT",
"permissions": ["SELECT"],
"databases": ["karlkratz_de"],
"tables": ["content_metadata"]
},
"content_writer": {
"password": "HIER_KOMMT_DEIN_PASSWORT",
"permissions": ["SELECT", "INSERT", "UPDATE", "DELETE"],
"databases": ["karlkratz_de"],
"tables": ["content_metadata"]
}
},
"default_user": "content_reader",
"host": "localhost",
"port": 3306
}
Die allowed_columns musst Du natürlich an Deine tatsächliche Tabellenstruktur anpassen.
security.json
{
"query_limits": {
"max_execution_time": 30,
"max_result_rows": 100,
"max_affected_rows_update": 10,
"max_affected_rows_delete": 5
},
"allowed_statements": [
"SELECT", "INSERT", "UPDATE", "DELETE"
],
"blocked_keywords": [
"DROP", "TRUNCATE", "ALTER", "CREATE",
"GRANT", "REVOKE", "LOAD", "OUTFILE"
],
"parameter_binding": {
"required": true,
"max_parameters": 20
},
"rate_limiting": {
"queries_per_minute": 50,
"concurrent_connections": 3
},
"allowed_tables": ["content_metadata"],
"allowed_columns": {
"content_metadata": [
"id", "title", "description", "created_at",
"updated_at", "status", "author_id"
]
}
}
Das Security-Setup im Detail:
- "query_limits": Grenzen für Query-Ausführung
- "max_execution_time": Nach 30 Sekunden wird jede Query abgebrochen
- "max_result_rows": Maximal 100 Zeilen pro SELECT-Query
- "max_affected_rows_update": Ein UPDATE darf maximal 10 Zeilen ändern
- "max_affected_rows_delete": Ein DELETE darf maximal 5 Zeilen löschen
- "allowed_statements": Nur diese SQL-Befehle sind erlaubt
- "blocked_keywords": Diese gefährlichen SQL-Befehle werden geblockt
- "parameter_binding/required": Alle Queries MÜSSEN Parameter-Binding verwenden
- "parameter_binding/max_parameters": Maximal 20 Parameter pro Query
- "rate_limiting/queries_per_minute": Maximal 50 Queries pro Minute
- "rate_limiting/concurrent_connections": Maximal 3 gleichzeitige Verbindungen
- "allowed_tables": Nur auf diese Tabellen darfst Du zugreifen
- "allowed_columns": Nur diese Spalten darfst Du verwenden
logging.json
{
"level": "INFO",
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"handlers": {
"file": {
"enabled": true,
"path": "/var/deinverzeichnis/mcp/content-metadata-server/logs/operations.log",
"max_size_mb": 10,
"backup_count": 5,
"rotation": "size"
}
},
"log_queries": {
"enabled": true,
"log_parameters": false,
"log_execution_time": true,
"log_affected_rows": true
}
}
Sichere Passwörter generieren
Für die Datenbank-Benutzer brauchst Du ordentliche Passwörter:
CONTENT_READER_PWD=$(openssl rand -base64 32)
CONTENT_WRITER_PWD=$(openssl rand -base64 32)
echo "Reader: $CONTENT_READER_PWD"
echo "Writer: $CONTENT_WRITER_PWD"
# Die kommen dann in credentials.json
Pro-Tipp: Speicher die Passwörter irgendwo sicher. Du wirst sie später für die MariaDB-Benutzer brauchen.
Berechtigungen setzen
Credentials gehören geschützt:
chmod 600 config/credentials.json
chmod 644 config/database.json
chmod 644 config/security.json
chmod 644 config/logging.json
chmod 755 logs/
touch logs/operations.log
chmod 644 logs/operations.log
Setup testen
Bevor wir weitermachen, prüfen wir, ob alles passt.
Das Test-Script macht eine systematische Überprüfung Deiner Installation. Zuerst schaut es, ob Python im Virtual Environment läuft (der Pfad muss "venv" enthalten). Dann versucht es, alle drei Dependencies zu importieren: wenn das klappt, sind sie installiert. Als nächstes prüft es jede Config-Datei: Existiert sie? Ist es valides JSON? Zum Schluss kontrolliert es, ob alle Verzeichnisse angelegt wurden. Nur wenn alle Tests durchlaufen, ist Dein Setup bereit für den nächsten Schritt.
# test_setup.py
#!/usr/bin/env python3
import json
import os
import sys
def test_setup():
# Virtual Environment Check
if "venv" not in sys.executable:
print("FEHLER: Virtual Environment nicht aktiv!")
return False
print("OK: Virtual Environment aktiv")
# Dependencies Check
try:
import fastmcp
import pymysql
import cryptography
print("OK: Dependencies installiert")
except ImportError as e:
print(f"FEHLER: Dependency fehlt: {e}")
return False
# Config Files Check
config_files = [
"config/database.json",
"config/credentials.json",
"config/security.json",
"config/logging.json"
]
for config_file in config_files:
if not os.path.exists(config_file):
print(f"FEHLER: {config_file} fehlt!")
return False
try:
with open(config_file, 'r') as f:
json.load(f)
print(f"OK: {config_file} valid")
except json.JSONDecodeError:
print(f"FEHLER: {config_file} ungültiges JSON!")
return False
# Directory Check
directories = ["modules", "config", "logs", "docs/howto"]
for directory in directories:
if not os.path.exists(directory):
print(f"FEHLER: Verzeichnis {directory} fehlt!")
return False
print("\nSetup komplett!")
return True
if __name__ == "__main__":
success = test_setup()
sys.exit(0 if success else 1)
Ausführen mit:
source venv/bin/activate
python test_setup.py
Wenn alles durchläuft, kannst Du weitermachen.
Git-Konfiguration (Optional)
Falls Du versionieren willst:
# .gitignore
venv/
__pycache__/
*.pyc
*.pyo
logs/*.log
config/credentials.json
.vscode/
.idea/
*.swp
*.swo
.DS_Store
Thumbs.db
Die credentials.json gehört NIEMALS ins Repository. Never ever.
Was haben wir jetzt?
Die Basis steht:
- Saubere Verzeichnisstruktur
- Virtual Environment mit allen Dependencies
- Konfigurationsdateien vorbereitet
- Berechtigungen korrekt gesetzt
- Setup-Test läuft durch
Das Grundgerüst steht. Als nächstes kümmern wir uns um die Datenbank - das Herzstück unseres MCP Servers. Ich zeige Dir, wie Du MariaDB-Benutzer mit minimalen Rechten anlegst, die Tabellenstruktur analysierst und alles für sicheren Zugriff vorbereitest. Weiter zum Datenbank-Setup mit MariaDB