Facturiadocs
MCP / IA

Conectar un agente

mcp.facturia.cl — el mismo motor, otra puerta de entrada. Cómo conectar Claude, qué pasa en el OAuth y por qué un grant de sandbox es un límite duro.

El mismo motor que la API REST, otra puerta de entrada: en vez de que una persona escriba curl, un agente de IA de terceros llama herramientas tipadas.

https://mcp.facturia.cl

Un solo endpoint MCP (/mcp) hablando Streamable HTTP, y un solo conjunto de endpoints OAuth en el mismo origen. No hay subdominios por empresa ni por cuenta: la tenencia es un claim del token, no un hostname.

El hecho arquitectónico

El servidor MCP es un cliente REST de /v1

No tiene lógica de negocio ni credenciales del motor: ni certificado del SII, ni llave de firma, ni acceso al esquema del motor. Cada pregunta de dominio — cuáles son los totales de un documento, si hay folios disponibles, qué dice el F29 — es un request a /v1, nunca una consulta.

Eso significa que todo lo que vale en esta documentación sobre estados, errores y garantías vale igual desde un agente.

Por qué el agente no es un desarrollador

Un desarrollador lee la documentación antes de escribir la primera línea; un agente decide qué llamar en el mismo turno en que se lo piden. Este servidor publica sus páginas como recursos MCP —las devuelve enteras, no como un enlace, así que un cliente sin capacidad de fetch también las lee— y aun así cada herramienta tiene que describirse sola: la documentación explica el modelo, la descripción de la herramienta es lo único que el modelo tiene a mano cuando decide. De ahí salen tres compromisos de diseño de esta capa:

Suite completa, no un wrapper delgado. Emisión, recepción y la capa tributaria están todas aquí.

Ejecución directa, con una salida de emergencia para quien la quiera. El paso de aprobación de herramientas del propio cliente MCP es el humano en el ciclo por defecto. Las empresas que quieran más pueden encender un doble paso borrador-y-confirmación.

Ser AI-first es resolver ambigüedad, no rechazarla. draft_document acepta un receptor por nombre, porque así le habla una persona a un agente. Los ítems van estructurados ([{description, quantity, unit_price}]): la prosa la convierte el modelo, que es quien la entiende mejor y más barato, y draft_document devuelve los totales para que la persona los vea antes de que se firme nada. No hay un parser de prosa en la API, y no lo va a haber: un parser escondido detrás de un endpoint convierte una cantidad mal leída en un documento tributario.

Agregar a tu cliente

Una sola dirección, https://mcp.facturia.cl/mcp, y ningún comando que instalar: el transporte es Streamable HTTP, así que no hay paquete que bajar ni proceso local que levantar. Tampoco hay un secreto que pegar en el archivo de configuración — el cliente descubre el OAuth solo (RFC 9728), se identifica con su documento de metadatos o se registra solo (RFC 7591), y te abre la pantalla de consentimiento en el navegador, donde tú decides qué puede hacer el agente y sobre qué empresas.

En Claude Desktop: Settings → Connectors → Add custom connector, con la URL https://mcp.facturia.cl/mcp. Si prefieres editar el archivo a mano (claude_desktop_config.json), es una línea:

{
  "mcpServers": {
    "facturia": { "url": "https://mcp.facturia.cl/mcp" }
  }
}

¿Nunca has creado una cuenta?

La pantalla de consentimiento te deja iniciar sesión ahí mismo y crear la llave del grant por ti — no tienes que traerla lista. Y si todavía no tienes cuenta, el enlace de esa pantalla te lleva a crearla y te devuelve a la misma autorización cuando terminas: no hay que reconectar el agente.

¿Tampoco tienes empresas todavía? Tampoco es un problema: marca «Todas las empresas de esta cuenta, incluidas las que cree más adelante» junto con empresas:write, y el agente crea la primera con create_empresa.

Escribiendo https://mcp.facturia.cl en el navegador sale la misma información en una página: qué es, el snippet y el enlace a esta documentación.

Cómo se identifica el cliente. La especificación de MCP fija un orden de prioridad para que un cliente diga quién es: un cliente pre-registrado primero, después un documento de metadatos del client_id (CIMD), y el registro dinámico al final, como respaldo.

  • Documento de metadatos del client_id (CIMD). El cliente puede usar una URL https como client_id — por ejemplo https://claude.ai/.well-known/oauth-client.json — en vez de registrarse antes de conectarse. El servidor la obtiene al momento de la conexión (GET, 3 s de plazo, 32 KB máximo, sin redirecciones, nunca hacia una dirección privada o loopback) y valida el JSON: el client_id que declara el documento tiene que ser exactamente esa URL, client_name y redirect_uris son obligatorios, y solo se aceptan clientes públicos (token_endpoint_auth_method ausente o "none", PKCE S256 como siempre). El resultado se cachea respetando Cache-Control: max-age, acotado entre 1 y 24 horas — un error nunca se cachea. El redirect_uri de cada autorización tiene que calzar exacto con uno de los que declara el documento, la misma regla que un cliente registrado — con una sola excepción, la de RFC 8252 §7.3: si el documento declara http://localhost/… o http://127.0.0.1/…, el puerto no se compara, porque un cliente nativo como Claude Code abre uno distinto en cada sesión.
  • Registro dinámico de cliente (RFC 7591). El respaldo para el cliente que todavía no publica un CIMD — Cursor, VS Code, Windsurf, ChatGPT y similares siguen aquí. Cualquier cliente MCP se registra en la primera conexión, sin aprobación previa ni lista blanca de aplicaciones. El registro devuelve un client_id público; no hay client_secret, porque PKCE es el mecanismo de confidencialidad de un cliente público que no puede guardar un secreto.
