#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
/mcpA 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.
https://api.clarisfy.com/mcpLos 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:
Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYeo 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.
| Parte | Estado |
|---|---|
initialize, tools/list, tools/call, ping | Implementado |
Notificaciones del handshake (notifications/initialized) | Aceptadas con 202 |
| Respuesta JSON por petición | Sí |
| Stream SSE, sesiones, mensajes iniciados por el servidor | No |
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
| Herramienta | Qué responde |
|---|---|
list_fiscal_entities | Los RFCs conectados de tu organización. Empieza aquí: las demás necesitan un fiscal_entity_id de esta lista. |
get_fiscal_entity | Detalle de un RFC: razón social, régimen, estado de la conexión, última sincronización. |
get_cfdi_monthly_summary | Totales de facturación emitida y recibida por mes, ya agregados. |
list_invoices | CFDIs de un RFC en un rango de fechas (obligatorio, máximo 24 meses), paginado por cursor. |
get_invoice | Detalle de un CFDI por UUID. |
check_sat_blacklists | Busca un RFC exacto en 69-B/EFOS, Artículo 69 y CSD sin efectos. Requiere plan Enterprise. |
get_financial_health_score | Score 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 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":{}}'{
"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 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:
{
"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ódigo | Cuándo |
|---|---|
-32700 | El cuerpo no era JSON. |
-32600 | No era una petición JSON-RPC válida. |
-32601 | Método no soportado (por ejemplo resources/list). |
-32602 | Herramienta 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:
{
"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
NUMERICen 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í.