savia-mcp

savia-mcp

MCP server that exposes SAVIA, a legacy travel-industry ERP with no public API, as tools an AI assistant can use. It uses Playwright to operate the browser, enabling read-only extraction of information like screenshots, text, and tables.

Category
Visit Server

README

savia-mcp

MCP Server en Python para integrar la app web SAVIA (savia4.com.ar) con Claude Desktop, usando Playwright para operar el navegador.

In English — An MCP server that exposes a legacy travel-industry ERP as tools an AI assistant can use. The ERP has no public API: network analysis showed all traffic goes through the framework's internal AJAX protocol with server-regenerated widget UUIDs, so a browser is the only viable integration path. The interesting parts are documented below: why HTTP was ruled out, how interactive elements are detected in a DOM with no semantic elements, and how server-side sessions are handled. Written as interoperability tooling for an account I own — read-only by design.

⚠️ SOLO LECTURA. Este MCP es exclusivamente para extraer información (capturas, texto, tablas). Aunque savia_click, savia_escribir y savia_presionar_enter son genéricos y técnicamente podrían usarse para crear o modificar expedientes, órdenes, comprobantes, etc., eso está prohibido por decisión explícita del dueño de la cuenta. Cualquier tarea que requiera crear/modificar algo en SAVIA se hace manualmente, no con este MCP.

Qué es SAVIA (importante para entender el diseño)

SAVIA corre sobre ZK Framework 6.5 (Java, AJAX, ~2012). Esto tiene dos consecuencias:

  • Los IDs del DOM se regeneran en cada carga de página y no son estables entre sesiones (ej. rH8Qk0). Por eso el login se ubica por placeholder del campo (fijo en el servidor), no por ID ni CSS frágil.
  • Las pantallas internas (post-login: reservas, facturación, etc.) no vienen mapeadas de antemano en este proyecto — no había forma de inspeccionarlas sin credenciales válidas. Por eso los tools no son scrapers fijos por pantalla, sino un set de herramientas genéricas (captura de pantalla, texto visible, listar elementos clicables, click por texto, extracción de grillas ZK) para que Claude pueda explorar y operar cualquier pantalla de SAVIA de forma interactiva, viendo lo mismo que ve el usuario.

El flujo de login (usuario + ID de empresa → luego contraseña, en dos pasos) está probado en vivo y funciona contra una cuenta propia. El popup de error de SAVIA usa la clase ZK .z-window-modal (confirmado forzando un error real) — es genérico, sirve para detectar cualquier alerta en cualquier pantalla, no solo el login.

El dashboard post-login (index.zul) ya se conoce: 8 menús superiores (Página Principal, Perfil Empresarial, Tarifarios y Cupos, Proveedores y Egresos, Clientes e Ingresos, Caja y Otros Medios, Contabilidad y Reportes, Soporte y Mesa de Ayuda) y accesos directos como Cotizaciones, Expedientes, Clientes, Órdenes de Ingreso/Egreso, Cronogramas de Salidas, Cajas, Comisiones y Comprobantes. Lo que falta mapear es el detalle de cada pantalla puntual (columnas de cada listado, formularios), por eso los tools siguen siendo genéricos hasta que se elija una pantalla concreta para automatizar.

¿Por qué no hablarle directo por HTTP en vez de un navegador? Se inspeccionó el tráfico real (Network) durante login y navegación: todo pasa por POST /savia/zkau con el protocolo interno de ZK ("AU requests"), cuyo payload referencia UUIDs de widgets que el servidor regenera en cada sesión (uuid_0=c5yPr0, etc.), atados al árbol de componentes vivo en el servidor. No hay ningún endpoint REST/JSON paralelo (se confirmó navegando por varias secciones: 0 requests XHR/fetch fuera de /zkau, un solo dominio). Replicar esto sin navegador implicaría reimplementar buena parte del protocolo cliente de ZK a mano — fragil y se rompe con cualquier update de SAVIA. Por eso el diseño usa Playwright: deja que el navegador real haga esa sincronización.

Estructura

savia-mcp/
├── savia_mcp/
│   ├── __init__.py
│   ├── browser.py      # Sesión de Playwright (login, screenshot, ciclo de vida)
│   ├── extractors.py   # Scraping genérico: texto, clicables, grillas ZK
│   └── server.py       # Servidor MCP (stdio) y definición de tools
├── .env.example
├── .env                 # (git-ignored) tus credenciales reales
├── pyproject.toml
├── setup.ps1
└── README.md

