#Servidor MCP

Clarisfy expone un servidor MCP (Model Context Protocol) para que un asistente de IA consulte los datos fiscales que ya descargamos de tu organización: tus RFCs, tus CFDIs, tus totales por mes, listas negras del SAT.

Es sólo lectura. No hay ninguna herramienta que conecte un RFC, dispare una descarga, desvincule algo ni toque credenciales. Eso no es una promesa de configuración: el servidor sólo sabe hacer peticiones GET a una lista fija de endpoints, así que no existe el camino para escribir.

#Endpoint

POST/mcp

A diferencia del resto de la API, no va bajo /v1: el protocolo lleva su propia versión, así que la URL es la raíz del dominio.

cURL
https://api.clarisfy.com/mcp

Los datos de conexión también están en la plataforma, en Organización → Desarrollo → Servidor MCP: la URL, el formato del header, un bloque de configuración listo para pegar y la lista de herramientas vigente.

Autentica igual que el resto de la API — ver Autenticación:

cURL
Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe

o Authorization: Basic base64(api_key:api_secret).

Sin credenciales responde 401. Si revocas la key, la conexión MCP muere con ella.

#Qué implementa del transporte

Es un servidor sin estado: cada petición trae sus credenciales y devuelve una sola respuesta JSON.

ParteEstado
initialize, tools/list, tools/call, pingImplementado
Notificaciones del handshake (notifications/initialized)Aceptadas con 202
Respuesta JSON por petición
Stream SSE, sesiones, mensajes iniciados por el servidorNo

No hay stream porque no hay nada que empujar: las herramientas responden y terminan. Un cliente que exija un canal SSE no va a funcionar.

#Herramientas

HerramientaQué responde
list_fiscal_entitiesLos RFCs conectados de tu organización. Empieza aquí: las demás necesitan un fiscal_entity_id de esta lista.
get_fiscal_entityDetalle de un RFC: razón social, régimen, estado de la conexión, última sincronización.
get_cfdi_monthly_summaryTotales de facturación emitida y recibida por mes, ya agregados.
list_invoicesCFDIs de un RFC en un rango de fechas (obligatorio, máximo 24 meses), paginado por cursor.
get_invoiceDetalle de un CFDI por UUID.
check_sat_blacklistsBusca un RFC exacto en 69-B/EFOS, Artículo 69 y CSD sin efectos. Requiere plan Enterprise.
get_financial_health_scoreScore interno de salud financiera del RFC (0-1000) y sus componentes.

Cada herramienta reenvía a su endpoint HTTP, con tus mismas credenciales. Eso significa que hereda todo lo demás sin excepciones nuevas: el filtro por organización, tu ventana de visibilidad, el gating por plan y las suspensiones por falta de pago.

#Ejemplo

Handshake y descubrimiento:

cURL
curl https://api.clarisfy.com/mcp \
  -H "Authorization: Bearer $CLARISFY_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "tools": { "listChanged": false } },
    "serverInfo": { "name": "clarisfy", "version": "2025-06-18" }
  }
}

Llamar una herramienta:

cURL
curl https://api.clarisfy.com/mcp \
  -H "Authorization: Bearer $CLARISFY_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "get_cfdi_monthly_summary",
      "arguments": { "fiscal_entity_id": "fe_9a1c2b3d4e5f6071", "months": 12 }
    }
  }'

La respuesta trae el JSON del endpoint dentro de un bloque de texto:

JSON
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "{\"months\":[{\"period\":\"2026-08\",\"emitted_total\":\"128400.00\"}]}" }],
    "isError": false
  }
}

#Errores

Hay dos niveles y la diferencia importa para un modelo.

Error de protocolo — JSON-RPC estándar, en error. La llamada no se hizo:

CódigoCuándo
-32700El cuerpo no era JSON.
-32600No era una petición JSON-RPC válida.
-32601Método no soportado (por ejemplo resources/list).
-32602Herramienta desconocida, falta un argumento requerido, o se mandó un argumento que no existe.

Un argumento no reconocido se rechaza, no se ignora: descartarlo en silencio respondería una pregunta distinta de la que el modelo hizo.

Fallo de la herramienta — la llamada sí ocurrió y el endpoint contestó un 4xx. Regresa como resultado con isError: true y el motivo adentro, no como error de JSON-RPC:

JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "{\"status\": 402, \"error\": {\"detail\": \"Tu organización tiene una factura vencida…\"}}" }],
    "isError": true
  }
}

Se separan así a propósito: un 402 por factura vencida no se arregla reintentando, y un modelo que lo lea como error de transporte lo reintentaría.

#Lo que el modelo debe saber

Dos advertencias que conviene repetir en tus prompts, porque el servidor las declara pero un modelo puede ignorarlas:

  • Los montos llegan como cadenas. Son NUMERIC en la base; convertirlos a flotante para sumar introduce error en dinero.
  • El score de salud financiera no es un buró. Es una lectura de los datos fiscales del propio cliente para uso interno: no es probabilidad de incumplimiento ni asesoría fiscal o de crédito, y no debe presentarse así.