Documentación / API / Servidor MCP

Servidor MCP

MCPhttps://api.cfdi.express/mcpStreamable HTTPOAuth 2.1 o API key

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

URLModoPara qué
https://api.cfdi.express/mcpProducciónTimbra CFDIs reales con validez fiscal y consume saldo de tu cuenta.
https://api.cfdi.express/mcp/testPruebasTimbra 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_… o sk_live_…. Aquí la llave decide el modo: una sk_test_ contra /mcp sigue 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: /mcp es producción y /mcp/test es 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

Terminal
claude mcp add --transport http cfdi https://api.cfdi.express/mcp \
  --header "Authorization: Bearer sk_test_..."

Cursor y Windsurf

mcp.json
{
  "mcpServers": {
    "cfdi": {
      "url": "https://api.cfdi.express/mcp",
      "headers": { "Authorization": "Bearer sk_test_..." }
    }
  }
}

Agentes propios con el SDK de MCP

TypeScript
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)

HerramientaQué hace
create_invoiceTimbra 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_noteTimbra una nota de crédito (CFDI de egreso) por una devolución, reembolso o descuento. Se relaciona con relatedInvoiceId o relatedUuid.
get_invoiceEstatus, 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_invoicesLista paginada con filtros por tipo, estatus, emisor, fechas y UUID (kind=credit_note para notas de crédito).
cancel_invoiceCancela ante el SAT con motivo 01–04 (el 01 exige folioSustitucion). Consume un timbre.
create_paymentTimbra un complemento de pago REP 2.0 contra una factura PPD timbrada.
get_paymentConsulta un complemento de pago con sus saldos y archivos.
list_paymentsLista los complementos de pago con filtros y cursor.
cancel_paymentCancela un REP y restaura el saldo pendiente de la factura.
list_merchantsLos emisores de la cuenta. El agente necesita un merchantId para poder facturar.
search_product_codesBúsqueda por palabra clave sobre c_ClaveProdServ, incluidos los sinónimos del SAT.
search_unit_codesBúsqueda por palabra clave sobre c_ClaveUnidad.
get_catalogCatálogos completos de usos de CFDI, regímenes fiscales y formas de pago.
get_balanceSaldo 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 consultar get_invoice cuando 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

Prompt
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_balance o GET /v1/balance: sin timbres, las herramientas que emiten fallan con insufficient_credits.