Skip to main content
Glama
shreyasKaturi2004

test-intelligence-mcp

test-intelligence-mcp

Ein MCP (Model Context Protocol) Server, der KI-Code-Agenten – Claude Code, Claude Desktop oder jeden anderen MCP-Client – die Fähigkeit gibt, die Testgesundheit eines Python-Repositorys zu analysieren: Coverage, flaky Tests und ML-basierte Pull-Request-Risikovorhersage.

Status: in aktiver Entwicklung. Diese README wächst mit jedem Meilenstein; siehe Build-Status unten für das, was heute real ist vs. was noch kommt.

Was es tut

Richten Sie es auf ein Python-Repository und Sie können in einem natürlichsprachlichen Gespräch mit einem MCP-fähigen Agenten:

  • Führen Sie die Testsuite des Repos mit Coverage aus und erhalten Sie echte, dateibasierte Zahlen zurück (analyze_coverage)

  • Führen Sie die Suite mehrmals aus und erkennen Sie echte flaky Tests, im Gegensatz zu reihenfolgeabhängigen oder umgebungsabhängigen Fehlern (detect_flaky_tests)

  • Persistieren Sie Testergebnisse in Postgres, um eine Historie über die Zeit aufzubauen (record_test_run)

  • Fragen Sie diese Historie wieder ab (get_test_history)

  • Trainieren Sie einen gradientenverstärkten Klassifikator auf der akkumulierten Laufhistorie, um vorherzusagen, welche Dateien in einem Pull-Request wahrscheinlich Tests brechen (train_risk_model)

  • Vergleichen Sie einen Branch mit einem Basis-Ref und erhalten Sie einen bewerteten Risikoscore pro geänderter Datei (predict_pr_risk)

Alles basiert auf echter Subprozess-Testausführung und echtem Parsing von coverage.json – nichts hier scraped Terminalausgaben oder fälscht Zahlen.

Related MCP server: Chisel

Warum MCP

MCP ist ein Protokoll (von Anthropic als Open Source veröffentlicht, jetzt weit verbreitet), das es einem KI-Agenten ermöglicht, Tools zu entdecken und aufzurufen, die von einem separaten Serverprozess über einen standardmäßigen JSON-RPC-Transport (stdio lokal oder HTTP/SSE remote) bereitgestellt werden. Anstatt eine benutzerdefinierte API zu entwickeln und den System-Prompt eines Agenten darüber zu unterrichten, exponieren Sie getypte Python-Funktionen als "Tools"; der Client entdeckt deren Namen, Argumentschemas und Docstrings automatisch und ruft sie während des Gesprächs auf. Dieses Projekt verwendet FastMCP, das ergonomische Python SDK, das auf dem offiziellen MCP-Spezifikation aufbaut – @mcp.tool() auf einer normalen getypten Funktion reicht aus, um sie zu exponieren.

Technologie-Stack

Bereich

Wahl

MCP-Server

FastMCP

Testausführung

pytest, pytest-cov, coverage.py (parst coverage.json)

Datenbank

PostgreSQL, async SQLAlchemy 2.0 (AsyncSession), asyncpg-Treiber

Migrationen

Alembic (versioniert, kein create_all())

ML

scikit-learn GradientBoostingClassifier

Git-Operationen

GitPython / subprocess

CI

GitHub Actions

Lokales Postgres

Docker + docker-compose

Paketverwaltung

uv

Repository-Layout

test-intelligence-mcp/
  src/test_intelligence/
    server.py       # FastMCP server + tool registration
    config.py        # typed settings, loaded from .env
    safety.py         # repo-path allowlist gate (see Safety below)
    paths.py            # cross-platform file-path normalization
    runners/               # pytest/coverage execution, JUnit + coverage.json parsing
    flaky/                   # multi-run comparison logic, order/seed control
    ml/                        # features.py, synthetic.py, training.py, prediction.py, model_store.py
    db/                        # SQLAlchemy models, session, query helpers
    git/                        # commit/branch metadata (repo_info.py), diff stats (diff.py)
  tests/                       # tests for THIS project's own code
    fixtures/                  # tiny throwaway repos the runner tests execute for real
  scripts/
    ci_report.py         # flaky-check + coverage summary, invoked by CI (see below)
  alembic/             # migration scripts
  .github/workflows/
    ci.yml              # runs on every PR — see Continuous Integration below
  docker-compose.yml  # local Postgres
  pyproject.toml
  .env.example

Einrichtung

1. Voraussetzungen

  • Python 3.11+

  • uv – ein schneller, moderner Ersatz für pip + venv + virtualenv, hier für Abhängigkeitsverwaltung und Ausführung von Befehlen verwendet. Unter Windows: winget install -e --id astral-sh.uv.

  • Docker Desktop – wird verwendet, um Postgres lokal über docker-compose auszuführen, sodass Sie Postgres nicht auf Ihrem Rechner installieren müssen. Unter Windows: winget install -e --id Docker.DockerDesktop.

2. Abhängigkeiten installieren

uv sync

uv sync liest pyproject.toml, löst einen gesperrten Abhängigkeitssatz auf (schreibt/verwendet uv.lock) und erstellt ein .venv/ – das uv-Äquivalent von pip install -r requirements.txt in einem frischen virtualenv, aber schneller und reproduzierbar über Maschinen hinweg.