POST https://mcp.facturia.cl/register        (RFC 7591)
GET  https://mcp.facturia.cl/.well-known/oauth-authorization-server

Ese mismo GET declara si el servidor acepta CIMD:

{ "client_id_metadata_document_supported": true }

Qué ve la persona en la pantalla de consentimiento. Con un cliente CIMD la pantalla muestra su nombre y el origen de su documento de metadatos («Claude · claude.ai») — ese origen es verificable, porque ahí vive el documento. Un cliente que se registró dinámicamente sigue con la advertencia «Esta aplicación se registró sola y eligió su propio nombre — nosotros no lo verificamos». En los dos casos la pantalla sigue mostrando el host al que va el código de autorización («A dónde va esto»), con una advertencia extra si ese host es localhost o 127.0.0.1.

Autorización y consentimiento. Flujo estándar de authorization-code + PKCE. La pantalla de consentimiento no es un timbre de goma: ahí decides qué credencial de Facturia queda envuelta en el grant.

GET https://mcp.facturia.cl/authorize
  ?client_id=mcpc_01K2SC9X4M
  &redirect_uri=https://claude.ai/api/mcp/auth_callback
  &response_type=code
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &scope=documents:read documents:write tax:read
  &state=af0ifjsldkj

Token. POST /token cambia el código (con el verificador PKCE) por un access token de vida corta y un refresh token de vida más larga, revocable individualmente.

{
  "access_token": "mcpat_9lQpV3fA2mKcRt7wZxYb1Nde",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "mcprt_qT8vN2wLmR5xKpJ7hYdCbA3s",
  "scope": "documents:read documents:write tax:read"
}

Qué carga el token

El mismo modelo de autorización que una llave de API, porque debe comportarse igual una vez emitido:

  • una cuenta,
  • un modo — el token puede ser solo-sandbox, live o mixto, según lo que se concedió;
  • un conjunto de scopes, con el mismo vocabulario que los scopes REST: documents:read, documents:write, received:read, received:write, tax:read, tax:write, empresas:read, usage:read y, para la puesta en marcha, onboarding:write, mandato:write y empresas:write;
  • una lista blanca de empresas — RUT explícitos, o "*".

Los dos scopes de atestación no existen en esta superficie

/v1 también define mandato:attest y onboarding:attest: aceptar el mandato con un cuerpo, y autorizar la puesta en vivo con uno. Esos son el momento en que una persona dice «sí, acepto» y «sí, este mes», y quedan registrados como evidencia de esa decisión.

Un agente no puede pedirlos acá, y no es una omisión: las herramientas MCP acuñan el enlace y se detienen; la persona decide en la página. Si el agente pudiera atestar, el registro de tu aprobación sería la palabra del agente.

Nombrar la empresa en una llamada de herramienta

La lista de un token puede abarcar varias empresas (el agente de un contador que lleva varios clientes, digamos), así que cada herramienta con alcance de empresa toma un argumento empresa explícito — el análogo directo del header Facturia-Empresa.

SituaciónComportamiento
Omitido donde se requiereLa herramienta devuelve empresa_required
Presente pero fuera de la listaempresa_not_allowed — nunca un «no encontrado» a secas
Un token con exactamente una empresaPuedes omitirlo; el servidor lo rellena
Herramientas de nivel cuenta (list_empresas, get_usage sin empresa)Rechazan el argumento

El límite del sandbox

Trampa

Un grant de sandbox es una capacidad, no una política

Un token con alcance de sandbox no puede alcanzar los datos de una empresa live ni emitir nada con efecto legal. No es una preferencia que se pueda cambiar en caliente: es un límite estructural.

Por eso es el default correcto para cualquier cosa exploratoria o de cara al público. El registro dinámico de cliente significa que el software que llama no está verificado por construcción, y el alcance del token es la defensa principal contra un agente comprometido o demasiado confiado.

La pantalla de consentimiento defiende lo mismo desde el otro lado: no viene nada premarcado. Eliges explícitamente qué empresas puede tocar este agente. Conceder "*" es posible pero exige un clic extra de confirmación — la asimetría es intencional, porque un grant a un agente de terceros demasiado confiado es un riesgo materialmente distinto de una llave de API de primera parte guardada en tu propio backend.

Revocación

En el panel, Agentes conectados lista cada grant MCP de la cuenta: qué cliente se conectó, con qué scopes, sobre qué empresas, en qué modo, cuándo y cuándo lo usó por última vez. Revocar uno invalida de inmediato sus access y refresh tokens.

Hay un segundo camino que sirve igual: cada grant envuelve una llave de API tuya, así que revocar esa llave en Llaves mata el grant en el mismo instante.

Límites de tasa

Las llamadas MCP pegan a los mismos servicios de backend que las REST y comparten los mismos buckets publicados. No hay cuota MCP separada, porque no hay un pipeline de emisión separado por debajo.

BucketLímiteQué herramientas
General300 req/mindraft_document, todas las list_* / get_*, query_rcv, get_periodo_summary, y las escrituras que no emiten ni declaran (update_*, set_*, characterize_purchases, send_document, request_folios, …)
Emisión10 req/s, ráfaga 30emit_document, emit_tipo46, emit_credit_note
Declaración F29 y sincronización del RCV10 req/min por empresafile_f29, sync_rcv (una llamada por período; un rango de diez meses gasta el bucket entero)
Artefactos60 req/minget_document_file (el minteo de la URL firmada, no la descarga posterior, que es pública y no medida)

Una llamada limitada devuelve el tipo rate_limit_error con un campo retry_after_seconds sobre el que un agente puede actuar directamente.

En esta página