Instalación (Windows)

cd "savia-mcp"
.\setup.ps1

Esto crea un entorno virtual .venv, instala dependencias, descarga Chromium para Playwright y genera .env a partir de .env.example.

Después completá tus credenciales en .env:

SAVIA_URL=https://www.savia4.com.ar:8443/savia
SAVIA_USUARIO=tu_usuario
SAVIA_EMPRESA=tu_id_de_empresa
SAVIA_PASSWORD=tu_contraseña
SAVIA_HEADLESS=false

SAVIA_HEADLESS=false deja la ventana de Chrome visible — recomendado mientras se explora la app por primera vez con Claude.

Configurar Claude Desktop

setup.ps1 imprime el snippet listo para copiar. Es de esta forma, en %APPDATA%\Claude\claude_desktop_config.json:

{
  "mcpServers": {
    "savia": {
      "command": "C:\\ruta\\a\\savia-mcp\\.venv\\Scripts\\python.exe",
      "args": ["C:\\ruta\\a\\savia-mcp\\savia_mcp\\server.py"]
    }
  }
}

Reiniciá Claude Desktop después de guardar.

Tools disponibles

Tool Qué hace
savia_login Login en SAVIA (usa .env salvo que se pasen overrides). Maneja los dos flujos reales: formulario completo (usuario+empresa→password) y el rápido "Hola <nombre>..." que aparece si el navegador ya tiene una sesión previa en el mismo proceso
savia_cerrar_sesiones_duplicadas Si savia_login falla por límite de sesiones simultáneas de la empresa, cierra las sesiones listadas y completa el login. Desloguea a cualquiera que esté usando ese usuario en otro lado — confirmar antes con esa persona
savia_logout Cierra la sesión en el servidor (libera el cupo de sesiones de la empresa), no solo el navegador local
savia_cerrar_navegador Hace logout real y además apaga Chromium, liberando los recursos de Playwright
savia_estado Sesión activa + URL actual
savia_captura Screenshot de la pantalla actual (se ve inline en el chat)
savia_texto_pagina Texto visible de la pantalla (o de un selector)
savia_elementos_clicables Lista elementos clickeables visibles con su texto (SAVIA no usa <a>/<button>: detecta por cursor:pointer, la única señal confiable en ZK)
savia_click Click por texto visible o por selector CSS
savia_escribir Escribe en un campo (por placeholder o selector)
savia_presionar_enter Enter en un campo — muchas acciones de ZK usan onOK (Enter) en vez de botón
savia_leer_modal Chequea si hay un popup/alerta de SAVIA visible y devuelve su texto
savia_extraer_tabla Extrae la primera grilla/listado ZK visible como filas/columnas
savia_navegar Navega a una ruta relativa dentro de /savia/ (ej. index.zul)

Flujo de uso típico

  1. savia_login
  2. savia_captura para ver dónde quedó la sesión tras el login
  3. savia_elementos_clicables para ver qué se puede tocar en el menú
  4. savia_click con el texto del menú deseado, después savia_captura de nuevo para confirmar
  5. savia_extraer_tabla o savia_texto_pagina para sacar los datos de esa pantalla

Con ese ciclo (captura → clicables → click → captura) se puede mapear cualquier sección de SAVIA sin haber tenido acceso previo, y una vez que se identifica una pantalla puntual que se use seguido (ej. reservas del día), se le puede agregar una función dedicada a extractors.py.

Notas

  • La sesión de SAVIA expira tras 60 minutos de inactividad (mensaje propio de la app). Si un tool falla con error de sesión, volvé a llamar savia_login.
  • SAVIA limita cuántas sesiones simultáneas puede tener la empresa a la vez (confirmado en vivo: 8). Cerrar el navegador sin hacer logout deja la sesión "colgada" del lado del servidor y come ese cupo — por eso savia_logout/savia_cerrar_navegador ahora clickean el botón real de salir en vez de solo cerrar la pestaña. Si igual se llega al límite, savia_cerrar_sesiones_duplicadas lo resuelve (pide confirmación primero porque puede desloguear a alguien más).
  • Las credenciales nunca se hardcodean: viven solo en .env (git-ignored).
  • El navegador persiste entre llamadas a tools dentro del mismo proceso del servidor MCP — no se relanza en cada tool call.
  • No hay API REST/JSON alternativa (confirmado inspeccionando el tráfico de red real): todo pasa por el protocolo interno de ZK. Playwright es la única vía razonable para automatizar SAVIA.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured