Skip to main content
Glama
skoniog

hydra-ops-mcp

by skoniog

hydra-ops-mcp

Opera una cabeza Hydra hablándole. Un servidor MCP que expone una cabeza en ejecución (ciclo de vida, libro mayor, monederos L1, registros de nodos y códigos de error en cadena) como herramientas que un cliente LLM puede invocar, para que puedas manejar y depurar una cabeza en lenguaje natural en vez de saltar entre una TUI, curl, cardano-cli y docker logs.

Cubre toda la superficie operativa: init, depósitos, transacciones dentro de la cabeza, decommit, close, fanout, fanout parcial y recuperación de depósitos, además de vistas de solo lectura del estado de la cabeza y de la L1. Cada operación que cambia el estado describe lo que haría y espera tu confirmación explícita antes de ejecutarse.


Contenido


Por qué

Operar una cabeza implica manejar varias herramientas a la vez. La TUI te muestra el estado de la cabeza pero no por qué se rechazó una transacción. La API WebSocket te da eventos pero tienes que parsear JSON a mano. Cuando algo sale mal, la respuesta suele estar en docker compose logs, correlacionada con el estado de la cabeza y decodificada contra códigos de error que viven en el código fuente de Plutus.

Este servidor pone todo eso detrás de una única interfaz conversacional:

"La cabeza no hace fanout. ¿Qué está mal?"

Claude puede verificar el estado de la cabeza, extraer la transacción fallida de los registros del nodo, decodificar el código de aborto H39 a FanoutUTxOHashMismatch y decirte las dos cosas que realmente lo causan — en un solo turno, porque tiene la API de la cabeza, los registros del contenedor y las tablas de errores al alcance.

También es útil para las partes rutinarias: abrir y financiar una cabeza, mover fondos y liquidar, con cada paso explicado y confirmado antes de ejecutarse. Y a diferencia de una sesión TUI vinculada a un solo nodo, cada herramienta acepta un argumento node, por lo que puedes comparar lo que alice, bob y carol creen sobre la misma cabeza.

Actualmente apunta a la demo devnet de hydra (tres nodos, tres partes). La capa de API no es específica de devnet; los ayudantes de L1 y el manejo de claves sí lo son (ver Limitaciones).


Inicio rápido

Requisitos previos — Docker, Python 3.10+ y un clon de cardano-scaling/hydra (para la demo devnet y las tablas de errores de Plutus).

git clone https://github.com/skoniog/hydra-ops-mcp && cd hydra-ops-mcp
python3 -m venv .venv                      # or: uv venv .venv
.venv/bin/pip install -r requirements.txt

./reset_devnet.sh                          # cardano-node + 3 hydra-nodes, seeded

Registra el servidor con tu cliente MCP. Claude Code:

claude mcp add hydra-ops -- /absolute/path/to/hydra-ops-mcp/.venv/bin/python \
    /absolute/path/to/hydra-ops-mcp/server.py

Claude Desktop — añade a claude_desktop_config.json:

{
  "mcpServers": {
    "hydra-ops": {
      "command": "/absolute/path/to/hydra-ops-mcp/.venv/bin/python",
      "args": ["/absolute/path/to/hydra-ops-mcp/server.py"]
    }
  }
}

Los lanzadores MCP inician el servidor con un entorno reducido, así que pasa cualquier anulación (HYDRA_DEMO_DIR, HYDRA_REPO) en un bloque "env" en lugar de exportarlas en tu shell.

Luego pregunta:

"¿En qué estado está la cabeza y qué tiene alice en L1?" "Abre una cabeza y compromete los fondos de alice." "Envía 5 ADA de alice a bob, luego muéstrame el conjunto UTXO de la cabeza."

¿Nuevo en operar una cabeza de esta manera? RUNBOOK.md recorre todo el ciclo de vida — abrir, financiar, transaccionar, decommit, cerrar, liquidar y romperlo a propósito — como una serie de sesiones guiadas.


