Agent Output Verifier
Verifica de forma independiente la salida de un agente antes de pagar: estructura, formatos, rangos y reglas entre campos, con una atestación firmada y un recibo. 3 llamadas gratuitas al día, luego x402 v2.
Servidor MCP alojado
npx add-mcp 'https://fastapi-service-5ag4.onrender.com/mcp'Se instala en Claude Code, Codex, Cursor y más
Documentación
Agent Output Verifier
Verifica de forma independiente la salida de un agente antes de pagar.
Comprobaciones independientes y deterministas para facturas, entregables y cualquier salida estructurada: estructura, formatos, rangos y reglas entre campos, como "los totales de línea deben ser iguales al total", según tus propios requisitos, escritos en JSON Schema estándar más reglas opcionales. Devuelve aprobado/rechazado, el porcentaje de comprobaciones superadas, sugerencias de corrección y una atestación firmada con Ed25519 y un recibo que cualquiera puede verificar con nuestra clave pública. Vendedores: comprueben su propia salida antes de enviarla y entréguenla con una atestación firmada y un recibo. Sin registro: pago por llamada con x402 v2, en USDC en Base o Solana. 3 llamadas gratuitas al día a través de MCP.
Este repositorio es documentación y metadatos públicos para el servicio alojado: no hay código fuente que instalar
ni ejecutar aquí. El servicio en sí es una API en vivo en https://fastapi-service-5ag4.onrender.com.
Endpoints
| Propósito | Endpoint |
|---|---|
| MCP (HTTP Streamable) | https://fastapi-service-5ag4.onrender.com/mcp |
| Verificar una salida (REST) | POST https://fastapi-service-5ag4.onrender.com/verify/schema |
| Consultar la puntuación de confianza de un agente (REST) | GET https://fastapi-service-5ag4.onrender.com/score/{agent_id} |
| Tarjeta de agente (descubrimiento) | GET https://fastapi-service-5ag4.onrender.com/.well-known/agent-card.json |
| Manifiesto de descubrimiento x402 | GET https://fastapi-service-5ag4.onrender.com/.well-known/x402 |
| llms.txt | GET https://fastapi-service-5ag4.onrender.com/llms.txt |
| Documentación interactiva de la API | GET https://fastapi-service-5ag4.onrender.com/docs |
Se exponen dos herramientas MCP en el mismo endpoint: verify_schema (POST /verify/schema) y
get_verification_record (GET /score/{agent_id}).
Precios y redes
Pago por llamada con x402 v2, en USDC, en cualquiera de las redes siguientes: sin cuenta ni registro:
| Ruta | Precio | Redes |
|---|---|---|
POST /verify/schema | $0.02 USDC | Base (eip155:8453), Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) |
GET /score/{agent_id} | $0.01 USDC | Base (eip155:8453), Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) |
/.well-known/x402 y el encabezado Payment-Required de una respuesta 402 en vivo siempre llevan los
precios exactos en vivo, las direcciones de pago y las direcciones de los activos: trátelos como la fuente de
verdad y esta tabla como referencia rápida.
Tres encabezados transportan el pago en sí, por nombre: una solicitud no pagada recibe HTTP 402 con el precio y
los requisitos de pago en el encabezado de respuesta Payment-Required; una solicitud pagada lleva su pago firmado
en el encabezado de solicitud Payment-Signature; una respuesta liquidada lleva el recibo de liquidación en el
encabezado de respuesta Payment-Response. Un resultado fail es una respuesta completa y válida a la
pregunta formulada y se cobra igual que un pass: el trabajo (ejecutar todas las comprobaciones) es
idéntico en ambos casos.
Prueba gratuita
Cada herramienta MCP tiene su propia asignación de prueba gratuita: 3 llamadas gratuitas por día por cliente, identificadas por la dirección IP de la solicitud; no hay registro ni cuenta, disponible a través de MCP. Las llamadas REST y MCP desde la misma dirección comparten una asignación por herramienta.
El cuerpo 402 de una llamada REST no pagada informa del estado real de este llamante, en vivo: available,
remaining_calls_today y resets_at (la próxima medianoche UTC). Una vez que se agotan las llamadas del día de un
cliente, available pasa a false y el cuerpo lleva "code": "free_trial_exhausted", distinto de una respuesta
ordinaria de pago requerido que nunca tuvo prueba gratuita:
{
"free_trial": {
"available": false,
"via": "mcp",
"transport": "streamable-http",
"url": "https://fastapi-service-5ag4.onrender.com/mcp",
"tool": "verify_schema",
"calls_per_client_per_day": 3,
"remaining_calls_today": 0,
"resets_at": "2026-10-02T00:00:00+00:00",
"client": "identified by request IP address",
"message": "This client's 3 free calls/day for the MCP tool 'verify_schema' are used up for today; they reset at 2026-10-02T00:00:00+00:00. This REST endpoint has no free tier of its own.",
"code": "free_trial_exhausted"
}
}
El mismo código free_trial_exhausted acompaña al resultado de pago requerido de la propia herramienta MCP
(en _meta) cuando se realiza una llamada a la herramienta después de que se agoten las llamadas
gratuitas del día de ese cliente. Después de la prueba gratuita (o una vez agotada para el día), una llamada
requiere un pago x402 transportado en el _meta de la solicitud MCP bajo x402/payment, o un
encabezado de pago x402 estándar en REST.
Verificación de un recibo, paso a paso
Cada respuesta de /verify/schema y /score/{agent_id} lleva una sección verify firmada y un bloque
attestation, por ejemplo:
"verify": {
"public_key_url": "https://fastapi-service-5ag4.onrender.com/.well-known/agent-card.json",
"key_version": "v1-2026-09c",
"canonicalization": "RFC 8785 (JCS)",
"hash_algorithm": "SHA-256",
"service": "Agent Output Verifier",
"mcp": "https://fastapi-service-5ag4.onrender.com/mcp"
},
"attestation": {
"algorithm": "Ed25519",
"key_version": "v1-2026-09c",
"timestamp": "2026-10-01T01:01:09.606993+00:00",
"signature": "8UexIObSAwQxjj8/rbEpLRgbYY6XO+wg5+b0D8I3BRfbOxl+ouwcKNPE/hp+9p37Tm2wwdmCqPjBgOMLGQtGAQ=="
}
No se necesita nada más que la propia respuesta y verify.public_key_url:
-
Obtenga la clave pública.
GETla tarjeta de agente enverify.public_key_url. Su matrizcapabilities.extensionstiene una entrada cuyouricomienza conurn:json-schema-verifier:extension:attestation:; suparams.publicKeysenumera todas las claves con las que el servicio ha firmado alguna vez, cada una{keyVersion, algorithm, publicKey}(la clave pública Ed25519 cruda de 32 bytes, codificada en base64). Elija la entrada cuyokeyVersionsea igual aresponse.attestation.key_version. La tarjeta de agente en vivo es siempre la fuente de verdad; esta es una copia de conveniencia de la clave actual, que vale la pena reconfirmar contra la tarjeta de agente en vivo primero:{ "keyVersion": "v1-2026-09c", "algorithm": "Ed25519", "publicKey": "d2IHH0/Xduci/5J8IewYmauUvgqf+gFIeCEXDwjHUhw=", "publicKeyEncoding": "base64 of the raw 32-byte Ed25519 public key" } -
Reconstruya el documento firmado. Es un objeto JSON con exactamente estas cinco claves:
{ "context": "json-schema-verifier/verify-schema-attestation/v1", "algorithm": "Ed25519", "key_version": "<attestation.key_version>", "attested_at": "<attestation.timestamp>", "response": { "...": "the full response, with the attestation field removed" } }contextesjson-schema-verifier/verify-schema-attestation/v1para respuestas/verify/schema, ojson-schema-verifier/trust-score-attestation/v1para respuestas/score/{agent_id}. -
Canonicalícelo con RFC 8785 (JCS): bytes UTF-8 del documento JSON anterior, claves de objeto ordenadas recursivamente, sin espacios en blanco insignificantes, números impresos como los imprime ECMAScript (
1.0se convierte en1). -
Verifique la firma Ed25519 (
response.attestation.signature, decodificada en base64) sobre esos bytes canónicos, usando la clave pública del paso 1. -
Compruebe los cuatro hash del recibo, cada uno SHA-256 sobre el JSON canónico RFC 8785 (JCS) del valor nombrado:
output_hash(desubmitted_output),schema_hash(deexpected_schema),rules_hash(de{"bounds": ..., "rules": ...}) yrequest_hash(de toda la solicitud tal como se analizó, solo detalle completo). Recálculelos usted mismo y compárelos: esto es lo que vincula el recibo a los datos exactos que se comprobaron.request_hashrellena cada campo por regla y por límite con su propio valor predeterminado antes de aplicar el hash: untoleranceomitido se procesa como1e-9, unif_presentomitido comofalse, unequals_field/equals/other_field/value/in_field/valuesomitido comonull—, de modo que dos solicitudes cuyas reglas difieren solo en qué campos opcionales se escribieron explícitamente aún tengan el mismo hash aquí.rules_hashes lo contrario: aplica hash exactamente y solo a los campos que usted proporcionó, sin valores predeterminados.
Un verificador mínimo en Python, que usa solo la biblioteca estándar más cryptography:
import base64, json
from decimal import Decimal
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
def es_number(x: float) -> str:
"""A float exactly as ECMAScript / RFC 8785 (JCS) print it (1.0 -> "1", 1e-7 -> "1e-7")."""
if x == 0:
return "0"
sign = "-" if x < 0 else ""
digits_tuple = Decimal(repr(abs(x))).as_tuple()
digits = "".join(map(str, digits_tuple.digits)).rstrip("0") or "0"
n = len(digits_tuple.digits) + digits_tuple.exponent # position of the decimal point
k = len(digits)
if k <= n <= 21:
body = digits + "0" * (n - k)
elif 0 < n <= 21:
body = digits[:n] + "." + digits[n:]
elif -6 < n <= 0:
body = "0." + "0" * (-n) + digits
else:
e = n - 1
body = digits[0] + ("." + digits[1:] if k > 1 else "") + f"e{'+' if e >= 0 else '-'}{abs(e)}"
return sign + body
def canonical(v) -> str:
if isinstance(v, bool):
return "true" if v else "false"
if isinstance(v, float):
return es_number(v)
if isinstance(v, dict):
return "{" + ",".join(f"{canonical(k)}:{canonical(v[k])}" for k in sorted(v)) + "}"
if isinstance(v, list):
return "[" + ",".join(canonical(x) for x in v) + "]"
return json.dumps(v, ensure_ascii=False) # covers None, int, str
def verify(response: dict, public_key_b64: str, context: str) -> bool:
att = response["attestation"]
body = {k: v for k, v in response.items() if k != "attestation"}
message = canonical({
"context": context,
"algorithm": att["algorithm"],
"key_version": att["key_version"],
"attested_at": att["timestamp"],
"response": body,
}).encode("utf-8")
key = Ed25519PublicKey.from_public_bytes(base64.b64decode(public_key_b64))
try:
key.verify(base64.b64decode(att["signature"]), message)
return True
except Exception:
return False
Probado contra ambos recibos del ejemplo práctico a continuación: ambos verifican True.
Ejemplo práctico: verificación de facturas
Ambas llamadas siguientes son llamadas reales, en vivo y pagadas contra el servicio de producción: pagos
x402 reales en Base, liquidados en cadena, con los recibos firmados resultantes mostrados exactamente como se
recibieron. Ambos son verificables de forma independiente: obtenga la tarjeta de agente anterior, confirme que
key_version: v1-2026-09c está listado y verifique cada attestation.signature con los pasos anteriores.
1. Factura borrador: falla en una regla entre campos (detail: "full")
Solicitud:
{
"task_id": "invoice-7731-draft",
"agent_id": "test-seller-invoice-agent",
"expected_schema": {
"type": "object",
"required": ["invoice_id", "currency", "line_items", "total"],
"properties": {
"invoice_id": { "type": "string", "pattern": "^INV-[0-9]{4}$" },
"currency": { "enum": ["USD", "EUR"] },
"line_items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["sku", "qty", "line_total"],
"properties": {
"sku": { "type": "string" },
"qty": { "type": "integer", "minimum": 1 },
"line_total": { "type": "number", "minimum": 0 }
}
}
},
"total": { "type": "number" }
}
},
"submitted_output": {
"invoice_id": "INV-7731",
"currency": "USD",
"line_items": [
{ "sku": "CRWL-100", "qty": 3, "line_total": 87.0 },
{ "sku": "CRWL-200", "qty": 1, "line_total": 42.5 }
],
"total": 135.0
},
"rules": [
{ "type": "sum_equals", "field": "line_items[].line_total", "equals_field": "total" }
],
"enforce_rules": true,
"detail": "full"
}
Las líneas suman 129.5, pero total dice 135.0. Con enforce_rules: true, esa violación
de regla hace fallar el resultado y viene con una sugerencia de corrección:
{
"summary": {
"result": "fail",
"blocking_checks": ["consistency:sum_equals"]
},
"next_actions": [
{ "action": "repair_and_reverify", "using": "hints" }
],
"result": "fail",
"verification_id": "28afb453-7c39-4993-a9c4-fcade1b7924f",
"task_id": "invoice-7731-draft",
"agent_id": "test-seller-invoice-agent",
"output_hash": "d4fb804e434eb3ee047068cbb3691ea1e07066928e7e3efc73b94317e53ee305",
"schema_hash": "23ea3213715cfaf2011dabe2a9a69d4ac25b6eceec7ce3d4bfef9a1298b69b2a",
"rules_hash": "2acb6de92b88cfbca279ea6d5bd74b7a1e7dec0839dd093dbe041e25df3364d2",
"request_hash": "e4bf9733726b24a19ec546ecc79015c9b1cb7a6829b409b41ef56b1c8f60b881",
"verified_at": "2026-10-01T01:01:09.606993+00:00",
"verifier_version": "0.4.1",
"enforce_rules": true,
"strict_content_check": false,
"errors": [
"enforce_rules: consistency:sum_equals at 'line_items[].line_total': values sum to 129.5, expected total (135.0)"
],
"errors_total": 1,
"errors_omitted": 0,
"errors_detail": [
{
"check": "consistency:sum_equals",
"path": "$.line_items[].line_total",
"expected": "a sum equal to total (135.0)",
"found": "sum 129.5",
"message": "enforce_rules: consistency:sum_equals at 'line_items[].line_total': values sum to 129.5, expected total (135.0)"
}
],
"errors_detail_total": 1,
"errors_detail_omitted": 0,
"flags": [
{
"check": "consistency:sum_equals",
"field": "line_items[].line_total",
"severity": "error",
"detail": "values sum to 129.5, expected total (135.0)"
}
],
"flags_total": 1,
"flags_omitted": 0,
"hints": [
{
"source": "integrity",
"check": "consistency:sum_equals",
"path": "$.line_items[].line_total",
"expected": "a sum equal to total (135.0)",
"found": "sum 129.5"
}
],
"hints_total": 1,
"hints_omitted": 0,
"schema_compliance": { "ratio": 1.0, "passed": 22, "total": 22 },
"integrity_checks": { "ratio": 0.875, "passed": 7, "total": 8 },
"overall": { "ratio": 0.966667, "passed": 29, "total": 30 },
"verify": {
"public_key_url": "https://fastapi-service-5ag4.onrender.com/.well-known/agent-card.json",
"key_version": "v1-2026-09c",
"canonicalization": "RFC 8785 (JCS)",
"hash_algorithm": "SHA-256",
"service": "Agent Output Verifier",
"mcp": "https://fastapi-service-5ag4.onrender.com/mcp"
},
"attestation": {
"algorithm": "Ed25519",
"key_version": "v1-2026-09c",
"timestamp": "2026-10-01T01:01:09.606993+00:00",
"signature": "8UexIObSAwQxjj8/rbEpLRgbYY6XO+wg5+b0D8I3BRfbOxl+ouwcKNPE/hp+9p37Tm2wwdmCqPjBgOMLGQtGAQ=="
}
}
Evidencia de pago: $0.02 USDC en Base, liquidado en cadena:
0x4cb755c71413ed5419215d2d7445c34e19be79d9f15b4046802656165b774897.
2. Factura corregida: pasa (detail: "compact")
Mismo esquema y regla, total corregido para coincidir con las líneas (129.5), solicitado con
"detail": "compact" para obtener solo el resumen, los campos del recibo y la firma:
{
"task_id": "invoice-7731-final",
"agent_id": "test-seller-invoice-agent",
"expected_schema": { "...": "same schema as above" },
"submitted_output": {
"invoice_id": "INV-7731",
"currency": "USD",
"line_items": [
{ "sku": "CRWL-100", "qty": 3, "line_total": 87.0 },
{ "sku": "CRWL-200", "qty": 1, "line_total": 42.5 }
],
"total": 129.5
},
"rules": [
{ "type": "sum_equals", "field": "line_items[].line_total", "equals_field": "total" }
],
"enforce_rules": true,
"detail": "compact"
}
{
"summary": {
"result": "pass",
"blocking_checks": []
},
"next_actions": [
{ "action": "attach_receipt", "for": "seller" },
{ "action": "proceed_to_payment", "for": "buyer" }
],
"result": "pass",
"verification_id": "96b4f722-04c3-47c7-8708-5bba97fd18b5",
"task_id": "invoice-7731-final",
"agent_id": "test-seller-invoice-agent",
"output_hash": "39e3d0a1431e3ce9cda89a1d2873e1ffb4e34f4eeded2ffa87946fbd941a34c3",
"schema_hash": "23ea3213715cfaf2011dabe2a9a69d4ac25b6eceec7ce3d4bfef9a1298b69b2a",
"rules_hash": "2acb6de92b88cfbca279ea6d5bd74b7a1e7dec0839dd093dbe041e25df3364d2",
"verified_at": "2026-10-01T01:01:15.158857+00:00",
"verifier_version": "0.4.1",
"enforce_rules": true,
"strict_content_check": false,
"verify": {
"public_key_url": "https://fastapi-service-5ag4.onrender.com/.well-known/agent-card.json",
"key_version": "v1-2026-09c",
"canonicalization": "RFC 8785 (JCS)",
"hash_algorithm": "SHA-256",
"service": "Agent Output Verifier",
"mcp": "https://fastapi-service-5ag4.onrender.com/mcp"
},
"attestation": {
"algorithm": "Ed25519",
"key_version": "v1-2026-09c",
"timestamp": "2026-10-01T01:01:15.158857+00:00",
"signature": "ri1AEl12DoZMTKBX8V5hfuD9jOWd+BLXIciqiX1JoSHJy8iDJKKSdsJmjpQUHTkbVMxDGpNwMNmc6X9zHaSVDw=="
}
}
La forma compacta conserva el resumen, los campos del recibo, verify y attestation; request_hash,
errors, errors_detail, flags, hints y las tres puntuaciones permanecen en la forma
completa (consulte detail anterior).
Evidencia de pago: $0.02 USDC en Base, liquidado en cadena:
0xaa9161736ac410b6ac9ccc478780aa2feaa6d2cf02af4c51855e099c14499079.
Verificación de estos dos recibos por su cuenta
Ambas respuestas anteriores se comprobaron contra la clave pública de la tarjeta de agente en vivo para v1-2026-09c
antes de incluirlas aquí, usando los pasos de Verificación de un recibo.
Confírmelo usted mismo de la misma manera: obtenga
https://fastapi-service-5ag4.onrender.com/.well-known/agent-card.json, confirme que v1-2026-09c está
listado y vuelva a ejecutar los mismos cinco pasos contra los dos bloques JSON anteriores: las firmas se
calcularon una vez, sobre exactamente estos datos, y se verificarán de manera idéntica para cualquiera.
agent_id identifica al agente que produjo la salida que se está comprobando, por ejemplo, el vendedor;
es una etiqueta no autenticada que proporciona el llamante. agent_id: "test-seller-invoice-agent" usa el
prefijo test- que el servicio reserva para ejemplos: la verificación se ejecutó de verdad y su recibo es
genuino, manteniéndose separado de la puntuación de confianza de ese agente.
Licencia
La documentación y los ejemplos de este repositorio están bajo la Licencia MIT. El servicio alojado es propietario; este repositorio contiene solo documentación y metadatos públicos.