3. Postgres starten

docker-compose up -d

Dies startet einen Postgres 16 Container, der in docker-compose.yml definiert ist, verfügbar auf localhost:5433 mit den in dieser Datei integrierten Anmeldeinformationen. (Port 5433, nicht der Postgres-Standard 5432, um eine Kollision zu vermeiden, falls Sie Postgres bereits nativ installiert haben – siehe docker-compose.yml für Details.) -d führt es im Hintergrund aus (detached). Überprüfen Sie, ob es gesund ist mit:

docker-compose ps

Sie sollten test-intelligence-postgres mit Status healthy sehen.

4. Umgebung konfigurieren

cp .env.example .env

Die Standardwerte in .env.example stimmen bereits mit den Anmeldeinformationen von docker-compose.yml überein, sodass Sie für die lokale Entwicklung normalerweise nichts ändern müssen, außer TI_ALLOWED_REPO_ROOTS (siehe Sicherheit unten).

5. Datenbankmigrationen anwenden

uv run alembic upgrade head

Alembic spielt jedes Migrationsskript unter alembic/versions/ der Reihe nach ab und bringt das Datenbankschema auf die neueste Version. Im Gegensatz zu SQLAlchemys Base.metadata.create_all() (das nur Tabellen erstellen kann, die dem aktuellen Modellcode entsprechen, ohne Erinnerung an vergangene Zustände), verfolgt Alembic die Schema-Historie als geordnete Kette von Skripten – so sind Änderungen in Git überprüfbar, reversibel (alembic downgrade) und werden identisch in Dev, CI und Produktion angewendet.

6. Bei einem MCP-Client registrieren

Claude Code

claude mcp add test-intelligence -- uv run --directory "C:\path\to\test-intelligence-mcp" test-intelligence-mcp

Die Verwendung von --directory (anstatt sich auf das Verzeichnis zu verlassen, von dem aus Sie claude mcp add ausgeführt haben) stellt sicher, dass die Registrierung unabhängig davon funktioniert, von wo der Prozess von Claude Code den Server später startet – wichtig, weil der Server .env relativ zu seinem Arbeitsverzeichnis beim Start liest.

Dies registriert den Server als MCP-Server mit stdio-Transport, der auf Ihre lokale Claude Code-Konfiguration beschränkt ist. Überprüfen Sie die Verbindung mit claude mcp list, starten Sie dann eine neue Claude Code-Sitzung (eine bereits laufende Sitzung erkennt einen nach ihrem Start registrierten Server nicht) und bitten Sie ihn, verfügbare Tools aufzulisten.

Claude Desktop

Fügen Sie zu claude_desktop_config.json hinzu (Windows: %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "test-intelligence": {
      "command": "uv",
      "args": ["--directory", "C:\\path\\to\\test-intelligence-mcp", "run", "test-intelligence-mcp"]
    }
  }
}

Starten Sie Claude Desktop neu; die sechs Tools sollten unter dem 🔨 Werkzeug-Symbol erscheinen.

Sicherheit

Da diese Tools die echte Testsuite eines Ziel-Repositorys – also beliebigen Python-Code – als Subprozess ausführen, werden zwei Schutzmaßnahmen bedingungslos durchgesetzt:

  • Pfad-Allowlist: jedes repo_path-Argument wird in einen absoluten Pfad aufgelöst und gegen TI_ALLOWED_REPO_ROOTS (eine kommagetrennte Liste erlaubter Basisverzeichnisse) in .env geprüft. Pfade außerhalb der Allowlist werden abgelehnt, bevor ein Subprozess ausgeführt wird.

  • Subprozess-Zeitüberschreitungen: jeder subprocess-Aufruf (ein pytest-Lauf, ein git-Befehl) hat eine harte Zeitüberschreitung (TI_SUBPROCESS_TIMEOUT_SECONDS in .env, Standard 300s), damit eine hängende oder Endlosschleifen-Suite den Server nicht unbegrenzt blockieren kann.

Anwendungsbeispiele

analyze_coverage

Fragen Sie einen MCP-fähigen Agenten etwas wie: "Führe analyze_coverage auf C:\path\to\some-repo aus". Das Tool führt die Testsuite dieses Repos mit Coverage aus (unter Verwendung seines eigenen .venv/venv, falls vorhanden, andernfalls fällt es auf den Interpreter dieses Servers zurück) und gibt zurück:

{
  "status": "ok",
  "tests_passed": true,
  "overall_coverage_percent": 87.5,
  "total_statements": 120,
  "total_covered_lines": 105,
  "total_uncovered_lines": 15,
  "files": [
    {
      "file": "pkg/calculator.py",
      "coverage_percent": 80.0,
      "num_statements": 10,
      "covered_lines": 8,
      "uncovered_line_count": 2,
      "uncovered_lines": [12, 13]
    }
  ]
}

files ist nach schlechtester Abdeckung zuerst sortiert, sodass ein Agent sofort auf die Dateien zeigen kann, die am meisten Tests benötigen. Erfordert, dass das Ziel-Repo pytest und pytest-cov in der aufgelösten Python-Umgebung installiert hat.

