Servidor MCP
Conecta tu agente LLM al servidor MCP remoto de Notta por HTTP, dos herramientas sobre un catálogo de 24 operaciones, con OAuth, techo por empresa y aprobación humana
Notta expone un servidor MCP (Model Context
Protocol) remoto en https://app.notta.cl/api/mcp. Es un solo servidor, por
HTTP streamable, con OAuth: no hay paquete que instalar ni API key que pegar en
un archivo de configuración.
El catálogo son 24 operaciones: veintiuna de consulta y tres detrás de un permiso
de escritura: emitir documentos tributarios, acusar o reclamar las facturas de
tus proveedores ante el SII, y destrabar un documento cuyo seguimiento ante el
SII se detuvo. Ese permiso viene apagado de fábrica: lo enciende tu empresa
en /app/mcp y quien conecta la app tiene que marcar su casilla al autorizar.
Las tres no se gobiernan igual, y la diferencia importa. Un documento que emite
tu agente sale directo si está bajo el umbral que fijes; un acuse o un reclamo
lo apruebas siempre, sin umbral y sin excepción, porque no se deshace: dado un
acuse ya no se puede reclamar, y una factura aceptada que tu proveedor cede a
factoring no se corrige con una nota de crédito. Destrabar un documento no pasa
por ningún umbral ni por aprobación: no crea ni cambia nada, solo vuelve a
preguntarle el estado al Servicio. Comparte el permiso dte:write con la
emisión, así que hoy no se puede conceder por separado.
Conéctalo
Con Claude Code:
En claude.ai: Ajustes → Conectores → Agregar conector personalizado, y pega esa misma URL. En ChatGPT, Ajustes → Conectores en modo desarrollador. Cualquier otro cliente con HTTP streamable y OAuth (Cursor, Gemini CLI) usa la URL tal cual.
Al conectar por primera vez, tu agente pide autorización OAuth, y lo que esa
conexión se lleva lo decides tú en la pantalla de consentimiento. Puede leer:
tus documentos (DTE) y su estado, y generar un enlace de 15 minutos a su PDF
(sin sesión, para reenviarlo); en qué quedaron las emisiones que dejaste
esperando aprobación (si se aprobaron, si se rechazaron y por qué, o si
vencieron);
el historial de tus documentos de venta recientes, para prellenar uno nuevo;
tus folios (CAF); tu Registro de Compras y Ventas (RCV); tu bandeja de compras
por Casilla de Intercambio con sus plazos; el perfil de tu empresa, tu estado de certificación ante el SII y tu
catálogo de contrapartes; el inventario de tus certificados digitales (nunca la
clave de firma); y tu plan y cuota de uso. La escritura va aparte, en casillas
que marcas tú y que solo aparecen si tu empresa la habilitó: emitir documentos
tributarios a tu nombre (facturas, notas de crédito y de débito, guías de
despacho); sobre el umbral que fije tu empresa, cada documento espera la
aprobación de una persona. Y acusar recibo o reclamar las facturas de tus
proveedores ante el SII; cada acción la aprueba una persona antes de
registrarse, porque son irreversibles y excluyentes entre sí. La casilla de
emisión concede además destrabar un documento cuyo seguimiento ante el SII se
detuvo: Notta vuelve a preguntarle el estado al Servicio. No crea documentos ni
cambia ninguno, y no espera aprobación porque no hay nada que aprobar.
Administra o revoca las apps conectadas desde /app/mcp en el dashboard.
La pantalla de consentimiento te dice qué app pide acceso, a qué empresa y a qué dominio van los datos (salen de Notta hacia el proveedor de esa app, que puede procesarlos fuera de Chile), y marca como no verificada a cualquier app que no pueda comprobar. Si administras varias empresas, ahí mismo eliges a cuál conectar la app (una conexión por empresa), sin cancelar ni volver a empezar. Solo se ofrecen las empresas en las que tienes membresía.
Autorización
El servidor implementa OAuth 2.1 con PKCE (S256 obligatorio) y registro
dinámico de clientes. Tu cliente MCP descubre los endpoints por metadata; no
hay que copiarlos a mano:
| Metadata | URL |
|---|---|
| Recurso protegido (RFC 9728) | https://app.notta.cl/.well-known/oauth-protected-resource |
| Servidor de autorización (RFC 8414) | https://app.notta.cl/.well-known/oauth-authorization-server |
| Manifiesto MCP | https://notta.cl/.well-known/mcp.json |
Una solicitud de autorización que pida un permiso que no se puede conceder no se
rechaza: se recorta. El grant sale con los permisos que sí correspondían y la
respuesta del token declara cuáles son (RFC 6749 §3.3), así que tu cliente
siempre sabe con qué se quedó. scope=read sigue siendo válido y significa toda
la lectura. El token queda atado a una empresa y al ambiente SII de esa empresa
(cert o prod): ningún parámetro del cliente lo cambia.
Los permisos efectivos de cada llamada son la intersección de tres cosas (lo que
la app pidió, el techo de la empresa y lo que permite tu rol) y se recalculan en
cada petición: bajar el techo en /app/mcp corta la escritura de todas las apps
conectadas en la petición siguiente, sin esperar a que expire ningún token. El
día que el SII autoriza a tu empresa a emitir en producción, las conexiones MCP
de esa empresa se revocan y el techo vuelve a apagarse: hay que reconectar y
encenderlo de nuevo, a propósito, sabiendo que ahora los documentos tienen
validez tributaria.
El manifiesto es público y sin token: publica el catálogo completo. Lo que un
token concreto puede ejecutar depende del permiso que le diste al autorizar. Si
tu agente no habla MCP, el corpus de estas docs está en https://notta.cl/llms.txt
y /llms-full.txt.
Las dos herramientas
El servidor no expone una tool por endpoint: expone dos, sobre un catálogo de operaciones que se descubre en caliente.
| Tool | Argumentos | Qué hace |
|---|---|---|
discover | { operation? } | Sin argumentos, devuelve a qué empresa y ambiente SII está conectado tu agente, qué puede y qué no puede hacer (con el porqué y el cómo habilitarlo) y el catálogo de operaciones que tu conexión alcanza. Con operation, el esquema completo de parámetros de esa operación y un ejemplo de llamada. |
execute | { operation, params?, body? } | Ejecuta una operación del catálogo. params lleva los parámetros de ruta, los filtros y los headers que la operación declara (Idempotency-Key, X-Cert-Id); body, el cuerpo JSON de las que escriben. Todo se valida contra el esquema OpenAPI: una clave no declarada nunca llega a la API. |
Lo que limita a execute es el catálogo, no el verbo: una operación que no está
en él no viaja, y el guardia de /api/v1 la vuelve a comparar contra el mismo
catálogo con tu token. Emitir se ve así:
La Idempotency-Key la pone tu agente, no el servidor. Genera una por
documento y reutiliza EXACTAMENTE ese valor si tienes que reintentar: una clave
nueva en el reintento no es un reintento, es un segundo documento real ante el
SII. discover({ operation: "emitDte" }) publica el esquema completo del cuerpo
y de los headers que la operación exige.
También puedes llamar POST /api/v1/dtes directo con el token de la conexión:
recibe el mismo guardia, el mismo techo y el mismo umbral. Y si prefieres no
encender la escritura por MCP, la API REST con una
API key sigue siendo el camino: mismo shape, misma
cuenta, pero sin pasar por el techo ni por el panel de aprobación.
Catálogo de operaciones
| Operación | Endpoint | Qué devuelve |
|---|---|---|
listDtes | GET /dtes | Tus DTEs, con limit (máx. 100), sort (folio, monto_total, fecha_emision, sii_status, created_at) y dir |
emitDte | POST /dtes | La única operación del catálogo que crea un documento: emite una factura, nota de crédito, nota de débito o guía de despacho. Exige el permiso dte:write y pasa por el gate de abajo |
getDte | GET /dtes/{id} | El detalle de un DTE con sus líneas |
getDteEvents | GET /dtes/{id}/events | La historia de estados SII de ese DTE (queued → sending → EPR/RPR/RFR/RCT/RSC). Este es el endpoint para seguir un documento, no el de abajo |
refreshDteStatus | POST /dtes/{id}/refresh-status | La escotilla para un documento cuyo seguimiento se murió (stuck, sin_permiso_sii, o un reloj frío de más de 25 h): vuelve a consultarle el estado al SII. Exige el permiso dte:write, el mismo que emitir. Tres respuestas 2xx, y solo una actúa: refresh_enqueued (202). already_terminal (200) significa que el SII ya juzgó el documento (puede ser un rechazo: mira sii_glosa) y poll_in_progress (200) que el seguimiento sigue vivo y trae retry_after en segundos. Llamarlo en bucle no acelera nada |
getDtePdfUrl | GET /dtes/{id}/pdf-url | Una URL firmada (vence en 15 minutos) para descargar el PDF sin sesión, para reenviarla a tu cliente |
getDteTotals | GET /dtes/totales | Conteo y suma (neto/exento/IVA/total) por período, tipo y estado: agregado en SQL, sin el detalle de cada documento |
getPendingAction | GET /dtes/pendientes/{id} | En qué quedó una emisión que el gate dejó esperando: pending, approved (con el DTE resultante), rejected (con el motivo que escribió la persona) o expired |
listSiiRecentDocuments | GET /sii/documents/recent | Tus últimas ventas (33/34) emitidas, para prellenar un documento nuevo |
getSiiDocumentTemplate | GET /sii/documents/{id}/template | El detalle de un documento anterior, como plantilla para uno nuevo |
listCaf | GET /caf | Tus CAF (folios), con folios restantes y aviso de folios bajos |
listRcv | GET /rcv | Tu Registro de Compras y Ventas por período, o el detalle de un RUT |
listRcvDocuments | GET /rcv/documents | El mismo registro documento por documento, con el evento del receptor y la referencia de cada NC/ND |
listRecepcion | GET /recepcion | Tu bandeja de compras por Casilla de Intercambio, con el plazo de 8 días corridos para acusar o reclamar ya calculado por fila |
registrarEventoRecepcion | POST /recepcion/{id}/evento | La operación que declara algo ante el SII a tu nombre: acusa recibo o reclama una factura de proveedor. Exige el permiso recepcion:write y siempre queda esperando aprobación humana, sin umbral |
getProfile | GET /profile | El perfil de tu empresa: giro, dirección, comuna y actividad económica |
getSiiCertState | GET /sii/cert-state | El estado de tu proceso de certificación ante el SII |
getSiiReadiness | GET /sii/readiness | El resumen de aplicabilidad y estado de tu certificación SII |
getOnboardingReadiness | GET /onboarding/readiness | Qué le falta a tu empresa para poder emitir |
getSuggestedDteTypes | GET /onboarding/suggested-types | Los tipos de DTE sugeridos según tu postulación ante el SII |
listEmpresas | GET /sii/empresas | Tu catálogo de contrapartes |
getEmpresa | GET /sii/empresas/{id} | La ficha completa de una contraparte |
listCertificates | GET /certificates | Tus certificados digitales vigentes (nunca la clave de firma) |
getBillingPlan | GET /billing/plan | Plan activo y cuota del mes |
Son 24 operaciones. Para leer un DTE por id, primero lista con listDtes y toma
el id de la fila: el mismo usage_hint que devuelve discover, que
también trae la regla de corte de más abajo.
Para seguir un documento recién emitido, el camino es getDteEvents (o
listDtes filtrando por estado), no refreshDteStatus: la emisión publica un
seguimiento durable que lleva el documento a su estado final por su cuenta.
refreshDteStatus existe para cuando ese seguimiento se murió, y si está vivo
responde poll_in_progress sin consultarle nada al SII. Notta tiene además
webhooks salientes (/docs/webhooks), pero sus cinco endpoints
están fuera de este catálogo a propósito: registrar una URL de callback
redirige el flujo de documentos de la empresa hacia un tercero, y esa es una
decisión de infraestructura de la persona que integra, no del agente que consume.
Un agente que necesita el estado lo tiene completo por pull. Corta cualquier bucle de espera por estado.terminal, NUNCA por sii_status === "EPR": un rechazo (RFR, RCT, RSC y RCH) también es final, y ese bucle no saldría nunca. stuck y sin_permiso_sii no son terminales (el SII no llegó a juzgar el documento) pero tampoco avanzan solos: los destraba POST /dtes/{id}/refresh-status.
Emitir por MCP: el techo, el umbral y la aprobación
Emitir es la escritura que más gobierno necesita del catálogo (es la que crea un documento con valor tributario), y ninguna empresa la tiene encendida sin decidirlo. Tienen que darse las tres cosas a la vez:
- El techo de tu empresa, arriba. Un
owneroadminenciende «Escritura por MCP» en/app/mcp. Viene apagado; con el techo abajo la casilla ni siquiera aparece al autorizar, y bajarlo corta la escritura de todas las apps conectadas en la petición siguiente. - El permiso, marcado al conectar. Quien autoriza la app marca la casilla de emisión en la pantalla de consentimiento. Sin marcarla, la conexión queda de solo lectura.
- El rol de quien autorizó. Un
viewerno otorga emisión ni marcando la casilla, y degradar a esa persona corta la escritura de su app.
Con eso puesto, cada emisión pasa por el gate:
| Situación | Qué pasa |
|---|---|
| Ambiente de certificación | Emite directo: los documentos son de prueba |
| Producción, monto ≤ tu umbral | Emite directo |
| Producción, monto > tu umbral | Queda esperando aprobación humana |
| Tu empresa pidió revisar todo | Queda esperando aprobación humana, siempre |
| Documento sin monto comparable (guía de traslado interno) | Emite directo |
El umbral se guarda en UF (no en pesos, para que no proteja cada año un poco
menos sin que nadie lo decida) y se compara con el valor del día. Por defecto son
60 UF y un tope de 60 documentos por minuto, ambos configurables en /app/mcp.
Cuando un documento queda esperando, la respuesta trae status: "pending", el
pending_id, un approve_url que apunta a /app/mcp/pendientes y el motivo en
español. Ese documento no quema folio ni llega al SII: espera hasta 24 horas
a que una persona con permiso para emitir lo apruebe o lo rechace desde el
dashboard, y vence solo si nadie lo mira. Aprobar dos veces no duplica el
documento. Tu agente consulta en qué terminó con getPendingAction: si lo
rechazaron, ahí está el motivo que escribió la persona, para corregir y volver a
pedirlo.
Lo que un agente todavía no hace por este canal
Por MCP no hay ruta para anular un documento, subir un certificado, pedir o subir folios, ni sincronizar el RCV: leerlos sí, con las operaciones de arriba. La boleta electrónica (39/41) y la boleta de honorarios no están en el catálogo mientras sigan pendientes de certificación ante el SII.
Próximos pasos
- Agentes: patrones para que tu agente emita con confirmación humana y maneje la emisión async.
- Emitir Factura 33: el shape completo del request de emisión y los estados SII.
- Autenticación: API keys, scopes y ambientes cert/prod.
- Referencia de la API: los endpoints que el catálogo del MCP refleja.
Última actualización