groundtruth-mcp
groundtruth-mcp
Tu agente de codificación puede leer todos los archivos de tu repositorio y aun así estar adivinando. Esto convierte las comprobaciones, reproducciones, simulaciones y consultas propias de tu proyecto en herramientas MCP, de modo que observa las consecuencias de su edición en lugar de predecirlas.
Documentación en chino · Guía de adopción · Arquitectura · Por qué usar semillas fijas
El problema
Un agente que edita una configuración estructurada — un grafo de flujo de trabajo, un archivo de reglas, una máquina de estados, una definición de pipeline — está trabajando con el tipo de contexto equivocado. Puede leer el esquema. No puede leer qué ocurre cuando la cosa se ejecuta.
Por lo tanto, infiere. Cambia un límite de reintentos y te dice que el cambio es seguro, porque «seguro» era el siguiente token más plausible dado un diff que parecía razonable. Nadie ejecutó nada. La restricción que violó vive en un invariante a tres archivos de distancia, o en una distribución que nadie ha muestreado desde que la política se ajustó por última vez.
La solución no es un mejor prompt. Es darle al agente algo que observar.
Qué hace
flowchart LR
E[Agent edits a config] --> L[lint]
L -->|DANGLING_TRANSITION at states 1.transitions 0.to| E
E --> R[replay seed=7]
R -->|the 5 steps that actually ran| E
E --> S[simulate 2000 seeds]
S -->|88.3% success · p95 2566ms · PASS| E
S --> G["CI: groundtruth simulate --gate"]
G -->|same config, same thresholds| SCinco herramientas, construidas a partir de cuatro pequeñas funciones que tú escribes:
Herramienta | Responde | Propiedad que la hace útil |
| ¿Es esta configuración autoconsistente? | Cada incidencia lleva la ruta exacta a editar |
| ¿Qué ocurre cuando ejecuto esta? | Función pura de |
| ¿Mi cambio es mejor o peor en general? | Lote con semilla, distribución, umbrales, pasa/falla |
| ¿Qué hay realmente en los datos? | Solo lectura impuesta por la base de datos, no por una expresión regular |
| ¿Qué tablas existen? | Para que nada tenga que adivinar un esquema |
Las mismas capacidades se ejecutan como CLI, por lo que groundtruth simulate --gate es una puerta de merge que lee los mismos umbrales contra los que optimiza el agente. No pueden divergir, porque solo hay una copia.
Sesenta segundos
pip install "groundtruth-mcp[mcp]"
git clone https://github.com/ZhenGtai123/groundtruth-mcp && cd groundtruth-mcp
groundtruth --config examples/checkout-flow/groundtruth.toml lint broken_checkoutEl ejemplo incluido es un proceso de compra dirigido por configuración: cuatro páginas, una pasarela de pago inestable, una política de reintentos, clientes que se van. broken_checkout.json contiene los errores que un agente comete realmente cuando edita configuración que no puede ejecutar.
broken_checkout: BLOCKED errors=6 warnings=1 infos=0
source: flows\broken_checkout.json
-- ERRORS — these block (6) --
[DANGLING_TRANSITION] states[1].transitions[0].to 'payment_methd' does not name any states.id
fix: point it at an existing state id, or delete the transition
[DEAD_END] states[6] 'review_hold' has no outgoing edge and is not marked terminal — a run that arrives here stops with no result
fix: give it a transition, or mark it kind = "terminal" with an outcome
[DUPLICATE_STATE] states[2] duplicate id='shipping' (first declared at states[1])
fix: rename one of them; the engine silently uses the first and ignores the rest
[RATE_OUT_OF_RANGE] policy.gateway_failure_rate 1.4 is above the maximum 1.0
fix: this is a probability, not a percentage — 0.18, not 18
[RETRY_BUDGET_TOO_THIN] policy.max_retries 140% gateway failure with 1 retries leaves 196.0% of checkouts failing on payment alone (budget: 2.0%)
fix: raise max_retries, or lower gateway_failure_rate if the gateway improved
[UNKNOWN_STATE_KIND] states[3].kind 'stage' is not one of ['step', 'gateway', 'retry', 'terminal']
fix: the engine only knows these four kinds; anything else is treated as a plain step
-- WARNINGS (1) --
[UNREACHABLE_STATE] states[4] 'gift_wrap' cannot be reached from 'cart_review'
fix: no path from start reaches this state — delete it, or wire it inSeis de esos errores provienen de un archivo de reglas. RETRY_BUDGET_TOO_THIN proviene de ocho líneas de Python, porque «¿cumple este presupuesto de reintentos el objetivo de fallos del producto?» es aritmética, no un esquema.
Ahora observa una ejecución:
groundtruth --config examples/checkout-flow/groundtruth.toml replay standard_checkout --seed 3standard_checkout seed=3 outcome=success steps=7 fingerprint=52b66a2024a61b5d
metrics: latency_ms=2506 payment_attempts=2 steps=7
-- TRACE --
0. cart_review --always-->
1. shipping --always-->
2. payment_method --always-->
3. authorize --failure--> # attempt 1 declined
4. retry_decision --retries_left--> # 0 retry(s) used of 2
5. authorize --success--> # attempt 2 authorized
6. confirmed # terminal: successLa semilla 3 siempre produce esos siete pasos —en tu máquina, en CI, el año que viene—. Eso es lo que hace que valga la pena leerlo.
Y dos mil de ellos:
groundtruth --config examples/checkout-flow/groundtruth.toml \
simulate standard_checkout --runs 2000 --seed 0 --gate --check-determinismstandard_checkout: PASS runs=2000 base_seed=0 fingerprint=449e16b50c8184c0
-- OUTCOMES --
success: 1767 (88.3%)
abandoned: 227 (11.3%)
payment_failed: 6 (0.3%)
-- METRICS (mean / p50 / p95 / max) --
latency_ms: 1587.75 / 1553 / 2566 / 3626
payment_attempts: 1.06 / 1 / 2 / 3
steps: 5.12 / 5 / 7 / 10
-- THRESHOLDS --
PASS rate:success = 0.8835 expected >= 0.8 (below this, the flow is losing customers faster than the business case allows)
PASS rate:stuck = 0 expected <= 0 (a run with nowhere to go is always a config bug, never bad luck)
PASS p95:latency_ms = 2566 expected <= 4000 (95th-percentile checkout wall time, retries included)
PASS mean:payment_attempts = 1.0585 expected <= 1.6 (rising attempts mean the gateway is degrading or the retry policy is too eager)
note: determinism: 20 seeds re-ran identicallyLa parte que justifica su existencia
Sube un número —shipping.abandon_chance de 0.05 a 0.28, el tipo de edición que parece un ajuste de producto y pasa la revisión:
$ groundtruth lint standard_checkout
standard_checkout: OK errors=0 warnings=0 infos=0 # exit 0
$ groundtruth simulate standard_checkout --runs 2000 --seed 0 --gate
standard_checkout: FAIL runs=2000 base_seed=0 fingerprint=5a7c0d9feed5adca
-- OUTCOMES --
success: 1336 (66.8%)
abandoned: 660 (33.0%)
-- THRESHOLDS --
FAIL rate:success = 0.668 expected >= 0.8
PASS rate:stuck = 0 expected <= 0
PASS p95:latency_ms = 2549 expected <= 4000
PASS mean:payment_attempts = 0.795 expected <= 1.6
# exit 1Estructuralmente perfecto. Veintiún puntos de conversión perdidos. Ningún esquema, sistema de tipos ni revisión de código detecta eso; un lote con semilla y una banda declarada lo detecta en cuatro segundos, en el pull request, antes de que un humano lea el diff.
También funciona en la otra dirección. express_checkout presenta una tasa de éxito más alta que el flujo estándar —91,0%— y es la peor configuración: sus fallos de pago son del 3,9% frente al 0,3%, ocultos dentro de una cifra destacada que parece correcta. El agregado no lo ve; el validador escrito a mano lo dice con claridad:
[RETRY_BUDGET_TOO_THIN] policy.max_retries 18% gateway failure with 1 retries
leaves 3.2% of checkouts failing on payment alone (budget: 2.0%)Ninguna capa subsume a la otra. Por eso hay dos.
Cómo adoptarlo
Un módulo, un archivo de configuración. examples/checkout-flow/groundtruth_app.py es la plantilla completa —unas cien líneas, comentarios incluidos—.
from groundtruth_mcp import Context, Issue, Loaded, Toolkit, Trace
kit = Toolkit(name="my-project", subject_noun="pipeline")
@kit.loader
def load(name: str):
path = CONFIG_DIR / f"{name}.yaml"
if not path.is_file():
return None # → "no pipeline named X; available: ..."
return Loaded(subject=parse(path), source=str(path))
@kit.validator
def check(pipeline, ctx: Context) -> list[Issue]:
... # the checks a rule file can't express
@kit.runner
def run_once(pipeline, seed: int, ctx: Context) -> Trace:
... # one run, pure in (pipeline, seed)@kit.runner por sí solo te da tanto replay como simulate: la librería lo ejecuta una vez por semilla y conserva el resultado. Todo lo demás (agrupación de semillas, agregación, percentiles, control de umbrales, presupuesto de salida, redacción de errores, la superficie MCP) viene del paquete.
# groundtruth.toml
[project]
toolkit = "groundtruth_app:kit"
[lint]
rules = "rules.toml"
[[thresholds]]
metric = "rate:success"
min = 0.80
note = "why this number, for whoever has to change it"Luego groundtruth doctor te dice qué está conectado, groundtruth serve entrega las herramientas a un agente, y groundtruth simulate --gate bloquea el merge. Guía completa con ejemplos por dominio: docs/ADOPTION.md.
Reglas que obtienes gratis
Las comprobaciones estructurales se declaran, no se escriben. Doce tipos, cada uno cubre una forma en la que las configuraciones estructuradas realmente se degradan:
Tipo | Detecta | Campos clave |
| entradas a medio escribir |
|
| ids duplicados que el motor silencia |
|
| un valor que tu motor no maneja |
|
| una cadena donde corresponde un número |
|
|
|
|
| ids que rompen un contrato de nomenclatura |
|
| una lista vacía donde se requiere una entrada |
|
| una referencia a algo que fue renombrado |
|
| un nodo al que ningún camino desde el inicio alcanza |
|
| un nodo no terminal sin salida |
|
| un nodo que transiciona a sí mismo |
|
| un anillo sin salida (con una lista |
|
Los selectores son un lenguaje de rutas deliberadamente pequeño —states[].transitions[].to— y cada coincidencia informa de la ruta concreta en la que se encontró, que es lo que hace posible states[3].transitions[1].to en lugar de «una transición no es válida».
Cada regla acepta un code, una severity y un hint opcionales. El hint es la frase sobre la que actúa un agente, así que escríbela en imperativo.
Solo lectura significa solo lectura
query ejecuta un único SELECT. Dos capas lo garantizan, y no son equivalentes.
El escaneo de palabras clave es experiencia de usuario: rechaza DELETE FROM … con una frase que lo dice, en lugar de un error de base de datos que el modelo tiene que descifrar. no es el límite —una lista negra sobre texto siempre está a un caso de ser incorrecta, y la demostración canónica es SELECT * INTO audit_copy FROM users, que empieza con SELECT, no contiene ningún verbo denegado y crea una tabla.
El límite es el almacén de datos: mode=ro más PRAGMA query_only en SQLite, una transacción READ ONLY en PostgreSQL, y un tiempo de espera de sentencia en ambos. Las pruebas sortean por completo la protección y confirman que la conexión sigue rechazando.
La redacción de columnas es el único control a nivel de texto que sí es una medida de cumplimiento: los valores en deny_columns se eliminan después de la obtención y antes de que exista la cadena de resultado, por lo que SELECT * no puede filtrarlos. Todo lo devuelto se envuelve en etiquetas <untrusted>, porque una columna notes que contiene algo con forma de instrucción es un dato y debe llegar etiquetado como dato.
CLI
groundtruth [--config PATH] <command>
doctor what is wired up, what is missing
targets the configs this project exposes
lint TARGET exit 1 on errors
replay TARGET --seed N one deterministic run, full trace
simulate TARGET --runs N --seed N --gate --check-determinism
query "SELECT ..." one read-only statement
schema readable tables and columns
serve the MCP server, over stdioCódigos de salida: 0 limpio, 1 hallazgos (errores de lint, un umbral fuera de su banda, no determinismo), 2 no se pudo ejecutar (mala configuración, capacidad faltante, consulta rechazada). Añade --json a lint, replay y simulate para una salida legible por máquina.
Instalación
pip install groundtruth-mcp # core: rules, simulation, gating, CLI
pip install "groundtruth-mcp[mcp]" # + the MCP server
pip install "groundtruth-mcp[postgres]" # + the PostgreSQL data sourcePython 3.11+. El núcleo no tiene dependencias de terceros —es intencionado—, para que la puerta de CI no dependa del stack del agente. Un ejecutor básico puede hacer cumplir tus umbrales sin instalar un SDK.
Verificar una integración
python scripts/mcp_smoke.py [path/to/groundtruth.toml]Lanza el servidor como un subproceso real, inicializa a través de stdio, lista las herramientas, llama a dos de ellas e imprime lo que devuelve —la misma secuencia que realiza un cliente—. Ejecútalo antes de culpar al agente por no ver tus herramientas.
Lo que CI exige en cada pull request
No es una insignia que signifique «las pruebas se ejecutaron» —seis cosas, cada una de las cuales ha bloqueado algo:
Verificación | Por qué es una puerta y no una sugerencia |
| Incluye |
| El paquete incluye |
| 69 pruebas, cobertura mínima del 75% (actualmente 78% con cobertura de ramas) |
| Un subproceso real, stdio real, |
| El propio argumento del proyecto, aplicado a sí mismo |
| Un lint que no puede fallar es decorativo |
Limitaciones, expresadas con claridad
La lista blanca de tablas SQL es textual. Escanea identificadores después de
FROMyJOIN. La aplicación real por tabla es un permiso de base de datos; esto es una salvaguarda con un buen mensaje de error, y la transacción de solo lectura es lo que realmente aguanta.La lista negra de palabras clave coincide dentro de literales de cadena. Una consulta que filtra por un valor que contiene
grantes rechazada. Arreglar eso requiere un parser SQL real, que no merece la pena construir cuando el parser no es el límite.El
LIMITautomático es una heurística. UnLIMITdentro de una subconsulta suprime la adición de nivel superior.max_rowssigue limitando lo que se muestra.Los selectores no filtran.
states[].transitions[]recorre todo; no existestates[kind=terminal]. Un lenguaje de predicados sería la tercera característica que nadie pidió. Escribe un@kit.validatoren su lugar.Los umbrales son para todo el proyecto, no por destino. Cada destino de un proyecto se evalúa con las mismas bandas. Los proyectos cuyas configuraciones necesitan bandas realmente distintas deberían ser archivos
groundtruth.tomlseparados.El origen de datos de PostgreSQL está implementado pero poco ejercitado —el conjunto de pruebas demuestra el límite contra SQLite, donde puede ejecutarse en cualquier lugar sin un contenedor de servicio.
De dónde viene esto
Extraído de una base de código privada donde el patrón se ganó su lugar: un pipeline de autoría cuyos colaboradores seguían enviando configuraciones que pasaban la validación de esquema y fallaban en tiempo de ejecución. Las partes específicas del dominio quedaron atrás. Lo que se generalizó fue la forma — check, replay, simulate, query — más un conjunto de decisiones que resultaron importar más que la lista de características:
Una lista de umbrales, leída tanto por el agente como por CI, porque dos copias se desincronizaron y la herramienta estuvo un tiempo reportando PASS sobre números que CI habría rechazado.
Errores que nombran las alternativas válidas en línea, porque un agente que tiene que hacer una segunda llamada para aprender qué puede pasar, en su lugar adivinará.
Descripciones de herramientas compuestas a partir de la configuración en vivo, porque una descripción obsoleta es una herramienta que el agente usa de manera incorrecta y con confianza.
Salida limitada en cada ruta, porque una consulta entusiasta puede desalojar el resto de la conversación.
docs/ARCHITECTURE.md contiene el mapa de módulos y el razonamiento completo.
Licencia
MIT.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Free public MCP for AI agents — 193 tools, 44 workflows. No API key.
Agent Replay Debugger MCP — record every agent step + deterministic replay. Step-debugger for
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ZhenGtai123/groundtruth-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server