Servidor MCP
CFDI Express expone un servidor MCP (Model Context Protocol) para que cualquier agente de IA pueda timbrar facturas, registrar pagos, emitir notas de crédito y cancelar CFDIs en tu cuenta, con las mismas reglas y validaciones que la API REST.
Los dos endpoints
| URL | Modo | Para qué |
|---|---|---|
| https://api.cfdi.express/mcp | Producción | Timbra CFDIs reales con validez fiscal y consume saldo de tu cuenta. |
| https://api.cfdi.express/mcp/test | Pruebas | Timbra contra el sandbox del SAT. Gratis, ilimitado y sin tocar tu saldo de producción. |
Ambos son Streamable HTTP y sin estado, así que funcionan con cualquier cliente MCP moderno.
Autenticación
Hay dos caminos, según lo que soporte tu cliente:
- API key (clientes que permiten headers, como Claude Code, Cursor, Windsurf o un agente propio):
Authorization: Bearer sk_test_…osk_live_…. Aquí la llave decide el modo: unask_test_contra/mcpsigue timbrando en el sandbox. - OAuth 2.1 (claude.ai, Claude Desktop, conectores de ChatGPT): pegas la URL y firmas con tu cuenta del dashboard cuando el cliente te lo pida, sin manejar llaves. Aquí la ruta decide el modo:
/mcpes producción y/mcp/testes pruebas.
En ambos casos el alcance es el mismo que el de la API REST sobre esa cuenta y ese modo. Usa el modo de pruebas mientras experimentas.
Conectar tu cliente
claude.ai y Claude Desktop (OAuth)
Configuración → Conectores → Agregar conector personalizado y pega https://api.cfdi.express/mcp (o https://api.cfdi.express/mcp/test para experimentar gratis). Claude abre el inicio de sesión de CFDI Express; entras con tu cuenta del dashboard y el conector queda listo.
ChatGPT (OAuth, modo desarrollador)
Requiere un plan Plus, Pro, Business o Enterprise en la app web: Settings → Apps & Connectors → activa Developer mode y agrega el servidor MCP con la misma URL. Inicia sesión cuando te lo pida.
Claude Code
claude mcp add --transport http cfdi https://api.cfdi.express/mcp \
--header "Authorization: Bearer sk_test_..."Cursor y Windsurf
{
"mcpServers": {
"cfdi": {
"url": "https://api.cfdi.express/mcp",
"headers": { "Authorization": "Bearer sk_test_..." }
}
}
}Agentes propios con el SDK de MCP
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "mi-agente", version: "1.0.0" });
await client.connect(
new StreamableHTTPClientTransport(new URL("https://api.cfdi.express/mcp"), {
requestInit: {
headers: { authorization: `Bearer ${process.env.CFDI_API_KEY}` },
},
}),
);
const { tools } = await client.listTools();Herramientas (14)
| Herramienta | Qué hace |
|---|---|
| create_invoice | Timbra una factura CFDI 4.0 de ingreso (PUE, PPD o global). Espera hasta ~20 s por el UUID del SAT; si regresa status "stamping", el agente consulta get_invoice. |
| create_credit_note | Timbra una nota de crédito (CFDI de egreso) por una devolución, reembolso o descuento. Se relaciona con relatedInvoiceId o relatedUuid. |
| get_invoice | Estatus, UUID, datos de cancelación y ligas firmadas de XML, PDF y ZIP (~15 min de vigencia). También sirve para notas de crédito. |
| list_invoices | Lista paginada con filtros por tipo, estatus, emisor, fechas y UUID (kind=credit_note para notas de crédito). |
| cancel_invoice | Cancela ante el SAT con motivo 01–04 (el 01 exige folioSustitucion). Consume un timbre. |
| create_payment | Timbra un complemento de pago REP 2.0 contra una factura PPD timbrada. |
| get_payment | Consulta un complemento de pago con sus saldos y archivos. |
| list_payments | Lista los complementos de pago con filtros y cursor. |
| cancel_payment | Cancela un REP y restaura el saldo pendiente de la factura. |
| list_merchants | Los emisores de la cuenta. El agente necesita un merchantId para poder facturar. |
| search_product_codes | Búsqueda por palabra clave sobre c_ClaveProdServ, incluidos los sinónimos del SAT. |
| search_unit_codes | Búsqueda por palabra clave sobre c_ClaveUnidad. |
| get_catalog | Catálogos completos de usos de CFDI, regímenes fiscales y formas de pago. |
| get_balance | Saldo prepagado y timbres restantes del modo en el que está conectado. |
Las herramientas que timbran o cancelan aceptan un argumento opcional idempotency_key. Pásale un valor estable (el id de tu pedido) y los reintentos devuelven el documento original sin gastar otro timbre; si lo omites, se genera una llave nueva en cada llamada.
Cómo se comporta con el agente
- Sabe el flujo. El servidor envía instrucciones al conectarse: resolver el emisor con
list_merchants—y preguntarte cuál usar si hay varios—, buscar claves del SAT antes de timbrar, y consultarget_invoicecuando el timbrado quedó en proceso. - Errores accionables. Cada falla regresa el código estable de la API (
validation_error,insufficient_credits,sat_rejected…) con punteros por campo, así que el agente corrige y reintenta solo. - Sin administración de CSDs. El agente puede timbrar, cancelar y consultar, pero los certificados sólo se suben y validan desde el dashboard o por la API REST.
- Rate limit compartido. Cada llamada a una herramienta consume 2 tokens del presupuesto por minuto de la cuenta (la petición del transporte más la llamada interna a la API). Las conexiones por OAuth comparten el bucket del usuario que firmó.
- Tokens OAuth. Expiran en 1 hora y se renuevan solos hasta por 30 días. Para revocarlos, quita el conector; volver a conectarte genera permisos nuevos.
Ejemplo de uso
Factura el pedido #1001 a XENON INDUSTRIAL ARTICLES
(RFC XIA190128J61, CP 01160, régimen 601): 2 teclados mecánicos
de $1,740 c/u, pago por transferencia, uso G03. Mándame el PDF.Con eso el agente resuelve el emisor con list_merchants, busca la clave del producto con search_product_codes, timbra con create_invoice y te devuelve la liga del PDF que trae get_invoice. Si algo falta —por ejemplo, el régimen del receptor— te lo pregunta en vez de inventarlo.
Antes de pasar a producción
- Prueba todo el flujo en
https://api.cfdi.express/mcp/test: los CFDIs del sandbox son idénticos a los reales salvo por su validez fiscal. - Revisa que el emisor correcto tenga su CSD vigente con GET /v1/merchants/{id}/csd. Un agente no puede arreglar un certificado vencido.
- Vigila el saldo con
get_balanceo GET /v1/balance: sin timbres, las herramientas que emiten fallan coninsufficient_credits.
