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.clUn 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 comoclient_id— por ejemplohttps://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: elclient_idque declara el documento tiene que ser exactamente esa URL,client_nameyredirect_urisson obligatorios, y solo se aceptan clientes públicos (token_endpoint_auth_methodausente o"none", PKCE S256 como siempre). El resultado se cachea respetandoCache-Control: max-age, acotado entre 1 y 24 horas — un error nunca se cachea. Elredirect_uride 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 declarahttp://localhost/…ohttp://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_idpúblico; no hayclient_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-serverEse 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=af0ifjsldkjToken. 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:ready, para la puesta en marcha,onboarding:write,mandato:writeyempresas: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ón | Comportamiento |
|---|---|
| Omitido donde se requiere | La herramienta devuelve empresa_required |
| Presente pero fuera de la lista | empresa_not_allowed — nunca un «no encontrado» a secas |
| Un token con exactamente una empresa | Puedes 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.
| Bucket | Límite | Qué herramientas |
|---|---|---|
| General | 300 req/min | draft_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ón | 10 req/s, ráfaga 30 | emit_document, emit_tipo46, emit_credit_note |
| Declaración F29 y sincronización del RCV | 10 req/min por empresa | file_f29, sync_rcv (una llamada por período; un rango de diez meses gasta el bucket entero) |
| Artefactos | 60 req/min | get_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.