record_test_run + get_test_history

"Zeichne einen Testlauf für C:\path\to\some-repo auf und zeige mir dann die Historie für pkg/calculator.py" – der erste Aufruf führt die Suite einmal über pytest's --junitxml-Ausgabe aus (sodass pytest allein im Ziel-Repo ausreicht, kein Plugin nötig), persistiert einen Satz von Repository/TestRun/TestResult-Zeilen in Postgres und markiert den Lauf mit dem aktuellen Commit-SHA und Branch des Ziel-Repos (über GitPython), wenn es ein echtes Git-Repo ist:

{
  "status": "ok",
  "run_id": 3,
  "repo_id": 1,
  "commit_sha": "a1b2c3d...",
  "branch": "main",
  "duration_seconds": 0.52,
  "total_tests": 3,
  "passed_count": 1,
  "failed_count": 1,
  "skipped_count": 1
}

get_test_history liest nur Zeilen, die bereits von record_test_run geschrieben wurden – es löst selbst nie einen Lauf aus, und es fragt über jedes Repo ab, das dieser Server jemals aufgezeichnet hat (es gibt kein repo_path-Argument), optional gefiltert auf einen file_path:

{
  "status": "ok",
  "count": 2,
  "history": [
    {
      "repo_name": "C:\\path\\to\\some-repo",
      "run_id": 3,
      "commit_sha": "a1b2c3d...",
      "branch": "main",
      "started_at": "2026-08-16T00:20:11+00:00",
      "node_id": "tests/test_calculator.py::test_divide",
      "file_path": "tests/test_calculator.py",
      "outcome": "passed",
      "duration_seconds": 0.001,
      "error_message": null
    }
  ]
}

detect_flaky_tests

"Führe detect_flaky_tests auf C:\path\to\some-repo mit 5 Läufen aus" – führt die Suite runs Mal mit explizit deaktivierten bekannten Testreihenfolge-randomisierenden Plugins (pytest-randomly, pytest-random-order) aus, sodass die Testreihenfolge bei jedem Lauf identisch ist. Dies isoliert echten Nichtdeterminismus (Timing, gemeinsamer Zustand, ungesäte Zufälligkeit im getesteten Code) als einzige mögliche Erklärung dafür, dass ein Test mit sich selbst über Läufe hinweg nicht übereinstimmt – ein Plugin, das die Reihenfolge mischt, würde sonst reihenfolgeabhängige Fehler von echter Flakiness ununterscheidbar machen. Der Fortschritt wird live über MCP-Fortschrittsbenachrichtigungen gestreamt (sichtbar für Clients, die sie unterstützen), da 5+ aufeinanderfolgende Läufe bei einer großen Suite eine Weile dauern können:

{
  "status": "ok",
  "repo_id": 2,
  "runs_requested": 5,
  "runs_completed": 5,
  "total_tests_observed": 2,
  "flaky_test_count": 1,
  "flaky_tests": [
    {
      "node_id": "tests/test_flaky.py::test_alternates",
      "runs_observed": 5,
      "inconsistency_count": 2,
      "flakiness_rate": 0.4,
      "outcomes": ["passed", "failed", "passed", "failed", "passed"],
      "majority_outcome": "passed"
    }
  ],
  "run_failures": []
}

Erkannte flaky Tests werden ebenfalls in der flaky_reports-Tabelle persistiert.

train_risk_model

"Trainiere das Risikomodell" – trainiert einen GradientBoostingClassifier, um vorherzusagen: "Wird ein Test fehlschlagen, nachdem diese Datei geändert wurde?" aus 10 Merkmalen pro Datei (Churn, historische Fehleranzahl, aktuelle Coverage, Anzahl der Tests, die die Datei betreffen, Tage seit der letzten Änderung, verschiedene Autoren, Dateigröße, zyklomatische Komplexität – siehe Kaltstartstrategie für die Herkunft der Trainingsdaten), evaluiert auf einem zurückgehaltenen Split und berichtet ehrlich:

{
  "status": "ok",
  "model_path": "models/risk_model.joblib",
  "real_sample_count": 0,
  "synthetic_sample_count": 500,
  "total_sample_count": 500,
  "test_set_size": 125,
  "metrics": {
    "accuracy": 0.6,
    "precision": 0.5962,
    "recall": 0.5167,
    "f1": 0.5536
  },
  "caveat": "Only 0 real training example(s) recorded so far (via record_test_run) — this training run is dominated by synthetic, artificially-generated bootstrap data. These metrics describe how well the model fits that synthetic relationship, NOT real predictive power on an actual repository. Keep calling record_test_run on real repos, then retrain, before trusting these numbers for anything beyond confirming the training pipeline itself works."
}

Das caveat-Feld verschwindet erst, wenn real_sample_count einen echten Schwellenwert (30, siehe ml/training.py) überschreitet – dieses Tool präsentiert nie synthetisch dominierte Metriken, als ob sie gegen die Realität validiert wären.

(Verbleibende Tools werden pro Meilenstein ergänzt – siehe Build-Status.)

Kaltstartstrategie für das ML-Modell

