Du hast CI für dein Backend. Du lintest dein Frontend. Deine Docker-Container haben Healthchecks. Alles in deinem Stack hat eine Testing-Story — außer die MCP-Verbindungen, von denen dein Agent bei jedem einzelnen Aufruf abhängt.

Am 19. April hat das MCP-Team seine Roadmap für 2026 veröffentlicht. Vier Prioritäten: Authorization, Registry, Rich UX Primitives und Agentic Capabilities. Testing, Health Checks, Contract Validation — nicht auf der Liste. Nicht erwähnt. Nicht geplant. 😾

Du bist also auf dich allein gestellt. Hier ist, wie du MCP-Server heute testen kannst — mit den Tools, die tatsächlich existieren.

Womit du arbeitest

Das MCP-Ökosystem hat ungefähr 17.000 registrierte Server. Community-Audits zeigen: etwa die Hälfte antwortet zu jedem beliebigen Zeitpunkt zuverlässig. Dein Agent verbindet sich mit drei Servern? Statistisch gesehen ist einer davon gerade instabil.

Testomat.io hat am 8. April die umfassendste Übersicht über MCP-Testing-Tools veröffentlicht. Ihr Fazit ist schonungslos: Nichts spricht MCP nativ für Tests. Alles ist Klebeband auf generischen HTTP-Frameworks. Kein Test-Runner versteht MCP-Transport. Keine Assertion-Library weiß, wie eine valide Tool-Response aussieht. Du baust den kompletten Testing-Stack von Grund auf für jeden Server, von dem du abhängst.

Hier ist das vollständige Inventar dessen, was existiert — und wie du es zum Laufen bringst.

MCP Inspector: der manuelle Startpunkt

MCP Inspector ist das offizielle Debugging-Tool — stell dir Postman für MCP vor. Du verbindest dich mit einem Server, rufst Tools manuell auf, inspizierst Responses.

Was es dir gibt:

  • Interaktive Tool-Discovery und Invocation
  • Raw-JSON-Response-Inspektion
  • Connection-Diagnostics für stdio und HTTP+SSE Transports

Was es nicht gibt:

  • CI-Integration
  • Regressionserkennung
  • Automatisierte Test-Suites
  • Response-Validierung gegen irgendein Schema

Es ist ein Schraubenzieher. Nützlich zum Rumstochern in der Entwicklung, wertlos gegen Regressionen in Production. Du brauchst ein Test-Harness. 😹

Wrapper-Tests bauen (der Klebeband-Ansatz)

Die meisten Teams, die MCP heute testen, schreiben Wrapper-Tests — ganz normale pytest- oder Jest-Suites, die Tools direkt über das MCP Client SDK aufrufen und die Rückgaben prüfen.

# pytest-Beispiel — einen MCP-Server-Tool testen
import json
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def test_search_tool_returns_results():
    server = StdioServerParameters(
        command="npx",
        args=["-y", "@example/mcp-search-server"]
    )
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            
            result = await session.call_tool(
                "search",
                arguments={"query": "test query", "limit": 5}
            )
            
            assert result.content is not None
            assert len(result.content) > 0
            assert result.content[0].type == "text"
            
            data = json.loads(result.content[0].text)
            assert "results" in data
            assert len(data["results"]) <= 5

Das funktioniert, bis der Upstream-Server sein Response-Format ändert. Was lautlos passiert, ohne Versionierung, ohne Changelogs — die MCP-Spec hat keine Semver-Konvention, kein Lockfile-Äquivalent, keinen Mechanismus für Breaking-Change-Ankündigungen. Deine Assertion prüft data["results"] — der Server benennt es an einem Dienstag um 2 Uhr nachts in data["items"] um. Best Case: Dein Test wird rot. Worst Case: Das Feld existiert noch, aber die innere Struktur ändert sich, dein Test bleibt grün, dein Agent halluziniert auf Basis kaputter Daten, und du zahlst pro halluziniertem Token.

Contract Testing ohne Contracts

Die fundamentale Lücke: MCP-Server veröffentlichen keine Response-Schemas. Die Spec beschreibt, was ein Tool tun sollte — in natürlicher Sprache. Sie bietet keinen maschinenlesbaren Contract zur Validierung.

Der Workaround: Generier dir deinen eigenen.

# Schritt 1: Echte Responses über Zeit aufzeichnen
from genson import SchemaBuilder

builder = SchemaBuilder()
for response in recorded_responses:  # aus Staging/Dev sammeln
    builder.add_object(json.loads(response))

inferred_schema = builder.to_schema()
# Speichere das in deinem Repo als "Contract"

# Schritt 2: In CI validieren
from jsonschema import validate, ValidationError

def test_tool_response_matches_contract():
    response = call_mcp_tool("search", {"query": "test"})
    try:
        validate(instance=response, schema=inferred_schema)
    except ValidationError as e:
        pytest.fail(f"Contract-Verletzung: {e.message}")

Der Prozess: Zeichne echte Responses des Servers über eine Woche auf. Leite ein JSON Schema aus diesen Responses mit einem Schema-Generator ab. Committe das Schema in dein Repo. Validiere zukünftige Responses dagegen in CI.

Es ist reverse-engineertes Contract Testing. Nicht elegant. Aber es fängt stille Upstream-Änderungen ab, die sonst unbemerkt in Production landen würden. Wenn das Schema bricht, bricht deine Pipeline — laut, in CI, nicht leise im Output deines Agents. 😸

Health Monitoring: Bau es oder bete

Dein Orchestrator pingt Docker-Container. Dein Load Balancer prüft /health. MCP-Server bieten keinen Health-Endpoint — die Spec definiert keinen. Ein Server antwortet entweder oder nicht, und du erfährst es erst, wenn der Tool-Call deines Agents hängt.

Bau deinen eigenen Health Check:

import asyncio
from datetime import datetime

async def check_mcp_health(server_params, timeout=10):
    try:
        async with asyncio.timeout(timeout):
            async with stdio_client(server_params) as (read, write):
                async with ClientSession(read, write) as session:
                    await session.initialize()
                    tools = await session.list_tools()
                    return {
                        "status": "healthy",
                        "tools_available": len(tools.tools),
                        "checked_at": datetime.utcnow().isoformat()
                    }
    except (asyncio.TimeoutError, Exception) as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "checked_at": datetime.utcnow().isoformat()
        }

Lass das per Cron laufen. Alarmiere bei aufeinanderfolgenden Fehlern. Prüfe nicht nur die Konnektivität, sondern auch die Tool-Liste — Server fügen Tools hinzu und entfernen sie ohne Vorwarnung, und wenn dein Agent search_v2 erwartet, nachdem der Server es stillschweigend entfernt hat, produziert das die Art von Fehler, die wie ein Agent-Bug aussieht, aber keiner ist.

Failure Injection: der Teil, den alle überspringen

Dein Agent ruft ein Tool auf. Das Tool hat einen Timeout. Was passiert dann?

Wenn du das nicht getestet hast, lautet die Antwort: Das Modell improvisiert. Es könnte endlos retrien. Es könnte die erwartete Response halluzinieren. Es könnte sich beim User entschuldigen und nichts tun. Du wirst es erst in Production erfahren, und Production berechnet dir die Lektion pro Token. 🙀

Wrappe deinen MCP-Client, um Fehler zu simulieren:

import random

class ChaosProxy:
    """Wrappt eine echte MCP-Session, um Fehler beim Testen zu injizieren."""
    def __init__(self, real_session, failure_rate=0.1, corruption_rate=0.05):
        self.session = real_session
        self.failure_rate = failure_rate
        self.corruption_rate = corruption_rate
    
    async def call_tool(self, name, arguments):
        # Timeout simulieren
        if random.random() < self.failure_rate:
            raise TimeoutError(f"Simulierter MCP-Timeout bei {name}")
        
        result = await self.session.call_tool(name, arguments)
        
        # Korrupte Response simulieren
        if random.random() < self.corruption_rate:
            return self._corrupt_response(result)
        
        return result
    
    def _corrupt_response(self, result):
        # Valides MCP-Envelope mit Datenmüll zurückgeben
        # Testet, ob dein Agent kaputte Daten graceful handelt
        ...

Schick deinen Agent durch diesen Proxy mit 10% Fehlerrate. Beobachte, wie er mit Timeouts, Datenmüll und fehlenden Tools umgeht. Fix die Bruchstellen. Erhöhe die Rate. Wiederhole, bis dein Agent graceful degradiert statt selbstbewusst halluziniert.

Der komplette Testing-Stack

So sieht ein getestetes MCP-Deployment heute aus — alles handgebaut, nichts davon standardisiert:

Ebene Tool Was es fängt
Manuelle Erkundung MCP Inspector 'Existiert dieses Tool und antwortet es?"
Unit Tests pytest/Jest Wrapper Response-Shape, Basisverhalten
Contract Tests Abgeleitetes JSON Schema Stille Upstream-Formatänderungen
Health Monitoring Custom Cron + Alerting Server-Ausfälle, Tool-List-Drift
Failure Injection Chaos-Proxy-Wrapper Agent-Verhalten unter Degradierung
Integration Tests End-to-End Agent-Runs Full-Pipeline-Regressionen

Standardisiertes Tooling, das die MCP-Spec für irgendetwas davon bereitstellt: null. Jede Ebene, die du baust, wartest, debuggst und neu baust du auch, wenn Transport-Änderungen deine Test-Infrastruktur sprengen. 😾

Die Stolperfallen, die dich erwischen werden

State Pollution. MCP-Tools können Seiteneffekte haben — Daten schreiben, Records löschen, Geld abbuchen. Die Spec definiert keinen Mock-Modus. Du baust entweder einen Fake-Server zum Testen, lässt Tests gegen Production laufen (gefährlich) oder betreibst eine Staging-Umgebung pro MCP-Dependency (teuer). Die meisten Teams testen gegen Production und hoffen. Hoffnung ist keine Testing-Strategie.

Transport Mismatch. Deine Tests laufen über stdio. Production läuft über HTTP+SSE. Die verhalten sich unter Last anders, timen unterschiedlich aus, fallen unterschiedlich aus. Teste beide Transports oder akzeptiere, dass deine Testumgebung nicht zu Production passt.

Auth Expiration. OAuth-Tokens laufen ab. Dein CI läuft um 3 Uhr nachts. Das Token ist um 2 Uhr abgelaufen. Dein Test schlägt fehl — nicht weil der Server kaputt ist, sondern weil Auth es ist. Handle Token-Refresh im Test-Setup oder du jagst stundenlang Phantom-Failures.

Tool List Drift. Server fügt ein Tool hinzu, entfernt ein Tool, benennt einen Parameter um — keine Benachrichtigung, kein Version-Bump. Teste Tool Discovery als Teil deiner Health Checks. Vergleiche die Tool-Liste gegen einen Known-Good-Snapshot. Alarmiere bei Änderungen.

Jetzt bist du gefährlich

Du kannst MCP-Server testen. Nicht weil das Protokoll dir hilft — die Roadmap vom 19. April bestätigt, dass es das so bald nicht priorisieren wird — sondern weil JSON Schema Validation, Chaos Engineering und Health Monitoring alles gelöste Probleme sind. Du kannst sie auf MCPs ungetestete Oberfläche draufschrauben mit normalem Python und einem Cron-Job.

Das Setup ist hässlich. Die Wartung ist manuell. Der gesamte Stack muss neu gebaut werden, wenn die Spec irgendwann Testing-Primitives einführt — falls sie das jemals tut.

Aber dein Agent hat jetzt getestete Dependencies statt Gebete. Das ist der Unterschied zwischen 'hat in der Demo funktioniert" und 'funktioniert in Production". Eins davon zahlt dein Gehalt. Das andere beschert dir eine Slack-Nachricht um 2 Uhr nachts von jemandem, der deinem Agent etwas Wichtiges anvertraut hat. 😼

MCP 2026 Roadmap (19. April 2026)Testomat.io — MCP Server Testing Tools