Arquitectura

  MCP client (Claude Code / Claude Desktop / anything speaking MCP)
        │  stdio
        ▼
  server.py                 FastMCP registration; thin wrappers only
        │
  tools/                    one module per domain, plain functions
   ├── observe.py           head state, UTXOs, L1 funds, params, events
   ├── lifecycle.py         init, commit, decommit, close, fanout, recover
   ├── transact.py          in-head transfers
   ├── diagnose.py          node logs, error-code decoding
   └── types.py             ok() / err() / needs_confirmation()
        │
        ├──▶ hydra_client.py    WebSocket + HTTP to hydra-node
        │                       async core, sync facade, event buffer
        ├──▶ tx_builder.py      PyCardano: build + sign in-head txs
        ├──▶ cardano.py         cardano-cli in the node container (L1)
        └──▶ errors.py          parses hydra-plutus for abort codes

hydra_client.py mantiene una conexión WebSocket por nodo, ejecutando un bucle de eventos asíncrono en un hilo demonio detrás de una fachada síncrona — así las funciones herramienta siguen siendo simples mientras esperan eventos del protocolo. Almacena en búfer cada salida del servidor para recent_events, rastrea el estado de la cabeza y correlaciona transacciones confirmadas. Los comandos esperan su evento de resultado específico (DecommitDecommitFinalized, FanoutHeadIsFinalized) en lugar de devolver optimistamente, por lo que una llamada a herramienta que tiene éxito significa que el paso del protocolo realmente se completó.

tx_builder.py construye y firma transacciones con PyCardano — sin ida y vuelta a cardano-cli por transacción. cardano.py maneja el lado L1 (derivación de direcciones, consultas UTXO, firma y envío de transacciones de depósito) ejecutando cardano-cli dentro del contenedor cardano-node en ejecución, que es también donde residen las claves.

errors.py analiza HeadError.hs, DepositError.hs, HeadTokensError.hs y otros archivos de tu clon local de hydra en el momento de la llamada, por lo que los códigos decodificados siempre coinciden con la versión que estás ejecutando, en lugar de una tabla que se desactualiza.


El modelo de confirmación

Toda herramienta que cambia el estado acepta confirm: bool = False. Si se llama sin él, la herramienta valida todo lo que puede, resuelve lo que realmente haría y devuelve una descripción — sin haber cambiado nada:

{
  "status": "requires_confirmation",
  "action": "deposit alice's UTXO 4a3f…#0 (100,000,000,000 lovelace) into the head via node 1",
  "message": "This would deposit… Nothing has been done. Retry with confirm=True to execute.",
  "party": "alice", "utxo_ref": "4a3f…#0", "lovelace": 100000000000
}

En la práctica, esto significa que Claude propone, tú apruebas, y solo entonces ocurre algo en la cadena. Es más importante para las operaciones que son unilaterales e irreversibles: close_head afecta a todos los participantes de la cabeza, y fanout liquida el estado final de la cabeza.

La vista previa está resuelta, no es hipotética — commit_funds nombra el UTXO exacto que seleccionó, decommit nombra el propietario y la cantidad que derivó del conjunto UTXO de la cabeza, send_tx informa el id de transacción que construyó. La validación se ejecuta antes de la puerta, por lo que nunca se te pide confirmar algo que de todos modos habría fallado. Las herramientas de solo lectura no tienen puerta y se ejecutan inmediatamente.


Referencia de herramientas

Todas las herramientas devuelven {status, error, ...}; los fallos son {"status": "error", "error": "<mensaje>", ...} en lugar de excepciones. Cada herramienta acepta node: int = 1 (1 = alice, 2 = bob, 3 = carol) excepto l1_funds y explain_error.

Observabilidad (solo lectura)

Herramienta

Firma

Devuelve

head_status

(node=1)

Etiqueta de cabeza, estado observado por WS, número de UTXOs, total de lovelaces, número de instantánea, versión de cabeza, plazo de impugnación

head_utxos

(node=1)

El conjunto UTxO de la cabeza agrupado por dirección, cada uno con referencia y valor

l1_funds

(party="alice")

Dirección L1 de una parte, número de UTXOs, total de lovelaces y valores por UTXO

protocol_parameters

(node=1)

Parámetros del libro mayor de la cabeza — conjunto completo más un resumen de los que suelen causar problemas (tarifas, min-UTXO, tamaños)

pending_deposits

(node=1)

Depósitos observados pero aún no absorbidos — los candidatos a recuperación

recent_events

(node=1, tag=None, limit=25)

Salidas del servidor vistas en esta conexión, opcionalmente filtradas por etiqueta

recent_events cubre eventos desde que el servidor se conectó — la conexión WS no solicita historial, por lo que es una cola en vivo más que un registro completo. Para cualquier cosa más antigua, usa node_logs.

Ciclo de vida (con confirmación)

Herramienta

Firma

Notas

init_head

(node=1, confirm=False)

Rechaza a menos que la cabeza esté en Idle. En 2.3.0 la cabeza se abre inmediatamente y vacía; los fondos siguen mediante depósitos

commit_funds

(party="alice", node=1, utxo_ref="", confirm=False)

Redacta el depósito mediante POST /commit, firma con la clave de fondos de la parte, lo envía a L1, luego espera la absorción. Deposita un UTXO — el más grande a menos que utxo_ref nombre otro

decommit

(utxo_ref, node=1, confirm=False)

Retira un UTXO de la cabeza a L1 con la cabeza aún abierta. Deriva el propietario de la dirección del UTXO y construye una autotransferencia por el valor completo como la transacción de decommit

close_head

(node=1, confirm=False)

Publica la última instantánea confirmada e inicia el período de impugnación. Afecta a todos los participantes

fanout

(node=1, confirm=False)

Espera a ReadyToFanout si es necesario, luego distribuye todo el conjunto UTxO a L1

partial_fanout

(utxo_refs, node=1, confirm=False)

Liquida un subconjunto elegido; informa qué se distribuyó y qué queda. Ver Limitaciones — necesita un nodo más reciente que 2.3.0

recover_deposit

(tx_id, node=1, confirm=False)

DELETE /commits/{txid} — devuelve un depósito atascado a L1

commit_funds deliberadamente deposita un solo UTXO por llamada: los depósitos multi-UTXO son lo que atasca el fanout con H39 en 2.3.0 (ver Notas operativas).

Transacciones (con confirmación)

Herramienta

Firma

Notas

send_tx

(sender, receiver, amount_lovelace, node=1, confirm=False)

Transferencia dentro de la cabeza. sender es una parte cuya clave de firma está disponible; receiver es un nombre de parte o una dirección bech32

Se rechazan cantidades inferiores a 1 ADA. La cabeza pone a cero el min-UTXO, por lo que tal salida es válida en L2 pero luego imposible de recrear en L1 — atascaría el fanout permanentemente. La transacción se reconstruye contra el conjunto UTxO actual en el momento de la confirmación, por lo que una vista previa que se quedó no gasta entradas obsoletas. La llamada retorna una vez que la transacción aparece en una instantánea confirmada, no meramente cuando es aceptada.

Diagnóstico (solo lectura)

Herramienta

Firma

Notas

node_logs

(node=1, pattern="", since="10m", limit=40)

Registros del contenedor, opcionalmente filtrados por expresión regular. Devuelve cuántas líneas coincidieron y las últimas limit de ellas

explain_error

(code)

Decodifica un código de aborto (H39, D01, …) a su constructor y módulo desde tu clon local de hydra, con notas prácticas sobre los que realmente aparecen


Comparación con hydra-tui

La superficie de herramientas coincide deliberadamente con lo que expone hydra-tui, por lo que cualquier cosa que puedas hacer en la TUI la puedes hacer aquí:

hydra-tui

aquí

i — init

init_head

diálogo de commit

commit_funds (borradores, firma, envía, espera absorción)

n — nueva transacción

send_tx

d — decommit

decommit

c — cerrar

close_head

f — fanout

fanout

p — fanout parcial

partial_fanout

r — recuperar depósito

recover_deposit

pestaña principal

head_status, head_utxos

pestaña de fondos

l1_funds

pestaña de historial

recent_events

protocol_parameters, pending_deposits

Al igual que el TUI, esto no expone Contest, SafeClose o SideLoadSnapshot. Esas son respuestas del protocolo a condiciones específicas en la cadena donde una acción es correcta y el tiempo es crítico; pertenecen a herramientas deterministas con alertas, no detrás de un aviso.

Donde esto va más allá:

  • Diagnóstico. node_logs y explain_error no tienen equivalente en el TUI. Esta es la ganancia práctica más grande — un cabezal atascado pasa de "el TUI dice que falló" a un código de aborto descifrado y las líneas de registro correspondientes.

  • Entre nodos. Una sesión del TUI se conecta a un solo nodo. Aquí cada herramienta toma node, para que puedas preguntar qué cree Alice, Bob y Carol sobre el mismo cabezal — la forma más rápida de detectar un nodo que se ha quedado atrás.

  • L1 y L2 juntos. l1_funds consulta la cadena directamente, por lo que "¿ese decommit realmente llegó?" es una sola pregunta en lugar de un cambio de contexto a cardano-cli.

  • Barandillas. Las salidas por debajo del mínimo UTXO y los depósitos multi-UTXO son rechazados por construcción, porque ambos atascan silenciosamente el fanout más tarde.

  • Composición. Las operaciones de varios pasos ocurren en una sola solicitud: "cierra el cabezal, espera a que pase la impugnación, haz fanout y muéstrame los saldos L1 finales de todos" es una sola petición.

Donde el TUI sigue ganando: es un panel en vivo. MCP es solicitud/respuesta, por lo que obtienes instantáneas en lugar de una vista que se actualiza continuamente — para observar un cabezal a lo largo del tiempo, mantén abierto el TUI. Las pulsaciones de teclas también superan un viaje de ida y vuelta del modelo para trabajo repetitivo, y los selectores de UTxO del TUI son visuales, mientras que aquí listas y luego seleccionas.


Configuración

Todo está en config.py, con anulaciones de entorno:

Configuración

Valor por defecto

Significado

NODES

4001, 4002, 4003 en localhost

Índice de nodo → puntos finales WS/HTTP y nombre de parte

HYDRA_DEMO_DIR

/home/dev/claudecode/hydra/demo

Devnet de demostración: proyecto docker compose y credenciales

HYDRA_REPO

/home/dev/claudecode/hydra

Repositorio de Hydra, para descifrar códigos de aborto

NETWORK_MAGIC

42

Magia de la devnet

MIN_OUTPUT_LOVELACE

1_000_000

Umbral de rechazo para salidas en el cabezal

Las claves de firma son los pares {alice,bob,carol}-funds de la demostración. Las rutas del lado del contenedor se usan para cardano-cli (firma y envío en L1); copias en el lado del host de las mismas claves son leídas por PyCardano para transacciones dentro del cabezal. Apuntar a una implementación diferente con el mismo diseño es un cambio de configuración; apuntar a una topología diferente no lo es (consulte Limitaciones).


Pruebas

.venv/bin/python test_ops.py           # offline — no devnet needed
.venv/bin/python test_ops_devnet.py    # live — needs a devnet with the head Idle

test_ops.py asegura que cada herramienta que cambia de estado devuelve requires_confirmation y no llega a ningún cliente sin confirm=True (el cliente ficticio lanza una excepción si un comando sale de la puerta), que las cargas útiles de las solicitudes coinciden con la API, que se activan el rechazo mínimo de UTXO y la validación de UTxO, que la tabla de errores se analiza y descifra, y que las 16 herramientas se registran con el servidor.

test_ops_devnet.py maneja un cabezal real a través de todo el ciclo de vida y asegura la observabilidad en cada etapa: verificación de puerta → initcommit → seis herramientas de lectura → dos pagos en el cabezal → decommit, verificado por los fondos que aparecen en L1 mientras el cabezal permanece abiertoclosefanout → de vuelta a Idle → registros y descifrado de errores. Se salta con un mensaje claro si la devnet no está activa o el cabezal no está en Idle.


Notas operativas

Cosas que vale la pena saber antes de que te cuesten un cabezal.

H39 / FanoutUTxOHashMismatch atasca un cabezal permanentemente. El fanout no puede reproducir lo que el cabezal cerrado se comprometió a hacer, por lo que el cabezal no puede liquidarse y sus fondos quedan atrapados. Dos causas, ambas prevenibles y ambas protegidas aquí: depósitos multi-UTXO en 2.3.0, y cualquier salida del cabezal por debajo del mínimo UTXO de L1. Pregunta explain_error("H39") para los detalles.

El cabezal pone a cero el mínimo UTXO; L1 no lo hace. Una salida de 0.5 ADA se transacciona felizmente en L2 y luego no se puede recrear en L1. send_tx rechaza por debajo de 1 ADA por esta razón.

Los depósitos se absorben después de un período de depósito, no al instante. commit_funds espera e informa si la absorción no ocurre; un depósito que nunca llega aparece en pending_deposits y regresa con recover_deposit.

El cierre es unilateral y afecta a todos. Cualquier participante puede cerrar, y todo el cabezal debe entonces liquidarse. La puerta existe principalmente para esto.

Un cabezal necesita que todos los participantes estén en línea. Si un pago se cuelga, verifica docker compose ps antes de sospechar de las herramientas.

El productor de bloques de la devnet de demostración puede atascarse después de largos períodos de inactividad — cardano-cli query tip devuelve el mismo slot dos veces y todo se cuelga. ./reset_devnet.sh lo arregla; la devnet es desechable por diseño.

La entrada WebSocket no analizable no devuelve tag. Un comando que un nodo no reconoce regresa como un objeto simple {"input", "reason"} en lugar de un evento etiquetado — vale la pena saberlo si escribes scripts directamente contra la API, ya que un cliente que espera eventos etiquetados se colgará. El cliente aquí lo maneja.


Limitaciones

partial_fanout necesita un nodo más nuevo que 2.3.0. El comando es posterior a la versión (hydra PR #2750, commit a271cced2), y la imagen de demostración fijada lo rechaza — el nodo lista los comandos que conoce y PartialFanout no está entre ellos. La herramienta detecta esto con precisión e informa la brecha de versión. La ruta de código está lista para un nodo construido desde master pero solo se ha ejercitado hasta ese rechazo.

Las tarifas son cero. tx_builder.py codifica fee=0, lo cual es correcto para los parámetros de protocolo de la demostración y está mal en cualquier otro lugar. Se necesita estimación de tarifas real y selección de monedas antes de que esto apunte a preview/preprod o mainnet.

Suposiciones con forma de devnet. Tres partes con nombres de clave conocidos, claves legibles dentro del contenedor cardano-node, docker compose disponible para consultas y registros de L1. La capa de API del cabezal es general; los ayudantes de L1 no lo son.

Solo ADA. La construcción de transacciones maneja UTXOs de solo lovelace — sin tokens nativos, scripts, datums o acuñación.

recover_deposit no está probado contra un depósito realmente atascado. Sigue la API, pero la devnet de demostración absorbe depósitos demasiado confiablemente como para producir uno bajo demanda.

Sin autenticación. Cualquiera que pueda alcanzar el servidor puede operar el cabezal. Eso es apropiado para una herramienta de operador local y no lo sería para cualquier cosa expuesta.


Extensión

Agregar una herramienta: escribe una función simple en el módulo tools/ relevante que devuelva ok() / err() / needs_confirmation(), luego registra un envoltorio delgado en server.py. Los módulos de herramientas no importan FastMCP, por lo que son llamables directamente desde las pruebas — que es como ambas suites los manejan.

Agregar un comando de protocolo: agrega un método a HydraClient usando _command_and_wait(command, ok_tags), que envía y espera el evento de resultado mientras trata tanto CommandFailed como los rechazos de análisis no etiquetados como errores.

Apuntar a otra implementación: apunta NODES a los puntos finales y HYDRA_DEMO_DIR / HYDRA_REPO a las rutas correctas. Cualquier cosa más allá del diseño de tres partes de la demostración significa revisar el manejo de claves en cardano.py y tx_builder.py, y las tarifas.

Lectura adicional

La documentación de Hydra para el protocolo en sí, y RUNBOOK.md para la visita guiada de la operación de un cabezal con estas herramientas.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

  • Hosted MCP server for live Bittensor chain reads and self-custodial on-chain writes.

  • MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/skoniog/hydra-ops-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server