Enty.io

Servidor MCP para Enty.io: facturas, transacciones bancarias, plazos contables y contratos, expuestos como herramientas que tu agente de IA puede invocar.

Documentación

enty-mcp

Un servidor MCP para Enty.io — facturas, transacciones bancarias, plazos contables y contratos, expuestos como herramientas que tu agente de IA puede invocar.

Enty no tiene API pública. Este servidor utiliza el mismo endpoint GraphQL que usa la aplicación web de Enty, autenticado con el token de sesión de tu navegador. Esto conlleva advertencias que deberías leer antes de usarlo:

No oficial. Este proyecto no está afiliado ni respaldado por Enty. Se comunica con una API interna no documentada que puede cambiar o romperse en cualquier momento, y su uso puede no estar cubierto por los términos de servicio de Enty. Lee los datos reales de tu empresa — no existe un entorno de pruebas. Dos herramientas también escriben en él (solo elementos de catálogo); nada elimina.

Herramientas

HerramientaQué devuelve
enty_get_meUsuario conectado + empresa activa
enty_list_companiesEmpresas de la cuenta
enty_list_invoicesFacturas con filtro de estado, totales, recuentos por estado
enty_list_counterpartiesClientes/proveedores con datos fiscales
enty_list_itemsElementos de catálogo (líneas de factura)
enty_list_item_unitsUnidades de medida que puede usar un elemento
enty_list_transaction_documentsDocumentos ya adjuntos a una transacción
enty_list_invoice_payment_candidatesTransacciones que podrían ser el pago de una factura
enty_list_bank_accountsCuentas bancarias con IBAN y estado de conexión
enty_list_transactionsTransacciones con filtros de cuenta/fecha/dirección/texto
enty_get_transactionUna transacción con nota y categoría
enty_get_balanceSaldo combinado de las cuentas seleccionadas
enty_get_transactions_statisticsEstadísticas de coincidencia de documentos para un rango de fechas
enty_list_categoriesÁrbol de categorización de transacciones
enty_list_accounting_periodsPeriodos contables
enty_get_period_deadlinesPróximo plazo fiscal/de declaración para un periodo
enty_get_potential_taxImpuesto estimado para un periodo, por tipo (EUR)
enty_get_period_issuesProblemas de contabilidad abiertos para un periodo
enty_list_contractsContratos con estado del ciclo de vida de firma electrónica
enty_list_dealsAcuerdos con estado y contraparte
enty_get_deals_statsImportes esperados vs recibidos de acuerdos

Herramientas de escritura

HerramientaQué hace
enty_create_itemCrear un elemento de catálogo (producto/servicio)
enty_update_itemActualizar nombre, precio, moneda, unidad o descripción de un elemento de catálogo
enty_create_dealCrear un acuerdo para una contraparte
enty_create_invoiceCrear un borrador de factura con líneas
enty_mark_invoice_paidMarcar una factura como pagada
enty_link_transaction_to_invoiceRegistrar una transacción bancaria como pago de una factura
enty_attach_document_to_transactionSubir un archivo local y adjuntarlo a una transacción

Estas escriben en tu empresa en vivo. Vale la pena distinguir dos niveles de riesgo.

Los elementos de catálogo y los acuerdos son datos de referencia. Crear o editar uno no altera las facturas que ya lo referencian.

Las últimas tres tocan la contabilidad. Vincular una transacción a una factura y adjuntar documentos cambian registros con los que trabaja tu contador, y un vínculo incorrecto se lee como un error de conciliación. Ninguna de ellas se puede deshacer aquí, así que verifica los ids antes de invocarlas.

enty_create_invoice deja un borrador. No se envía nada al cliente ni se genera PDF; revísalo y emítelo en la aplicación web de Enty. Requiere cuatro llamadas, porque Enty construye una factura de esa manera: crear un borrador en blanco, ajustar el encabezado, añadir las líneas, guardar los totales. Si un paso posterior falla, el borrador sobrevive y el error lleva su id para que puedas terminarlo o descartarlo manualmente.

enty_link_transaction_to_invoice necesita que la factura tenga un documento generado, ya que el vínculo se establece entre ese documento y la transacción. Enty no tiene un registro de pago separado. Abre una factura nueva una vez en la aplicación web si la herramienta informa que no tiene ninguna.

enty_attach_document_to_transaction es la única vía que no es GraphQL. Los bytes van al servicio de almacenamiento de archivos de Enty como datos de formulario multiparte, el archivo devuelto se registra como documento contable, y solo entonces se vincula a la transacción.

Nada en este servidor elimina. La API de Enty tiene 233 mutaciones, 19 de ellas de eliminación (deleteItemsAtOrganization, DeleteTransactions, DeleteUserCompanies, etc.). Ninguna está expuesta, y el cliente GraphQL se niega a enviar cualquier mutación cuyo nombre de operación no esté en una lista blanca explícita (ALLOWED_MUTATIONS en src/enty_mcp/graphql.py), por lo que una escritura bloqueada nunca sale del proceso. Eliminar cualquier cosa es una acción manual en la aplicación web de Enty, a propósito.