train_risk_model benötigt gelabelte Beispiele – "Gegeben diese Merkmale über eine Dateiänderung, ist ein mit dieser Datei verbundener Test danach fehlgeschlagen?" Auf einem frisch eingerichteten Server wurden null Läufe aufgezeichnet, es gibt also keine Historie, aus der gelernt werden kann. Drei Optionen wurden abgewogen, bevor ML-Code geschrieben wurde:

  1. Die Git/CI-Historie eines echten Open-Source-Repos abspielen. Ein echtes Projekt klonen, seine Commits durchgehen, jeden auschecken, seine Abhängigkeiten so installieren, wie sie zu diesem Zeitpunkt in der Geschichte existierten, seine Suite ausführen, echte Features und echte Labels extrahieren. Die mit Abstand realistischsten Daten – aber teuer und fragil, um sie zuverlässig zu erstellen: Abhängigkeitsinstallationen brechen über Jahre der Geschichte hinweg (veraltete Pakete, Python-Versionsdrift), Vollständige-Historie-Checkouts sind langsam, und es fügt eine harte externe Abhängigkeit (ein bestimmtes Repo zu einem bestimmten Zeitpunkt) an das eigene CI dieses Projekts an, das dies bei jedem Lauf reproduzieren müsste.

  2. Die eigenen Commits dieses Projekts abspielen. Gleiche Idee, kleinerer Umfang – vermeidet das Kernkostenproblem nicht, und die eigene Geschichte dieses Projekts ist viel zu kurz und eng, um die Breite der Dateiänderungsmuster darzustellen, über die ein Allzweck-Risikomodell generalisieren sollte.

  3. Synthetische Daten generieren (ausgewählt). Merkmalsvektoren aus plausiblen Verteilungen ziehen und Labels aus einer bewusst entworfenen, domäneninformierten generativen Regel ableiten – mehr Churn + mehr vergangene Fehler + niedrigere Coverage + höhere Komplexität → höhere Fehlerwahrscheinlichkeit, plus Rauschen – anstatt eines Münzwurfs. Schnell, vollständig reproduzierbar, kein externes Repo erforderlich und ausreichend, um die gesamte Pipeline (Feature-Extraktion → Training → Evaluierung) heute ehrlich zu testen.

Der ehrliche Kompromiss: Ein Modell, das ausschließlich auf synthetischen Daten trainiert wurde, hat die Form einer plausiblen Risikobeziehung gelernt, nicht die echte. Seine Metriken auf zurückgehaltenen synthetischen Daten sehen vernünftig aus (~0.6 Genauigkeit, ROC-AUC ~0.67 – siehe tests/ml/test_synthetic.py), was nur beweist, dass die Pipeline funktioniert, nicht dass sie etwas über ein echtes Repository vorhersagt. train_risk_model mischt reale Beispiele ein, sobald welche existieren (über record_test_run → file_changes-Zeilen – siehe unten) und berichtet immer den real/synthetischen Split plus einen expliziten Hinweis, wenn reale Daten zu dünn sind, um ihnen zu vertrauen, anstatt jemals synthetisch abgeleitete Zahlen als validiert darzustellen.

Woher die echten Beispiele stammen: record_test_run berechnet nach jedem Durchlauf einen echten Git-Diff (HEAD~1..HEAD) und schreibt eine file_changes-Zeile pro geänderter Datei, gekennzeichnet mit tests_failed_after = "ist irgendein Test in diesem Durchlauf fehlgeschlagen" – angewendet auf jede darin geänderte Datei, nicht pro Datei zugeschrieben. Das ist eine bewusste Entscheidung: Die Zuschreibung eines Fehlschlags zur spezifischen Datei, die ihn verursacht hat, würde eine abdeckungsbasierte Verfolgung erfordern (welcher Test welche Quellzeilen ausgeführt hat), was dieses Projekt nicht tut. Das gröbere Signal ist ehrlich korrelativ ("diese Datei war Teil eines Commits, der etwas kaputt gemacht hat"), nicht kausal – siehe den Kommentar in runners/record_run.py für die vollständige Begründung, einschließlich warum eine Heuristik zum Abgleich von Dateipfad-Strings präziser ausgesehen hätte, während sie tatsächlich enger und irreführender gewesen wäre.

Die historische Merkmalsextraktion (verwendet für echte Trainingsbeispiele) liest den Git-Verlauf "zum Zeitpunkt" des jeweiligen aufgezeichneten Durchlaufs und Commits – git log --before, git show <sha>:<path> – niemals den aktuellen Zustand der Datei, sodass ein Modell nicht versehentlich mit Informationen trainiert werden kann, die zum Zeitpunkt der Vorhersage noch nicht existierten. coverage_percent ist das eine Merkmal, das historisch nicht rekonstruiert werden kann, ohne die gesamte Testsuite zu diesem genauen Commit erneut auszuführen (zu teuer, um es pro Trainingsbeispiel zu tun), daher wird es für echte historische Zeilen als expliziter "unbekannt"-Sentinel gespeichert und nur für Live-Vorhersagen frisch berechnet (predict_pr_risk, unten).

predict_pr_risk

