Faxtal

Servidor MCP

Faxtal expone un servidor MCP (Model Context Protocol) para que un asistente de IA consulte y opere la facturación de una empresa en lenguaje natural: ChatGPT y Claude como conectores personalizados (OAuth), Claude Code, Cursor, un agente propio o cualquier cliente MCP. El modelo lo pones tú; Faxtal no interviene en él.

Conexión

URLhttps://app.faxtal.com/mcp
TransporteStreamable HTTP, sin estado
  • Cada petición es autocontenida. La respuesta llega como JSON o como un stream SSE corto.
  • Usa la URL tal cual, sin barra final.
  • Si tu cliente envía la cabecera Origin (clientes de navegador), tiene que ser un origen autorizado. Los clientes de escritorio y de terminal no la envían.

Autenticación

API key

Envía la API key de la empresa en una de estas cabeceras:

  • Authorization: Bearer fctXXXXXXXX_YYYYYYYYYYYYYYYY
  • X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY

La clave se valida igual que en la API: revocación, caducidad, lista de IPs permitidas, plan con acceso a la API y límite de peticiones (ver Autenticación). Además, el plan debe incluir el Servidor MCP (planes Pro y Business). Puedes crearla en la aplicación, en Configuración → Servidor MCP, o en Configuración → API Keys.

Claude Code

claude mcp add --transport http faxtal https://app.faxtal.com/mcp \
  --header "Authorization: Bearer fctXXXXXXXX_YYYYYYYYYYYYYYYY"

Clientes con configuración mcpServers (p. ej. Cursor)

{
  "mcpServers": {
    "faxtal": {
      "url": "https://app.faxtal.com/mcp",
      "headers": { "Authorization": "Bearer fctXXXXXXXX_YYYYYYYYYYYYYYYY" }
    }
  }
}

Agente propio (SDK mcp de Python)

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client(
    "https://app.faxtal.com/mcp",
    headers={"Authorization": "Bearer fctXXXXXXXX_YYYYYYYYYYYYYYYY"},
) as (read, write, _):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await session.list_tools()
        result = await session.call_tool("search_invoices", {"kind": "issued", "limit": 10})

OAuth 2.1

Para clientes que no admiten una cabecera fija y conectan con OAuth, como los conectores personalizados de ChatGPT y Claude. El cliente descubre el servidor de autorización desde la URL del MCP:

MetadatosURL
Recurso protegidohttps://app.faxtal.com/.well-known/oauth-protected-resource/mcp
Servidor de autorizaciónhttps://app.faxtal.com/.well-known/oauth-authorization-server
  • Flujo authorization code con PKCE S256. Clientes públicos, sin secreto.
  • Registro dinámico de clientes en /oauth/register. Autorización en /oauth/authorize, tokens en /oauth/token y revocación en /oauth/revoke.
  • En la pantalla de consentimiento de Faxtal eliges las empresas y los permisos que concedes. Solo puedes conceder lo que tu rol permite en cada empresa. Si tu rol cambia, los permisos se recortan en el siguiente uso.
  • El token de acceso dura 30 minutos. El refresh token cambia en cada renovación.
  • Sin token válido, /mcp responde 401 con la cabecera WWW-Authenticate, que apunta a los metadatos del recurso.
  • Revoca el acceso en Configuración → Servidor MCP → Clientes autorizados.

La empresa

La empresa sale de la credencial, nunca de lo que pida el asistente. Las tools aceptan un company_id opcional para elegir entre las empresas autorizadas:

  • una API key autoriza una sola empresa;
  • una autorización OAuth puede cubrir varias; sin company_id se usa la primera.

list_companies devuelve las empresas autorizadas. Un company_id fuera de la credencial da company_not_allowed.

Scopes

Cada tool exige un scope de la credencial. Una API key sin lista de scopes tiene acceso completo. Con lista, dominio:* concede todo el dominio y * concede todo. Una lista vacía no da acceso a nada.

ScopePermite
invoices:readBuscar y consultar facturas, documentos, terceros y productos; validar canónicos
invoices:writeCrear borradores; enviar facturas por email
invoices:issueEmitir, importar, rectificar y anular
received:writeReconocer, registrar y borrar facturas recibidas
parties:writeAlta y actualización de terceros
payments:readConsultar los cobros de emitidas y los pagos de recibidas
payments:writeRegistrar, revertir y compensar cobros y pagos
compliance:readEstado VeriFactu, TicketBAI y SII; incidencias y plazos
recurring:readConsultar plantillas recurrentes y su calendario
recurring:writeCrear plantillas recurrentes, pausarlas y saltar fechas

Combinaciones habituales:

CasoScopes
Emitir y consultarinvoices:read invoices:write invoices:issue compliance:read
Solo lecturainvoices:read compliance:read

Tools

El listado de tools (tools/list) solo muestra las que la credencial puede usar: las de sus scopes. Las de facturas recurrentes solo se listan si el plan incluye la función (recurring_invoices). Cada llamada (tools/call) lo vuelve a comprobar y responde scope_missing o feature_not_enabled si no se cumple.

Las marcadas con Sí piden confirmación.

ToolScopeConfirmaciónQué hace
get_company–Datos fiscales, plan, funcionalidades, sistemas fiscales y series de emisión
list_companies–Empresas autorizadas en la credencial
search_invoicesinvoices:readEmitidas, recibidas o borradores, con filtros y paginación
get_invoiceinvoices:readResumen y estado fiscal; con include, eventos, documentos o canónico
validate_invoiceinvoices:readValida un canónico json_1_1 sin guardarlo
create_draftinvoices:writeCrea un borrador
issue_invoiceinvoices:issueSíEmite un borrador o un canónico, con el siguiente número de la serie o con el del usuario; devuelve número, QR y leyenda
import_invoicesinvoices:issueSí, con dry_run=falseImporta facturas numeradas por el origen; por defecto solo simula
create_correctiveinvoices:issueSí, con issue=trueBorrador rectificativo (sustitución o diferencias) desde la original
cancel_invoiceinvoices:issueSíAnula una factura emitida
send_invoiceinvoices:writeSíEnvía la factura por email
get_invoice_documentinvoices:readURI del documento: PDF, Facturae, UBL o CII
recognize_documentreceived:writePropone un canónico a partir de un PDF o imagen; no registra
ingest_received_invoicereceived:writeRegistra una factura recibida, con control de duplicados
delete_received_invoicereceived:writeSíBorra una recibida no declarada
find_third_partyinvoices:readBusca clientes y proveedores
upsert_third_partyparties:writeAlta o actualización por NIF y país
find_productinvoices:readBusca productos
list_invoice_paymentspayments:readCobros (emitida) o pagos (recibida) de una factura, con reversiones
register_invoice_paymentpayments:writeSíRegistra un cobro o pago con fecha, importe y medio; con external_reference no se duplica
reverse_invoice_paymentpayments:writeSíRevierte un cobro o pago con el movimiento inverso, sin borrarlo
compensate_invoice_paymentspayments:writeSíCompensa una factura con otra de signo contrario (abono) del mismo tercero: un movimiento con medio 14 en cada una; con external_reference no se duplica
compliance_statuscompliance:readEstado por sistema fiscal y certificados
list_incidentscompliance:readRechazos de la administración con código y motivo
sii_deadlinescompliance:readPlazos SII próximos
list_recurring_templatesrecurring:readPlantillas de facturas recurrentes
preview_recurring_templaterecurring:readCalendario de una plantilla, sin guardar
create_recurring_templaterecurring:writeSíCrea una plantilla recurrente; con issue exige además invoices:issue
pause_recurring_templaterecurring:writePausa una plantilla
skip_recurring_occurrencerecurring:writeSalta una fecha del calendario

Los ficheros se pasan en base64 (files: [{"name", "content_base64"}]).

issue_invoice emite con el siguiente número de la serie. Para emitir con el número del usuario o de su programa, envíalo en el argumento invoice_number junto a invoice_id, o en header.invoice_number dentro de canonical. Va completo, con la serie, y el preview de la confirmación lo muestra. Tiene que encajar con la plantilla de la serie (forced_number_invalid) y no puede estar ya usado (forced_number_in_use). Faxtal no comprueba que la numeración sea correlativa: tu agente solo debe enviar un número que aporte el usuario o su sistema, nunca inventarlo ni calcular el siguiente.

Resources

URIContenidoScope
faxtal://healthEstado del servidor–
faxtal://schema/canonical-1.1JSON Schema del formato canónico–
faxtal://docs/rulesReglas para construir facturas–
faxtal://catalog/tax-ratesTipos impositivos–
faxtal://catalog/exemption-reasonsCausas de exención y no sujeción–
faxtal://catalog/tax-regimesClaves de régimen–
faxtal://catalog/invoice-typesTipos de factura–
faxtal://catalog/payment-methodsFormas de pago–
faxtal://catalog/correction-reasonsMotivos de rectificación–
faxtal://catalog/countriesPaíses–
faxtal://catalog/es-subdivisionsProvincias y comunidades–
faxtal://company/{company_id}/seriesSeries de la empresainvoices:read
faxtal://invoice/{invoice_id}/{formato}Documento: pdf, facturae, ubl o ciiinvoices:read