enty_update_item fusiona: pasa solo los campos que quieres cambiar. La actualización de Enty reemplaza el elemento completo, por lo que la herramienta primero lee los valores actuales del elemento y los envía de vuelta junto con tus cambios. Sin eso, actualizar un campo dejaría en blanco el resto.

El resto de la superficie de mutaciones está mapeada (spec/graphql/bundle-operations/) pero no expuesta. Añadir una escritura significa añadir su nombre a la lista blanca, que es el paso de revisión.

Autenticación

Dos opciones. Elige una.

Correo electrónico y contraseña (ENTY_EMAIL, ENTY_PASSWORD). El servidor inicia sesión por ti, mantiene el token de sesión en memoria y vuelve a iniciar sesión automáticamente cuando la sesión expira. No hay nada que hacer cuando un token muere, que es lo que quieres para un servidor destinado a ejecutarse sin supervisión. Enty no emite token de refresco, por lo que renovar es realmente un nuevo inicio de sesión.

Un token de sesión (ENTY_AUTH_TOKEN). Inicia sesión en app.enty.io, abre DevTools → Red, haz clic en cualquier solicitud a /api/ y copia el valor del encabezado de solicitud enty-auth. Esto expira, y sin credenciales el servidor no puede renovarlo, por lo que repites los pasos cada vez que las herramientas empiecen a fallar.

Configura ambos y el token se usa primero, con respaldo a las credenciales una vez que expire. Eso evita un inicio de sesión al arrancar mientras sigue sobreviviendo a la expiración.

De cualquier manera, el secreto otorga acceso completo a tu cuenta de Enty, así que trátalo como la contraseña que efectivamente es. Las credenciales y tokens se mantienen como SecretStr de pydantic, se mantienen fuera de los encabezados compartidos del cliente, se envían solo a tu ENTY_BASE_URL configurado y nunca se escriben en los registros. El correo de la cuenta se registra en INFO cuando ocurre un inicio de sesión, para que puedas saber qué cuenta está usando un servidor en ejecución.

Las cuentas con autenticación multifactor no pueden usar correo y contraseña. Enty responde a esos inicios de sesión sin id de sesión, y el servidor lo indica en lugar de fallar de manera oscura. Usa un token para esas cuentas.

Ejecución

Con uv

git clone https://github.com/appsome/enty-mcp-server
cd enty-mcp-server
cp .env.example .env      # paste your token
uv sync
uv run enty-mcp                       # streamable HTTP on :8001/mcp
uv run enty-mcp --transport stdio     # for stdio clients

Con Docker Compose

cp .env.example .env      # fill in ENTY_EMAIL and ENTY_PASSWORD
docker compose up -d
# server: http://localhost:8001/mcp   health: http://localhost:8001/health

El archivo compose compila desde el código fuente. Para ejecutar una imagen publicada en su lugar:

docker run -d -p 8001:8001 \
  -e ENTY_EMAIL=you@example.com -e ENTY_PASSWORD=... \
  ghcr.io/appsome/enty-mcp-server:latest

Las imágenes se compilan para linux/amd64 y linux/arm64 y se publican en GitHub Container Registry en cada push a main, etiquetadas latest y con el sha del commit. Publicar una etiqueta v* añade las etiquetas semver correspondientes. El contenedor sale inmediatamente con un error claro si no se configuran ni credenciales ni un token.

Configuración

Variable de entornoPredeterminado
ENTY_EMAIL / ENTY_PASSWORDcredenciales; el servidor inicia sesión y se renueva solo
ENTY_AUTH_TOKENtoken de sesión; alternativa a lo anterior
ENTY_BASE_URLhttps://app.enty.io
ENTY_LOCALEen
ENTY_TIMEOUT_S30
MCP_HOST / MCP_PORT0.0.0.0 / 8001transportes HTTP
LOG_LEVELINFO

Conexión de un cliente

OpenHands (docker compose): usa docker-compose.override.example.yml para añadir el servicio a tu stack, luego apunta OpenHands a http://enty-mcp:8001/mcp — consulta openhands/mcp.json y openhands/config.toml.snippet.

Claude Code:

claude mcp add --transport http enty http://localhost:8001/mcp

Claude Desktop (stdio):

{
  "mcpServers": {
    "enty": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/enty-mcp-server", "enty-mcp", "--transport", "stdio"],
      "env": { "ENTY_EMAIL": "you@example.com", "ENTY_PASSWORD": "..." }
    }
  }
}

Cómo se hizo el mapeo de la API

El endpoint GraphQL de Enty tiene la introspección deshabilitada, por lo que el esquema se reconstruyó a partir de dos fuentes: una captura HAR de la aplicación web (56 operaciones con formas de respuesta, spec/graphql/operations/) y los paquetes JS de la aplicación, que contienen todos los documentos GraphQL que el frontend puede enviar (434 operaciones, spec/graphql/bundle-operations/). spec/graphql/NOTES.md documenta las convenciones y las brechas restantes. Los scripts de extracción en scripts/ son repetibles cuando la aplicación cambia.

Desarrollo

uv sync
uv run pytest          # respx-mocked, no network
uv run ruff check src tests scripts
uv run pyright

Las pruebas nunca tocan la API real. Los datos de los fixtures son sintéticos, con forma de respuestas registradas.

Licencia

MIT