"PR-Risiko für C:\path\to\some-repo gegen main vorhersagen" – differenziert base_ref..HEAD (ein echter git diff --numstat), extrahiert Live-Merkmale für jede geänderte Datei (aktueller Arbeitsverzeichnisstand, plus einen frischen analyze_coverage-Durchlauf für die aktuelle echte Abdeckung – nicht den "unbekannt"-Sentinel, den historische Trainingszeilen erhalten), bewertet jede mit dem trainierten Modell und sortiert nach höchstem Risiko zuerst:

{
  "status": "ok",
  "repo_id": 3,
  "base_ref": "0bcbeba860df0457c55ad3c1d3826ed5fd941506",
  "commit_sha": "8306f4598275f92907de89e1161f982772f3aac7",
  "model_trained_at": "2026-08-17T19:03:42.707577+00:00",
  "model_real_sample_count": 0,
  "predictions": [
    { "file": "tests/test_calculator.py", "predicted_risk_probability": 0.0743, "lines_added": 9, "lines_deleted": 1 },
    { "file": "pkg/calculator.py", "predicted_risk_probability": 0.0457, "lines_added": 7, "lines_deleted": 0 }
  ]
}

model_real_sample_count wird aus den Trainingsmetadaten des Modells übernommen – so kann ein Aufrufer auf einen Blick sehen, ob diese Vorhersagen von einem synthetisch dominierten Modell stammen (siehe Kaltstart-Strategie), ohne eine separate Abfrage. Erfordert, dass train_risk_model mindestens einmal ausgeführt wurde (andernfalls no_trained_model-Fehler) – dieses Tool trainiert niemals implizit ein Modell als Nebeneffekt. Jede Vorhersage wird in risk_predictions mit actual_outcome auf NULL gesetzt gespeichert, sodass die Vorhersagen eines echten Repositorys irgendwann mit dem tatsächlich Eingetretenen abgeglichen werden können – diese Auswertung ist noch nicht implementiert, aber die Daten werden von Anfang an erfasst, sodass sie ohne Schemaänderung hinzugefügt werden kann.

Kontinuierliche Integration (GitHub Actions)

GitHub Actions ist eine direkt in GitHub integrierte CI: Ein Workflow – eine YAML-Datei, .github/workflows/ci.yml – beschreibt Jobs, die automatisch als Reaktion auf Repository-Ereignisse ausgeführt werden (hier: Öffnen/Aktualisieren eines Pull Requests oder Pushen zu main). Jeder Job läuft auf einer frischen, temporären virtuellen Maschine (einem "Runner") – nichts bleibt zwischen den Läufen erhalten, außer was explizit zwischengespeichert oder hochgeladen wird – und ist nur eine Abfolge von Schritten, die jeweils entweder ein Shell-Befehl oder eine wiederverwendbare Aktion sind (ein veröffentlichter Schritt von jemand anderem, referenziert wie actions/checkout@v4).

Der Workflow dieses Projekts testet das Projekt selbst, Ende-zu-Ende:

  1. Repository auschecken und uv + Abhängigkeiten installieren – dieselben Tools, die ein Mitwirkender lokal installiert.

  2. Postgres als Service-Container starten – ein zweiter Container, den GitHub Actions parallel zum Job ausführt, erreichbar unter localhost:5433 von jedem Schritt aus, genau wie docker-compose up -d lokal, aber verwaltet von GitHub anstatt Docker Desktop. Die Job-Schritte beginnen erst, wenn der Healthcheck bestanden ist – keine manuell geschriebene "Warte auf Postgres"-Polling-Schleife erforderlich.

  3. Alembic-Migrationen anwenden, dann die eigene Testsuite dieses Projekts ausführen mit --cov-fail-under=$COVERAGE_THRESHOLD – pytest-cov's integrierter Gate; der Build schlägt sofort fehl, wenn die Abdeckung darunter fällt (derzeit 80 %, mit Spielraum unter den tatsächlichen ~93 %).

  4. detect_flaky_tests gegen die eigenen Tests dieses Projekts ausführen – über scripts/ci_report.py, das das Tool durch die echte MCP-Schicht aufruft (fastmcp.Client, der mit dem tatsächlichen Serverobjekt spricht), nicht eine Abkürzung. Nur informativ – es lässt den Build niemals fehlschlagen, nur die Abdeckung tut das.

  5. Beide Berichte als Workflow-Artefakte hochladen (actions/upload-artifact) – standardmäßig 90 Tage lang von der Seite des Workflow-Laufs herunterladbar.

  6. Eine Job-Zusammenfassung schreiben ($GITHUB_STEP_SUMMARY, als Markdown direkt auf der Seite des Laufs gerendert) und als PR-Kommentar posten (actions/github-script, unter Verwendung des integrierten GITHUB_TOKEN des Laufs – keine zusätzlichen Geheimnisse erforderlich). Die Schritt-Zusammenfassung ist der Fallback, der immer funktioniert, auch bei PRs von Forks, die einen schreibgeschützten Token erhalten, der keine Kommentare posten kann (eine GitHub-Sicherheitseinschränkung, kein Fehler in diesem Workflow) – der Kommentar-Schritt ist mit continue-on-error: true umschlossen, sodass diese Einschränkung elegant abgestuft wird, anstatt den gesamten Job fehlschlagen zu lassen.

