Skip to main content
Glama
martinmangos

ZelioSoft2 MCP

by martinmangos

ZelioSoft2 MCP

MCP servers that let an LLM agent build and test Schneider Electric ZelioSoft2 V5.4.3 relay-ladder-logic programs (.zm2 files) — without ZelioSoft2 exposing any official API or scripting interface of its own.

🇬🇧 English · 🇪🇸 Español


English

What's in here

Three independent MCP servers, each usable on its own:

Server

File

What it does

zelio-ladder-builder

server.py

Generates a valid .zm2 ladder program directly from a JSON spec — no GUI, no automation, just the file format written correctly.

zelio-desktop-control

desktop_server.py

Drives the real, visible ZelioSoft2 window: open a file, run its simulation, toggle inputs, read outputs, screenshot.

zelio-hidden-desktop

hidden_desktop_server.py

Same capabilities as above, but the automated ZelioSoft2 instance runs on an isolated Windows desktop — your mouse, keyboard, and screen are never touched.

Why this exists

ZelioSoft2 has no scripting API, no CLI, no file format documentation. Everything here came from reverse-engineering the app (Win32/MFC binary analysis) and the .zm2 container format, then building three different ways to act on that knowledge:

  1. Write the file directly (fastest, most precise — no UI involved at all).

  2. Drive the real GUI (needed to actually run a program and verify its logic, not just its syntax).

  3. Drive the GUI in isolation (so an agent can debug a program while you keep using your own PC).

How it works (short version)

  • zm2codec.py — the outer container: LZMA compression + a keyed BLAKE2b MAC + a 14-byte XOR mask. Fully reversed and round-trip verified against real ZelioSoft2 sample files.

  • zm2builder.py — the inner ladder format: a fixed table of "P-pins" encodes every contact/coil in the grid as a 16-bit opcode (element type, address, NA/NC flag). Validates addresses against the target hardware module's real I/O capacity, and can auto-pick the smallest module that fits a given spec.

  • templates/ — one .zm2 per supported hardware module (I/O count varies by model); zm2builder reads each module's real symbol table dynamically, no hardcoded per-model offsets.

  • zelio_driver.py — classic GUI automation (pyautogui + pywinauto) for the visible window.

  • hidden_desktop.py — the isolated version: a real Win32 CreateDesktop, with input injected via PostMessage/WM_COMMAND directly to window handles (SendInput does not work on a non-visible desktop — confirmed empirically) and screenshots captured via PrintWindow (a desktop-wide BitBlt also silently fails on a hidden desktop).

Full reverse-engineering log, including every dead end: HANDOFF.md.

Install

pip install -r requirements.txt

Windows only (ZelioSoft2 itself is Windows-only). Requires ZelioSoft2 V5.4.3 installed for the two desktop-control servers; server.py alone needs nothing but the templates included here.

Wire it into an MCP client

Add to your client's MCP config (Claude Code's .mcp.json, Antigravity's mcp_config.json, etc.):

{
  "mcpServers": {
    "zelio-ladder-builder": {
      "command": "python",
      "args": ["<path>/zelio_mcp/server.py"]
    },
    "zelio-desktop-control": {
      "command": "python",
      "args": ["<path>/zelio_mcp/desktop_server.py"]
    },
    "zelio-hidden-desktop": {
      "command": "python",
      "args": ["<path>/zelio_mcp/hidden_desktop_server.py"]
    }
  }
}

Tools

zelio-ladder-builder

  • describe_addressing() — the row/contact/coil spec DSL reference (call this first).

  • list_hardware_modules() — every template's I/O capacity.

  • validate_program(rows, ...) — dry-run a spec, get errors/warnings without writing a file.

  • build_ladder_program(rows, output_path, ...) — compile and save a .zm2 file.