Prompts

PromptArgumentosQué guía
issue_invoicecustomer, description, amount (opcional)Preparar, validar y emitir una factura con confirmación
ingest_receivedfilename (opcional)Reconocer un documento de proveedor y registrarlo tras revisarlo
fiscal_health–Informe priorizado de cumplimiento de la empresa
portfolio_health–Recorrer las empresas autorizadas y resumir incidencias

Confirmación de acciones sensibles

Emitir, importar sin simulación, rectificar emitiendo, anular, enviar por email, borrar recibidas y registrar o revertir cobros y pagos piden confirmación. La decide el servidor, no el cliente:

  1. Si el cliente admite elicitation, Faxtal pide la confirmación al usuario con un resumen. Si no la acepta, la tool responde cancelled.
  2. Si no, la primera llamada no ejecuta nada y devuelve:
{
  "status": "confirmation_required",
  "tool": "cancel_invoice",
  "preview": { "series": "A", "number": "A-2026-0042", "total": 121.0 },
  "confirm_token": "eyJ0Ijoi...",
  "expires_at": "2026-09-15T10:05:00+00:00",
  "next_step": "Muestra el preview al usuario y, solo si confirma expresamente, vuelve a llamar..."
}

Enseña el preview al usuario. Solo si confirma, repite la llamada con los mismos argumentos y confirm_token.

  • El token caduca en expires_at (5 minutos), vale una sola vez y queda ligado a la credencial, a la tool y a los argumentos exactos.
  • Las comprobaciones de estado van antes de pedir confirmación: si la acción no es posible (p. ej. anular una factura ya anulada), el error llega en la primera llamada.
  • El token no demuestra por sí solo que una persona haya confirmado. Tu cliente debe enseñar el preview y esperar la respuesta del usuario.
codeCausa
confirm_token_invalidToken mal formado o de otra tool o credencial
confirm_token_expiredHa caducado: pide confirmación de nuevo
confirm_token_mismatchLos argumentos no coinciden con los confirmados
confirm_token_usedEl token ya se usó
cancelledEl usuario rechazó la confirmación

Límites

LímiteValor
Peticiones al servidor MCP120 por minuto por credencial, además del límite de la API key
Ficheros en una tool5 MB decodificados por llamada
Búsquedaslimit hasta 100; la siguiente página con next_offset
import_invoicesHasta 100 facturas por llamada
send_invoiceHasta 20 destinatarios

Errores

Antes del protocolo

Si la petición HTTP no pasa la autenticación o los controles de transporte, /mcp responde sin entrar en MCP, con cuerpo {"error": "<código>", "message": "..."}:

HTTPerrorCausa
401missing_credentials u otroFalta la credencial o no es válida
402feature_outside_planEl plan de la empresa no incluye acceso a la API o el Servidor MCP
403origin_not_allowedLa cabecera Origin no está autorizada
403ip_forbiddenLa IP no está en la lista permitida de la clave
421host_not_allowedHost no admitido
429rate_limitedDemasiadas peticiones; respeta Retry-After
503mcp_unavailableEl servidor MCP no está disponible

En una tool

La llamada devuelve isError: true y structuredContent.error con {code, message, params}. Corrige según code y params y reintenta.

{ "error": { "code": "scope_missing", "message": "La credencial no tiene permiso para esta tool.", "params": { "scope": "invoices:issue" } } }
codeCausa
scope_missingLa credencial no tiene el scope de la tool
feature_not_enabledEl plan de la empresa no incluye la funcionalidad
company_not_allowedcompany_id fuera de las empresas autorizadas
invalid_argumentsLos argumentos no cumplen el esquema de la tool
invoice_not_foundLa factura no existe o es de otra empresa
invalid_status_transitionLa factura no admite la operación en su estado
validation_failed · schema_validation_failedEl canónico no pasa las reglas o el esquema (errors)
inferred_fields_not_allowedSe enviaron campos que calcula Faxtal
duplicate_receivedYa existe una recibida con esos datos
invoice_frozenLa factura está congelada fiscalmente
no_recipient_emailNo hay email de destinatario
quota_exceededSe ha agotado la cuota del plan
invalid_base64 · files_too_largeFichero mal codificado o por encima del límite
internal_errorError inesperado, sin detalle técnico

Seguridad

  • Los textos que devuelven las tools (nombres de terceros, conceptos, descripciones) son datos. Tu agente no debe seguirlos como instrucciones.
  • Cada llamada queda registrada con la credencial, la tool, el resultado y el cliente. Las facturas creadas por MCP quedan marcadas con ese origen.
  • Da a cada credencial solo los scopes que necesita.

Ver también

On this page