Skip to main content
Glama
shreyasKaturi2004

test-intelligence-mcp

test-intelligence-mcp

Un servidor MCP (Protocolo de Contexto de Modelo) que proporciona a los agentes de codificación de IA — Claude Code, Claude Desktop o cualquier otro cliente MCP — la capacidad de analizar la salud de las pruebas de un repositorio Python: cobertura, pruebas inestables y predicción de riesgos en pull requests basada en ML.

Estado: en desarrollo activo. Este README crece con cada hito; consulte Estado de compilación a continuación para ver qué es real hoy vs. qué está por venir.

Qué hace

Apúntelo a un repositorio Python y, desde una conversación en lenguaje natural con un agente compatible con MCP, puede:

  • Ejecutar la suite de pruebas del repositorio con cobertura y obtener números reales por archivo (analyze_coverage)

  • Ejecutar la suite varias veces y detectar pruebas genuinamente inestables, a diferencia de fallos dependientes del orden o del entorno (detect_flaky_tests)

  • Persistir los resultados de las ejecuciones de pruebas en Postgres para construir un historial a lo largo del tiempo (record_test_run)

  • Consultar ese historial (get_test_history)

  • Entrenar un clasificador potenciado por gradiente en el historial de ejecuciones acumulado para predecir qué archivos en una pull request probablemente romperán las pruebas (train_risk_model)

  • Comparar una rama con una referencia base y obtener una puntuación de riesgo clasificada por archivo modificado (predict_pr_risk)

Todo está respaldado por la ejecución real de pruebas en subprocesos y el análisis real de coverage.json — nada aquí extrae la salida del terminal o inventa números.

Related MCP server: Chisel

Por qué MCP

MCP es un protocolo (código abierto por Anthropic, ahora ampliamente adoptado) que permite a un agente de IA descubrir y llamar a herramientas expuestas por un proceso servidor separado, a través de un transporte JSON-RPC estándar (stdio localmente, o HTTP/SSE de forma remota). En lugar de crear una API personalizada y enseñar el prompt del sistema del agente sobre ella, expone funciones Python tipadas como "herramientas"; el cliente descubre sus nombres, esquemas de argumentos y cadenas de documentación automáticamente y las llama en medio de la conversación. Este proyecto utiliza FastMCP, el SDK Python ergonómico construido sobre la especificación oficial de MCP — @mcp.tool() en una función tipada normal es suficiente para exponerla.

Pila tecnológica

Aspecto

Elección

Servidor MCP

FastMCP

Ejecución de pruebas

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

Base de datos

PostgreSQL, SQLAlchemy 2.0 asíncrono (AsyncSession), controlador asyncpg

Migraciones

Alembic (versionadas, sin create_all())

ML

scikit-learn GradientBoostingClassifier

Operaciones Git

GitPython / subprocess

CI

GitHub Actions

Postgres local

Docker + docker-compose

Gestión de paquetes

uv

Estructura del repositorio

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

Configuración

1. Requisitos previos

  • Python 3.11+

  • uv — un reemplazo rápido y moderno para pip + venv + virtualenv, utilizado aquí para la gestión de dependencias y la ejecución de comandos. En Windows: winget install -e --id astral-sh.uv.

  • Docker Desktop — se utiliza para ejecutar Postgres localmente a través de docker-compose, por lo que no necesita tener Postgres instalado en su máquina. En Windows: winget install -e --id Docker.DockerDesktop.

2. Instalar dependencias

uv sync

uv sync lee pyproject.toml, resuelve un conjunto de dependencias bloqueadas (escribiendo/usando uv.lock) y crea un .venv/ — el equivalente de uv a pip install -r requirements.txt dentro de un virtualenv nuevo, pero más rápido y reproducible entre máquinas.

3. Iniciar Postgres

docker-compose up -d

Esto inicia un contenedor de Postgres 16 definido en docker-compose.yml, expuesto en localhost:5433 con las credenciales incluidas en ese archivo. (Puerto 5433, no el 5432 predeterminado de Postgres, para evitar una colisión si ya tiene Postgres instalado de forma nativa — consulte docker-compose.yml para más detalles). -d lo ejecuta en segundo plano (detached). Verifique que esté saludable con:

docker-compose ps

Debería ver test-intelligence-postgres con estado healthy.

4. Configurar el entorno

cp .env.example .env

Los valores predeterminados en .env.example ya coinciden con las credenciales de docker-compose.yml, por lo que para el desarrollo local normalmente no necesita cambiar nada excepto TI_ALLOWED_REPO_ROOTS (consulte Seguridad a continuación).

5. Aplicar migraciones de base de datos

uv run alembic upgrade head

Alembic reproduce cada script de migración bajo alembic/versions/ en orden, actualizando el esquema de la base de datos a la última versión. A diferencia de Base.metadata.create_all() de SQLAlchemy (que solo puede crear tablas que coincidan con lo que dice el código del modelo actual, sin memoria de estados pasados), Alembic rastrea el historial del esquema como una cadena ordenada de scripts — por lo que los cambios son revisables en git, reversibles (alembic downgrade) y se aplican de manera idéntica en desarrollo, CI y producción.

6. Registrar con un cliente MCP

Claude Code

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

Usar --directory (en lugar de confiar en el directorio desde el que ejecutó claude mcp add) hace que el registro funcione independientemente del directorio desde el que el proceso de Claude Code inicie el servidor más tarde — importante porque el servidor lee .env relativo a su directorio de trabajo al inicio.

Esto registra el servidor como un servidor MCP de transporte stdio con alcance en su configuración local de Claude Code. Verifique que esté conectado con claude mcp list, luego inicie una nueva sesión de Claude Code (una sesión ya en ejecución no recogerá un servidor registrado después de que comenzó) y pídale que liste las herramientas disponibles.

Claude Desktop

Agregue a claude_desktop_config.json (Windows: %APPDATA%\Claude\claude_desktop_config.json):

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

Reinicie Claude Desktop; las seis herramientas deberían aparecer bajo el icono de herramientas 🔨.

Seguridad

Debido a que estas herramientas ejecutan la suite de pruebas real de un repositorio de destino — es decir, código Python arbitrario — como un subproceso, se aplican dos barreras de seguridad de forma incondicional:

  • Lista blanca de rutas: cada argumento repo_path se resuelve a una ruta absoluta y se verifica contra TI_ALLOWED_REPO_ROOTS (una lista separada por comas de directorios base permitidos) en .env. Las rutas fuera de la lista blanca se rechazan antes de que se ejecute cualquier subproceso.

  • Tiempos de espera de subprocesos: cada llamada a subprocess (una ejecución de pytest, un comando git) tiene un tiempo de espera máximo (TI_SUBPROCESS_TIMEOUT_SECONDS en .env, por defecto 300s) para que una suite colgada o en bucle infinito no pueda bloquear el servidor indefinidamente.

Ejemplos de uso

analyze_coverage

Pida a un agente compatible con MCP algo como: "Ejecuta analyze_coverage en C:\ruta\a\algún-repo". La herramienta ejecuta la suite de pruebas de ese repositorio con cobertura (usando su propio .venv/venv si lo tiene, de lo contrario recurre al intérprete de este servidor) y devuelve:

{
  "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 está ordenado primero el peor cubierto, por lo que un agente puede señalar inmediatamente los archivos que más necesitan pruebas. Requiere que el repositorio de destino tenga pytest y pytest-cov instalados en el entorno Python que se resuelva.

record_test_run + get_test_history

"Registra una ejecución de prueba para C:\ruta\a\algún-repo, luego muéstrame el historial de pkg/calculator.py" — la primera llamada ejecuta la suite una vez a través de la salida --junitxml de pytest (por lo que solo pytest es suficiente en el repositorio de destino, no se necesita ningún complemento), persiste un conjunto de filas Repository/TestRun/TestResult en Postgres, y etiqueta la ejecución con el SHA y la rama del commit actual del repositorio de destino (a través de GitPython) cuando es un repositorio git real:

{
  "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 solo lee filas ya escritas por record_test_run — nunca desencadena una ejecución por sí mismo, y consulta en todos los repositorios que este servidor haya registrado alguna vez (no hay argumento repo_path), opcionalmente filtrado a un 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

"Ejecuta detect_flaky_tests en C:\ruta\a\algún-repo con 5 ejecuciones" — ejecuta la suite runs veces con complementos conocidos de aleatorización de orden de pruebas (pytest-randomly, pytest-random-order) explícitamente deshabilitados, por lo que el orden de las pruebas es idéntico en cada ejecución. Eso aísla el no determinismo genuino (tiempo, estado compartido, aleatoriedad sin semilla en el código bajo prueba) como la única explicación posible para que una prueba no esté de acuerdo consigo misma entre ejecuciones — un complemento que mezcle el orden haría que los fallos dependientes del orden fueran indistinguibles de la inestabilidad real. El progreso se transmite en vivo a través de notificaciones de progreso de MCP (visibles para los clientes que las admiten) ya que 5 o más ejecuciones secuenciales en una suite grande pueden llevar un tiempo:

{
  "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": []
}

Las pruebas inestables detectadas también se persisten en la tabla flaky_reports.

train_risk_model

"Entrena el modelo de riesgo" — entrena un GradientBoostingClassifier para predecir "¿fallará una prueba después de que cambie este archivo?" a partir de 10 características por archivo (cambio, recuento histórico de fallos, cobertura actual, recuento de pruebas que tocan el archivo, días desde la última modificación, autores distintos, tamaño del archivo, complejidad ciclomática — consulte Estrategia de arranque en frío para saber de dónde provienen los datos de entrenamiento), evalúa en una división reservada e informa honestamente:

{
  "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."
}

El campo caveat solo desaparece una vez que real_sample_count supera un umbral real (30, consulte ml/training.py) — esta herramienta nunca presenta métricas dominadas por datos sintéticos como si estuvieran validadas contra la realidad.

(Las herramientas restantes se completan por hito — consulte Estado de compilación.)

Estrategia de arranque en frío para el modelo de ML

train_risk_model necesita ejemplos etiquetados — "dadas estas características sobre un cambio de archivo, ¿falló una prueba vinculada a ese archivo después?" En un servidor recién configurado, no se ha registrado ninguna ejecución, por lo que no hay historial del que aprender. Se sopesaron tres opciones antes de escribir cualquier código de ML:

  1. Reproducir el historial git/CI de un repositorio real de código abierto. Clonar un proyecto real, recorrer sus commits, verificar cada uno, instalar sus dependencias tal como existían en ese punto de la historia, ejecutar su suite, extraer características reales y etiquetas reales. Los datos más realistas con diferencia — pero costosos y frágiles de construir de manera confiable: la instalación de dependencias se rompe a lo largo de años de historia (paquetes obsoletos, desviación de versiones de Python), las verificaciones de historial completo son lentas y agrega una dependencia externa difícil (un repositorio específico, en un punto específico en el tiempo) al propio CI de este proyecto, que necesitaría reproducirlo en cada ejecución.

  2. Reproducir los commits de este propio proyecto. Misma idea, alcance más pequeño — no evita el problema de costo central, y la propia historia de este proyecto es demasiado corta y estrecha para representar la amplitud de patrones de cambio de archivo que un modelo de riesgo de propósito general debería generalizar.

  3. Generar datos sintéticos (elegido). Extraer vectores de características de distribuciones plausibles y derivar etiquetas de una regla generativa diseñada deliberadamente e informada por el dominio — más cambio + más fallos pasados + menor cobertura + mayor complejidad → mayor probabilidad de fallo, más ruido — en lugar de un lanzamiento de moneda. Rápido, completamente reproducible, no requiere repositorio externo y suficiente para ejercitar el pipeline completo (extracción de características → entrenamiento → evaluación) de manera honesta hoy.

La compensación honesta: un modelo entrenado puramente con datos sintéticos ha aprendido la forma de una relación de riesgo plausible, no la real. Sus métricas en datos sintéticos reservados parecen razonables (~0.6 de precisión, ROC-AUC ~0.67 — consulte tests/ml/test_synthetic.py), lo que solo demuestra que el pipeline funciona, no que predice algo sobre un repositorio real. train_risk_model mezcla ejemplos reales en el momento en que existen (a través de record_test_run → filas file_changes — consulte a continuación) y siempre informa la división real/sintética más una advertencia explícita cuando los datos reales son demasiado escasos para confiar, en lugar de presentar números derivados de sintéticos como si estuvieran validados.

De dónde vienen los ejemplos reales: record_test_run calcula un diff real de git (HEAD~1..HEAD) después de cada ejecución y escribe una fila file_changes por archivo modificado, etiquetada con tests_failed_after = "¿falló alguna prueba en esta ejecución?" — aplicado a cada archivo modificado en ella, no una atribución por archivo. Esa es una elección deliberada: atribuir un fallo al archivo específico que lo causó requeriría un rastreo basado en cobertura (qué prueba ejecutó qué líneas de código fuente), algo que este proyecto no hace. La señal más gruesa es honestamente correlacional ("este archivo fue parte de un commit que rompió algo"), no causal — consulte el comentario en runners/record_run.py para el razonamiento completo, incluyendo por qué una heurística de coincidencia de ruta de archivo habría parecido más precisa mientras que en realidad era más limitada y engañosa.

La extracción histórica de características (utilizada para ejemplos de entrenamiento reales) lee el historial de git "a partir de" la marca de tiempo y el commit de cada ejecución registrada — git log --before, git show <sha>:<path> — nunca el estado actual del archivo, para que un modelo no pueda entrenarse accidentalmente con información que aún no existía en el momento de la predicción. coverage_percent es la única característica que no se puede reconstruir históricamente sin volver a ejecutar la suite completa en ese commit exacto (demasiado costoso para hacerlo por ejemplo de entrenamiento), por lo que se almacena como un centinela explícito "desconocido" para filas históricas reales, y solo se calcula en fresco para predicciones en vivo (predict_pr_risk, a continuación).

predict_pr_risk

"Predecir riesgo de PR para C:\ruta\a\algún-repo contra main" — compara base_ref..HEAD (un git diff --numstat real), extrae características en vivo para cada archivo modificado (estado actual del árbol de trabajo, más una ejecución fresca de analyze_coverage para la cobertura actual real — no el centinela "desconocido" que obtienen las filas de entrenamiento históricas), puntúa cada uno con el modelo entrenado y clasifica el de mayor riesgo primero:

{
  "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 se transmite desde los metadatos de entrenamiento del modelo — para que un llamador pueda ver de un vistazo si estas predicciones provienen de un modelo dominado por sintéticos (consulte Estrategia de arranque en frío) sin una búsqueda separada. Requiere que train_risk_model se haya ejecutado al menos una vez (de lo contrario, error no_trained_model) — esta herramienta nunca entrena un modelo implícitamente como efecto secundario. Cada predicción se persiste en risk_predictions con actual_outcome dejado como NULL, para que las predicciones de un repositorio real puedan eventualmente verificarse contra lo que realmente sucedió — esa evaluación aún no está construida, pero los datos se capturan desde el primer día para que se pueda agregar sin un cambio de esquema.

Integración Continua (GitHub Actions)

GitHub Actions es CI integrado directamente en GitHub: un workflow — un archivo YAML, .github/workflows/ci.yml — describe jobs que se ejecutan automáticamente en respuesta a eventos del repositorio (aquí: abrir/actualizar un pull request, o hacer push a main). Cada job se ejecuta en una máquina virtual nueva y desechable (un "runner") — no persiste nada entre ejecuciones excepto lo que se almacena explícitamente en caché o se sube — y es solo una secuencia de steps, cada uno ya sea un comando de shell o una action reutilizable (un paso empaquetado publicado por otra persona, referenciado como actions/checkout@v4).

El workflow de este proyecto es el proyecto probándose a sí mismo, de principio a fin:

  1. Revisar el repositorio e instalar uv + dependencias — las mismas herramientas que un colaborador instala localmente.

  2. Iniciar Postgres como un contenedor de servicio — un segundo contenedor que GitHub Actions ejecuta junto al job, accesible en localhost:5433 desde cada paso, exactamente como docker-compose up -d localmente pero gestionado por GitHub en lugar de Docker Desktop. Los pasos del job no comienzan hasta que su healthcheck pase — no se necesita un bucle de sondeo "esperar a Postgres" escrito a mano.

  3. Aplicar migraciones de Alembic, luego ejecutar la suite de pruebas de este propio proyecto con --cov-fail-under=$COVERAGE_THRESHOLD — la puerta de enlace incorporada de pytest-cov; la compilación falla directamente si la cobertura cae por debajo de ella (actualmente 80%, con margen por debajo del ~93% real).

  4. Ejecutar detect_flaky_tests contra las pruebas de este propio proyecto — a través de scripts/ci_report.py, que llama a la herramienta a través de la capa MCP real (fastmcp.Client hablando con el objeto del servidor real), no un atajo. Solo informativo — nunca falla la compilación, solo la cobertura.

  5. Subir ambos informes como artefactos del workflow (actions/upload-artifact) — descargables desde la página de ejecución del workflow durante 90 días por defecto.

  6. Escribir un resumen del job ($GITHUB_STEP_SUMMARY, renderizado como Markdown directamente en la página de la ejecución) y publicarlo como un comentario en el PR (actions/github-script, usando el GITHUB_TOKEN incorporado de la ejecución — no se necesitan secretos adicionales). El resumen del paso es el plan de respaldo que siempre funciona, incluso para PRs de forks, que obtienen un token de solo lectura que no puede publicar comentarios (una restricción de seguridad de GitHub, no un error en este workflow) — el paso de comentario está envuelto en continue-on-error: true para que esa limitación se degrade con gracia en lugar de fallar todo el job.

Para ver esto realmente ejecutarse, el proyecto necesita estar en un repositorio real de GitHub con commits enviados a él — nada en este proceso de compilación local ha creado uno todavía. Una vez que eso exista: abra un PR, y la pestaña Actions (y el PR mismo, una vez que llegue el comentario) lo mostrará ejecutándose en vivo.

Estado de la compilación

Este proyecto se construye hito por hito, cada uno verificado como funcional antes de pasar al siguiente.

  • Hito 1 — esqueleto del proyecto, docker-compose Postgres, .env.example, este README

  • Hito 2 — capa de base de datos (modelos SQLAlchemy + Alembic)

  • Hito 3 — esqueleto del servidor FastMCP (6 herramientas registradas, cuerpos placeholder)

  • Hito 4 — analyze_coverage

  • Hito 5 — record_test_run + get_test_history

  • Hito 6 — detect_flaky_tests

  • Hito 7 — Estrategia de arranque en frío de ML, extracción de características, train_risk_model

  • Hito 8 — predict_pr_risk

  • Hito 9 — CI de GitHub Actions (construido + verificado localmente; ejecución de PR en vivo pendiente de un repositorio real de GitHub)

  • Hito 10 — pulido final

Ejecución de las pruebas de este proyecto

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

Las pruebas de la capa de base de datos utilizan una base de datos Postgres real y desechable (test_intelligence_test, creada y eliminada automáticamente) y ejecutan las migraciones reales de Alembic contra ella, en lugar de simular la base de datos o usar create_all() — el mismo enfoque que CI usa a través de su contenedor de servicio Postgres (Hito 9). Consulte tests/conftest.py para más detalles.

Modelo de datos

Seis tablas, gestionadas por migraciones de Alembic:

  • repositories — un repositorio rastreado (nombre + ruta local o URL remota)

  • test_runs — una fila por invocación de pytest (repositorio, SHA del commit, rama, marca de tiempo, duración, recuentos de aprobados/fallidos/saltados)

  • test_results — una fila por ID de nodo de prueba dentro de una ejecución (resultado, duración, mensaje de error)

  • file_changes — estadísticas de diff por archivo para una ejecución (líneas añadidas/eliminadas, si las pruebas fallaron después del cambio)

  • flaky_reports — resumen de inestabilidad por nodo de prueba (ejecuciones observadas, recuento de inconsistencia, marca de tiempo de detección)

  • risk_predictions — puntuaciones de riesgo de ML por archivo para un commit, más el resultado real una vez conocido (para evaluación fuera de línea del modelo)

Licencia

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