zelio-desktop-control (visible window)

  • zelio_launch_and_open, zelio_open_file, zelio_is_running

  • zelio_enter_simulation, zelio_press_run, zelio_stop_simulation, zelio_exit_simulation

  • zelio_read_io, zelio_set_input

  • zelio_screenshot, zelio_force_repaint (the simulation panels cache stale frames — a real ZelioSoft2 bug, not this tool's)

zelio-hidden-desktop (isolated window — same shape, _hidden naming)

  • zelio_hidden_open, zelio_hidden_enter_simulation, zelio_hidden_press_run, zelio_hidden_stop_simulation, zelio_hidden_exit_simulation

  • zelio_hidden_read_io, zelio_hidden_set_input, zelio_hidden_screenshot, zelio_hidden_close

⚠️ About the hidden-desktop technique, honestly

hidden_desktop.py uses Win32's CreateDesktop API to give a launched process its own input queue and render surface, invisible to the interactive desktop. This is the exact same low-level mechanism "Hidden VNC" (HVNC) malware uses for covert remote control — worth knowing if you're reading or extending this code, since the shape (create desktop → inject input → hide a process) is identical either way.

The use here is the opposite of covert: it automates your own licensed copy of ZelioSoft2, at your own explicit direction, so an agent can debug a program without hijacking the mouse/keyboard you're actively using. Nothing is hidden from you — the whole point is that you can keep working while it runs. If you fork this for something else, make sure that framing still holds.

Known limitations

  • branch_of (parallel-branch / seal-in wiring in zm2builder.py) is implemented but was never verified by opening a branch-using file in the real app.

  • I/O comments (ZelioSoft2's per-symbol "Comentario" field) aren't reachable through the P-pin table at all — they live in a still-unsolved, ID-renumbers-every-save part of the format.

  • hidden_desktop_server.py's MCP tool wrappers weren't exercised through an actual MCP client — the underlying HiddenDesktopSession methods they call were verified directly.

Credits

  • martinmangos — project owner, direction, and every hands-on test against the real app.

  • Claude (Anthropic) — reverse engineering (IDA Pro decompilation, live binary tracing) and implementation, across several sessions.

  • Antigravity CLI (Google) — built parts of the ladder-generation logic and exercised the MCP tools independently.

A lot of the reverse engineering (the .zm2 container format, the P-pin ladder-matrix encoding, the Win32 internals behind the desktop-control layer) came from decompiling Zelio2.exe in IDA Pro. The full session-by-session log, including every dead end, is in HANDOFF.md.


Related MCP server: Windows-MCP

Español

Qué hay acá

Tres servidores MCP independientes, cada uno usable por separado:

Servidor

Archivo

Qué hace

zelio-ladder-builder

server.py

Genera un programa ladder .zm2 válido directo desde un spec JSON — sin GUI, sin automatización, solo el formato de archivo escrito correctamente.

zelio-desktop-control

desktop_server.py

Controla la ventana visible real de ZelioSoft2: abrir archivo, correr simulación, togglear entradas, leer salidas, sacar captura.

zelio-hidden-desktop

hidden_desktop_server.py

Mismas capacidades, pero la instancia automatizada corre en un desktop de Windows aislado — tu mouse, teclado y pantalla nunca se tocan.

Por qué existe esto

ZelioSoft2 no tiene API de scripting, ni CLI, ni el formato de archivo documentado. Todo esto salió de hacer ingeniería inversa de la app (análisis del binario Win32/MFC) y del contenedor .zm2, y después construir tres formas distintas de actuar con ese conocimiento:

  1. Escribir el archivo directo (lo más rápido y preciso — sin GUI de por medio).

  2. Controlar la GUI real (necesario para de verdad correr un programa y verificar la lógica, no solo que compile).

  3. Controlar la GUI de forma aislada (para que una IA pueda debuggear un programa mientras vos seguís usando tu PC).

Cómo funciona (versión corta)

  • zm2codec.py — el contenedor externo: compresión LZMA + MAC BLAKE2b con clave + una máscara XOR de 14 bytes. Reverseado completo y verificado con archivos de ejemplo reales de ZelioSoft2.

  • zm2builder.py — el formato interno del ladder: una tabla fija de "P-pins" codifica cada contacto/bobina de la grilla como un opcode de 16 bits (tipo de elemento, dirección, flag NA/NC). Valida direcciones contra la capacidad de E/S real del módulo de hardware elegido, y puede elegir automáticamente el módulo más chico que cumpla un spec dado.

  • templates/ — un .zm2 por cada módulo de hardware soportado (la cantidad de E/S varía según el modelo); zm2builder lee la tabla de símbolos real de cada módulo de forma dinámica, sin offsets hardcodeados por modelo.

  • zelio_driver.py — automatización de GUI clásica (pyautogui + pywinauto) para la ventana visible.

  • hidden_desktop.py — la versión aislada: un CreateDesktop real de Win32, con input inyectado vía PostMessage/WM_COMMAND directo a los handles de ventana (SendInput no funciona en un desktop no visible — confirmado empíricamente) y capturas de pantalla vía PrintWindow (un BitBlt de todo el desktop también falla en silencio en un desktop oculto).

Historial completo de la ingeniería inversa, con cada callejón sin salida incluido: HANDOFF.md.

Instalación

pip install -r requirements.txt

Solo Windows (ZelioSoft2 en sí es solo Windows). Los dos servers de control de escritorio necesitan ZelioSoft2 V5.4.3 instalado; server.py solo no necesita nada más que los templates incluidos acá.

Conectarlo a un cliente MCP

Agregalo a la config MCP de tu cliente (.mcp.json de Claude Code, mcp_config.json de Antigravity, etc.):

{
  "mcpServers": {
    "zelio-ladder-builder": {
      "command": "python",
      "args": ["<ruta>/zelio_mcp/server.py"]
    },
    "zelio-desktop-control": {
      "command": "python",
      "args": ["<ruta>/zelio_mcp/desktop_server.py"]
    },
    "zelio-hidden-desktop": {
      "command": "python",
      "args": ["<ruta>/zelio_mcp/hidden_desktop_server.py"]
    }
  }
}

Tools

zelio-ladder-builder

  • describe_addressing() — referencia del DSL de filas/contactos/bobinas (llamar esto primero).

  • list_hardware_modules() — capacidad de E/S de cada template.

  • validate_program(rows, ...) — prueba en seco de un spec, errores/warnings sin escribir archivo.

  • build_ladder_program(rows, output_path, ...) — compila y guarda un .zm2.

zelio-desktop-control (ventana visible)

  • zelio_launch_and_open, zelio_open_file, zelio_is_running

  • zelio_enter_simulation, zelio_press_run, zelio_stop_simulation, zelio_exit_simulation

  • zelio_read_io, zelio_set_input

  • zelio_screenshot, zelio_force_repaint (los paneles de simulación cachean frames viejos — bug real de ZelioSoft2, no de esta herramienta)

zelio-hidden-desktop (ventana aislada — mismas tools, con prefijo _hidden)

  • zelio_hidden_open, zelio_hidden_enter_simulation, zelio_hidden_press_run, zelio_hidden_stop_simulation, zelio_hidden_exit_simulation

  • zelio_hidden_read_io, zelio_hidden_set_input, zelio_hidden_screenshot, zelio_hidden_close

⚠️ Sobre la técnica de hidden-desktop, con honestidad

hidden_desktop.py usa la API CreateDesktop de Win32 para darle a un proceso lanzado su propia cola de input y superficie de render, invisible para el desktop interactivo. Es exactamente el mismo mecanismo de bajo nivel que usa el malware "Hidden VNC" (HVNC) para control remoto encubierto — vale la pena saberlo si leés o extendés este código, porque la forma (crear desktop → inyectar input → ocultar un proceso) es idéntica en ambos casos.

El uso acá es lo opuesto a encubierto: automatiza tu propia copia licenciada de ZelioSoft2, bajo tu propia dirección explícita, para que una IA pueda debuggear un programa sin secuestrarte el mouse/teclado que estás usando activamente. No se te oculta nada — la gracia es justamente que puedas seguir trabajando mientras corre. Si forkeás esto para otra cosa, asegurate de que ese encuadre se mantenga.

Limitaciones conocidas

  • branch_of (ramas paralelas / sello propio en zm2builder.py) está implementado pero nunca se verificó abriendo un archivo con ramas en la app real.

  • Los comentarios de E/S (el campo "Comentario" por símbolo de ZelioSoft2) no son alcanzables desde la tabla de P-pins — viven en una parte del formato aún no resuelta, que renumera IDs en cada guardado.

  • Los wrappers de tools MCP de hidden_desktop_server.py no se probaron a través de un cliente MCP real — sí se verificaron directamente los métodos de HiddenDesktopSession que usan por debajo.

Créditos

  • martinmangos — dueño del proyecto, dirección, y todas las pruebas a mano contra la app real.

  • Claude (Anthropic) — ingeniería inversa (decompilación con IDA Pro, tracing en vivo del binario) e implementación, a lo largo de varias sesiones.

  • Antigravity CLI (Google) — construyó parte de la lógica de generación del ladder y probó las tools MCP de forma independiente.

Buena parte de la ingeniería inversa (el formato de contenedor .zm2, la codificación de la matriz ladder de P-pins, los detalles de Win32 detrás de la capa de control de escritorio) salió de decompilar Zelio2.exe en IDA Pro. El log sesión por sesión completo, con cada callejón sin salida incluido, está en HANDOFF.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to interact with Windows operating systems through native UI automation, file navigation, application control, and system commands. Provides seamless integration between LLMs and Windows environments for tasks like clicking, typing, launching apps, and capturing desktop state.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to interact with Windows operating systems by providing tools for UI automation, file navigation, application control, and system operations. Works with any LLM to perform tasks like clicking, typing, launching applications, and executing PowerShell commands through native Windows integration.
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI agents to discover, inspect, edit, rebuild, and save Schneider Electric RemoteConnect and SCADAPack x70 IEC logic projects, including program sections, hardware, variables, and Modbus configuration.
    63
    MIT