Um dies tatsächlich laufen zu sehen, muss das Projekt in einem echten GitHub-Repository mit darauf gepushten Commits leben – nichts in diesem lokalen Build-Prozess hat eines erstellt. Sobald das existiert: Öffnen Sie einen PR, und der Reiter "Actions" (und der PR selbst, sobald der Kommentar eintrifft) zeigt den laufenden Vorgang.

Build-Status

Dieses Projekt wird Meilenstein für Meilenstein gebaut, jeder wird verifiziert, bevor es zum nächsten geht.

  • Meilenstein 1 – Projektskelett, docker-compose Postgres, .env.example, diese README

  • Meilenstein 2 – Datenbankschicht (SQLAlchemy-Modelle + Alembic)

  • Meilenstein 3 – FastMCP-Server-Skelett (6 registrierte Tools, Platzhalter-Rümpfe)

  • Meilenstein 4 – analyze_coverage

  • Meilenstein 5 – record_test_run + get_test_history

  • Meilenstein 6 – detect_flaky_tests

  • Meilenstein 7 – ML-Kaltstart-Strategie, Merkmalsextraktion, train_risk_model

  • Meilenstein 8 – predict_pr_risk

  • Meilenstein 9 – GitHub Actions CI (gebaut + lokal verifiziert; Live-PR-Lauf in Erwartung eines echten GitHub-Repositorys)

  • Meilenstein 10 – letzte Feinarbeit

Ausführen der eigenen Tests dieses Projekts

uv sync --extra dev     # installs pytest-asyncio + ruff on top of the base deps
uv run pytest -v
uv run pytest --cov --cov-report=term-missing   # with coverage
uv run ruff check .                              # lint

Die DB-Schichttests verwenden eine echte, wegwerfbare Postgres-Datenbank (test_intelligence_test, automatisch erstellt und abgebaut) und führen die tatsächlichen Alembic-Migrationen dagegen aus, anstatt die Datenbank zu mocken oder create_all() zu verwenden – derselbe Ansatz, den CI über seinen Postgres-Service-Container verwendet (Meilenstein 9). Siehe tests/conftest.py für Details.

Datenmodell

Sechs Tabellen, verwaltet durch Alembic-Migrationen:

  • repositories – ein verfolgtes Repository (Name + lokaler Pfad oder Remote-URL)

  • test_runs – eine Zeile pro pytest-Aufruf (Repository, Commit-SHA, Branch, Zeitstempel, Dauer, Anzahl bestanden/fehlgeschlagen/übersprungen)

  • test_results – eine Zeile pro Testknoten-ID innerhalb eines Laufs (Ergebnis, Dauer, Fehlermeldung)

  • file_changes – Datei-Diff-Statistiken pro Lauf (hinzugefügte/gelöschte Zeilen, ob Tests nach der Änderung fehlgeschlagen sind)

  • flaky_reports – Flakiness-Zusammenfassung pro Testknoten (beobachtete Läufe, Inkonsistenzanzahl, Erkennungszeitstempel)

  • risk_predictions – ML-Risikobewertungen pro Datei für einen Commit, plus tatsächliches Ergebnis, sobald bekannt (für die Offline-Bewertung des Modells)

Lizenz

MIT

Available Tools

6 tools
analyze_coverageA

Run the test suite with coverage and report real, per-file coverage numbers.

Executes pytest with pytest-cov against the target repository, then parses the machine-readable coverage.json report it produces (never the human-readable terminal summary) to compute overall coverage percentage, per-file coverage, and uncovered line counts.

ParametersJSON Schema
NameRequiredDescriptionDefault
repo_pathYesAbsolute path to the Python repository to analyse. Must resolve to a location under one of this server's allowed repo roots.
test_pathNoOptional path, relative to repo_path, restricting which tests to run (e.g. "tests/unit"). Defaults to the whole test suite.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that the tool executes pytest with pytest-cov, parses coverage.json (never the human-readable summary), and computes overall coverage, per-file coverage, and uncovered line counts. This is comprehensive for a coverage analysis tool, though it could mention any destructive effects or file modifications.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise at two sentences: the first line states the core purpose, and the second line details the execution and parsing behavior. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists (so return values are documented separately), the description adequately covers the tool's behavior, parameters, and execution context. It could mention prerequisites like pytest-cov installation, but for a tool with good schema coverage and output schema, this is mostly sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage, so the baseline is 3. The description adds value by explaining that test_path restricts which tests to run and defaults to the whole suite, and repo_path must be under allowed roots. However, it does not elaborate on the parameters further beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that this tool runs the test suite with coverage and reports real, per-file coverage numbers. It specifies the resource (test suite) and verb (analyze coverage), and the detail about parsing machine-readable coverage.json distinguishes it from any generic coverage tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool (for running pytest with pytest-cov and getting machine-readable per-file coverage), but it does not explicitly say when not to use it or mention alternatives like detect_flaky_tests or record_test_run. It implies usage for coverage analysis among siblings focused on flaky detection, risk prediction, and history.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detect_flaky_testsA

Run the test suite multiple times and flag tests with inconsistent outcomes.

Runs the full suite runs times, comparing each test's outcome (by its stable pytest node ID) across runs. A test that passes in some runs and fails in others is reported as flaky, along with its flakiness rate. Test order and random seeds are controlled so genuine flakiness isn't confused with order-dependent or environment-dependent failures.

ParametersJSON Schema
NameRequiredDescriptionDefault
runsNoHow many times to run the suite. Higher values give more confidence but take proportionally longer. Defaults to 5.
repo_pathYesAbsolute path to the Python repository to analyse. Must resolve to a location under one of this server's allowed repo roots.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations were provided, so the description carries the full burden. It discloses that the tool runs the full suite multiple times (potentially expensive), uses stable pytest node IDs, controls test order and seeds, and reports flakiness rates. However, it does not mention if the tool modifies any files or has any side effects beyond reporting.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and structured effectively. The first sentence immediately states the core purpose, followed by a short paragraph explaining the mechanism and guarantees. Every sentence adds essential information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that the tool has only 2 parameters with 100% schema coverage, an output schema exists, and no annotations are provided, the description sufficiently covers what the tool does, how it works, and what guarantees it provides (controlled order/seeds). There are no obvious gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value by explaining that runs controls the number of executions and that higher values give more confidence but take proportionally longer. It also clarifies that repo_path must be a Python repository and resolves under allowed roots. The first sentence of the description contextualizes both parameters together.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose using a specific verb-resource pair: 'Run the test suite multiple times and flag tests with inconsistent outcomes.' It immediately distinguishes itself from siblings by focusing on flakiness detection rather than coverage analysis, risk prediction, or history retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly suggests when to use this tool (to identify flaky tests) vs alternatives (e.g., analyze_coverage for coverage, get_test_history for historical results). It explains that test order and seeds are controlled to avoid false positives, but does not explicitly state when NOT to use it or provide direct comparisons to siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_test_historyA

Query previously recorded test run history from the database.

Reads rows written by record_test_run — this tool never triggers a new test run itself, it only reports on what's already been recorded.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of history entries to return, most recent first. Defaults to 50.
file_pathNoOptional file path to filter history down to test runs/results touching that specific file. Omit to get history across the whole repo.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description correctly identifies the tool as read-only ('never triggers a new test run', 'reports on what's already been recorded'). This adequately covers the main behavioral trait. However, it could add more details like handling of empty results or performance implications for large histories.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the main purpose, and no wasted words. The description efficiently conveys the tool's role and its safety characteristic.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only query tool with an output schema, the description covers purpose, read-only nature, and relationship to record_test_run. It doesn't mention ordering (most recent first) but that is in the parameter description. Minor gap in not stating that history is returned sorted, but overall complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with both parameters fully described. The description adds no additional parameter semantics beyond the schema, so baseline 3 is appropriate. The context about reading history is helpful but does not directly enhance parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it queries previously recorded test run history, with the verb 'query' and resource 'test run history'. It distinguishes from siblings by noting it reads rows written by record_test_run and never triggers a new test run, differentiating it from record_test_run and other tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states this tool is for reading existing history and never triggers a new test run, guiding the agent to use it when querying past results. It indirectly points to record_test_run as the alternative for writing, providing clear usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

predict_pr_riskA

Diff the current branch against a base ref and rank changed files by predicted risk.

Computes the file-level diff between HEAD and base_ref, extracts the same features the risk model was trained on for each changed file (churn, historical failure count, current coverage, etc.), and runs them through the trained GradientBoostingClassifier to produce a ranked risk score per file.

ParametersJSON Schema
NameRequiredDescriptionDefault
base_refNoThe git ref to diff the current branch against, e.g. "main" or a commit SHA. Defaults to "main".main
repo_pathYesAbsolute path to the Python repository to analyse. Must resolve to a location under one of this server's allowed repo roots.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral burden. It explains the internal steps (diffing, feature extraction, model inference) and names the model type (GradientBoostingClassifier), which aids transparency. However, it does not disclose side effects (e.g., does it write anything) or failure modes for missing refs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences: the first is a concise summary, the second provides helpful internal detail. Each sentence adds value, though the second could be slightly tighter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (2 params, 100% schema coverage, and an output schema exists), the description is largely sufficient. It explains how the tool works internally, which compensates for the lack of annotations, leaving no major gaps for typical use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters. The description calls out 'base_ref' implicitly by stating it diffs HEAD against base_ref, but does not add new semantics beyond the schema's default and description for base_ref.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool diffs the current branch against a base ref and ranks changed files by predicted risk. It uses specific verbs ('diff', 'rank') and resources ('changed files', 'predicted risk'), distinguishing it from siblings like 'analyze_coverage' or 'train_risk_model'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is used for assessing risk of changed files in a branch, which differs from siblings like 'detect_flaky_tests' or 'analyze_coverage'. It does not explicitly mention when not to use it or provide alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

record_test_runA

Execute the test suite once and persist the results to the database.

This is the explicit, distinct step that builds up the training data other tools (get_test_history, train_risk_model) rely on — it never runs implicitly as a side effect of another tool, so it's always clear when history is being written versus just read or analysed.

ParametersJSON Schema
NameRequiredDescriptionDefault
repo_pathYesAbsolute path to the Python repository to run. Must resolve to a location under one of this server's allowed repo roots.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, description carries full burden. It discloses that the tool executes a test suite (potentially side-effecting) and persists results, and it emphasizes the explicit, distinct nature preventing implicit side effects. It does not mention failure behavior or data overwrite semantics, but it provides security context (repo_path must resolve under allowed roots).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, first is direct action, second adds valuable context on when to use. No redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool executes arbitrary Python tests and persists data, description covers the core role and relation to siblings. Output schema exists, so return values are documented elsewhere. Missing some edge-case behavior but adequate for an AI agent to select and invoke.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers the only parameter fully with a description including absolute path and allowed root constraint. The tool description does not add further meaning, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description starts with a specific action: 'Execute the test suite once and persist the results to the database.' It clearly distinguishes from siblings by explaining that this is the explicit write step while get_test_history and train_risk_model consume the data, and it never runs implicitly, so it's unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains that this tool is the explicit step for writing history versus reading or analyzing, referencing sibling tools get_test_history and train_risk_model. It could be more explicit about when NOT to use it (e.g., for read-only queries, use get_test_history), but the contrast between 'written versus just read or analysed' provides clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

train_risk_modelA

Retrain the PR-risk classifier on everything currently in the database.

Trains a GradientBoostingClassifier using file_changes/test_results history as labelled examples (did a test tied to this file fail within N runs after the file changed?), then reports accuracy, precision, recall, and F1 on a held-out split. When the training set is small, the returned metrics come with an explicit caveat that they aren't yet statistically meaningful — this tool never reports metrics as trustworthy without that context.

Returns: Training set size and accuracy/precision/recall/F1, with an honest caveat attached when the training set is too small for the metrics to mean much.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully explains the tool's behavior: it trains a GradientBoostingClassifier, uses training history, reports metrics, and includes a caveat for small datasets. The disclosure about statistical meaningfulness is valuable. However, it doesn't mention how long training might take, whether it requires a running database, or if it's a destructive operation (overwrites the current model?), which would justify a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three well-structured paragraphs: first a one-liner summary, then technical detail, then returns section. Every sentence adds value without redundancy. It is concise (every sentence earns its place) and front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema is present, so return values are documented elsewhere. The description covers the algorithm, training data source, metric reporting with caveats, and honesty about statistical significance. This is complete for a training-tool description given the schema availability and zero parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, and schema description coverage is 100% (schema is empty). The description doesn't need to explain parameters, but it adds value by detailing the training process and metrics returned. Baseline is 4 due to no parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Retrain the PR-risk classifier on everything currently in the database') and specifies the algorithm (GradientBoostingClassifier) and output metrics. It distinguishes the tool from siblings like 'predict_pr_risk' (which presumably uses the model, not trains it) and 'analyze_coverage' (which analyzes coverage, not risk).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for retraining the model using historical data, with no explicit when-to-use or when-not-to-use guidance. However, given that all sibling tools have distinct purposes (e.g., 'predict_pr_risk' for predictions, 'analyze_coverage' for coverage), the context is clear enough. No alternatives or exclusions are stated, so score 4.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedanalyze_coverage
    • First observeddetect_flaky_tests
    • First observedget_test_history
    • First observedpredict_pr_risk
    • First observedrecord_test_run
    • First observedtrain_risk_model

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct function: coverage analysis, flaky detection, risk prediction, test execution recording, history querying, and model training. There is no functional overlap, and the descriptions clearly differentiate their purposes.

Naming Consistency4/5

Tool names consistently use a verb_noun pattern (e.g., analyze_coverage, detect_flaky_tests, train_risk_model). The pattern is clear and predictable, though 'record_test_run' and 'get_test_history' slightly shift the pattern (record vs. get, test_run vs. test_history), but it's still minor and readable.

Tool Count5/5

With 6 tools, the set is well-scoped for a CI/testing intelligence server. Each tool covers a necessary stage (record, query, analyze, detect flakiness, predict risk, train model), and none feel redundant or extraneous.

Completeness4/5

The tool set covers the core lifecycle: recording test runs (record_test_run), querying history (get_test_history), analyzing coverage (analyze_coverage), detecting flakiness (detect_flaky_tests), predicting risk (predict_pr_risk), and training the risk model (train_risk_model). A minor gap is the lack of a tool to delete or manage stored history, but the essential pipeline is complete.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A production-ready MCP server that provides comprehensive dbt project quality assessment for any GitHub repository, enabling AI agents to analyze dbt models, check metadata coverage, and map data lineage.
    8
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for test impact analysis and code intelligence. Maps tests to code and git history to determine impacted tests, risk scores, and ownership for AI coding agents.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    This MCP server enables automated maintenance and code analysis for Python/pytest repositories in isolated Docker environments. It supports read-only investigations, fix-and-verify tasks, and provides full audit trails with SQLite event history and artifact exports.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Analyzes codebases to produce structured quality health reports with risk-scored modules based on git churn, test coverage, and test-to-source mapping, acting as an MCP server for AI coding agents and a standalone CLI.
    MIT