runpod-mcp
runpod-mcp — servidor MCP personalizado para la replicación Learning-to-Swim
Nota independiente: este servidor fue extraído (con su historial completo) del proyecto
learning-to-swim-replication. Los enlaces relativos como../runbook/RUNBOOK.mdremiten a ese proyecto padre y solo se resuelven cuando este repositorio está dentro de él (o mediante un symlink); el servidor en sí se ejecuta de forma independiente.
Herramientas con forma de tarea (14) que reflejan el runbook/RUNBOOK.md
del proyecto padre en lugar de ~50 espejos genéricos de API. Es un servidor
personalizado porque ninguna API de RunPod ejecuta comandos en un pod —
el MCP oficial solo cubre el plano de control; ejecutar pod_setup.sh,
el barrido de verificación de los ejes y el entrenamiento exige SSH + rsync,
codificado aquí con salvaguardas de coste en el código.
Arquitectura
.mcp.json → run.sh (venv bootstrap) → server.py (FastMCP, stdio; thin)
└── runpod_mcp/
config.py Keychain key fetch + rpa_ scrubber
api.py REST v1 (pods/volumes/billing) + unauth GraphQL gpuTypes
guardrails.py one-pod-per-vehicle (unknown refused) · 4090-only · no spot · volume required · confirm gate
ssh.py hardened ssh/scp/rsync; known_hosts_runpod; 60s conn cache
jobs.py detached jobs: /workspace/jobs/<id>/{cmd.sh,pid,out.log,exit_code,meta.json}
training.py DR tables (RUNBOOK/yaml-cross-checked) + verbatim train cmd
supervise.py Mac-side background CLI: launch→poll→pull→sync→spend→stop (reuses tools.*)
watch.py Mac-side ADVISORY observation CLI: discover job→tail out.log→parse metrics→page on plateau/failure/stall (read-only; never stops pods)
remote/ job_wrapper.sh · idle_watchdog.sh · apply_bluerov2_patch.py
deadman.py Mac-side stop-pod fuse: arm --vehicle → sleep → stop with retries (per-vehicle pid/summaries)
supervise.sh → caffeinate -i wrapper around python -m runpod_mcp.supervise
watch.sh → caffeinate -i wrapper around python -m runpod_mcp.watch (live-pod behavior UNVERIFIED — fixture/mock-verified only; see CLAUDE.md §D)
deadman.sh → caffeinate -i wrapper around python -m runpod_mcp.deadman (arm/cancel REQUIRE --vehicle; bare status reports all vehicles)Las arquitecturas clave:
Sin estado y por vehículo: «el pod» = lo que
GET /podsdevuelva que coincida con el nombre configurado del vehículo seleccionado (hippocampus→lts-replication,bluerov2→lts-replication-bluerov2; el parámetrovehiclede cada herramienta utiliza por defecto hippocampus;stop_pod/terminate_podlo exigen de forma explícita); consola y MCP siempre coinciden. Solo hay estado local: una caché de 60 segundos (host, port) por Runtime del vehículo.Trabajos asíncronos: una sola llamada SSH ejecuta
setsid bashjob_wrapper.sh <dir> <pod_id> <ceiling> <auto_stop>; el estado vive en el volumen de red, por lo que sobrevive a reinicios del MCP, a la suspensión del Mac y a paradas del pod.timeout --kill-afterimpone los topes de tiempo de reloj (exit 124); el sufijo de auto-stop se ejecuta DESPUÉS de que se escribaexit_code, así que un timeout nunca puede anularlo. El id del pod se inyecta como argv (las variables de entorno del contenedor no son fiables en shells BatchMode separados); se obtiene/etc/rp_environmentpara las credenciales de runpodctl; al armarauto_stopse sondea runpodctl de forma síncrona y si no funciona falla de forma ruidosa. La sonda (2026-08-09) es un diagnóstico de tres vías: las comprobaciones de shell puro no deciden nada (responden a H1-vs-H2 y captura el PATH puro), luego se hacesourcede/etc/rp_environmentde forma incondicional, y el par tras elsourcelleva el veredicto —NO_RUNPODCTL(binario ausente incluso después delsource, salida 90),NO_RUNPODCTL_AUTH_SOURCED(aún rechazado después delsource, salida 91),PROBE_OK(éxito solo tras elsource;NO_RUNPODCTL_AUTH_BAREes el diagnóstico intermedio que continúa).Watchdog de inactividad: se reinstala en cada transición a running — el borrado del disco del contenedor elimina el material instalado en runtime (el propio
idle_watchdog.sh, las librerías apt X11/GL,rsync), por eso se mantiene la instalación en cada transición;runpodctlviene EN LA IMAGEN y vuelve en cada arranque (un borrado restaura el disco desde la imagen, no lo vacía — corregido el 2026-08-09). Cada 5 min: sin pid de trabajo activosin sesión sshd +
/workspace/.keepalivecon más de 60 min de antigüedad →runpodctl stop pod.touch /workspace/.keepalivees la vía de escape de la sesión manual. Una instalación correcta informa dearmed (stop path unverified)— la sonda certifica lectura (get pod), el watchdog requiere escritura (stop pod); la primera confirmación real es una entrada de parada correcta en/workspace/.idle_watchdog.log. Estado (2026-08-09): la sonda de instalación ha fallado en cada puesta en marcha registrada (rc=91 opaco antes del arreglo) — el watchdog nunca se ha llegado a armar; el defecto 2 llega DIAGNOSTICADO, no CERRADO, y el centinela de la próxima puesta en marcha lo resuelve.idle_watchdog: FAILED⇒ arma el deadman del Mac antes de cualquier trabajo.
Las salvaguardas son código: un pod por vehículo declarado (se rechaza cualquier otro nombre de pod en la cuenta), RTX 4090 ×1, SECURE,
interruptibleforzado a false, volumen de red obligatorio,terminate_podexigevehicleexplícito más la cadena literalterminate <pod_name del vehículo>(p. ej.,terminate lts-replication), un trabajo a la vez por pod salvo conforce.
Instalación / registro
Registra el servidor en el .mcp.json de un proyecto (Claude Code) con una
ruta absoluta a run.sh — run.sh prepara su propio .venv en el primer
arranque:
{
"mcpServers": {
"runpod": {
"command": "bash",
"args": ["/path/to/runpod-mcp/run.sh"]
}
}
}Configuración
Clave de API (nunca en disco/git/argv — solo en el Llavero de macOS; el servidor la lee con
security find-generic-passwordy elimina los valoresrpa_de cualquier error y registro):security add-generic-password -a kyle -s runpod-api-key -w '<KEY>'(El nombre de cuenta de la consulta está actualmente fijo a
kyleenrunpod_mcp/config.py— ajústalos conjuntamente si tu cuenta de macOS difiere.)Clave SSH: debe existir
~/.ssh/id_ed25519(.pub); el.pubse inyecta en la creación del pod mediante la variable de entornoPUBLIC_KEY(lo que las imágenesrunpod/pytorchrealmente respetan — verificado en vivo;SSH_PUBLIC_KEYtambién se define como refuerzo extra). SSH directo aroot@publicIp:portMappings["22"]; el SSH proxy de RunPod no se usa (no scp). Las claves de host van a un~/.ssh/known_hosts_runpoddedicado, truncado en cada arranque del pod (la restauración del disco del contenedor regenera las claves de host; las entradas obsoletas solo causan falsos fallos de MITM).Nada más —
run.shcrea.venv/e instala requirements.txt en el primer arranque (condicionado por una marca).
Pruebas
runpod-mcp/.venv/bin/python -m pytest runpod-mcp/tests -q # offline (default)
RUNPOD_MCP_LIVE=1 runpod-mcp/.venv/bin/python -m pytest \
runpod-mcp/tests/test_live.py -q # live $0 read-onlyLas pruebas offline usan ttpx.MockTransport + un SSH falso con duck typing
— sin red, sin clave. Las pruebas en vivo son GETs de solo lectura + un
handshake de stdio de MCP a través de run.sh (verifican que se registran
las 14 herramientas). Las tablas de DR se comparan de forma cruzada
analizando BLUEROV2/config/bluerov2_heavy.yaml,
RUNBOOK.md y APPLY.md;
el script de parches se ejercita contra extractos fixture confirmados de las
fuentes fijadas en 7c5ebe7 (más una prueba condicionada por SHA contra el
clon de referencia real cuando está disponible — solo lectura, copias
temporales).
test_supervise.py conduce la CLI de supervise con fakes inyectados +
un reloj falso (sin esperas reales) y cubre todas las ramas de seguridad:
finalización normal, fallo del trabajo, parada forzada por --max-wait,
negativa de pod no en ejecución, negativa de lanzamiento, errores de sondeo
transitorios, fallo de captura que aun así detiene, --no-stop y se afirma
que terminate_pod nunca se llama en ningún caso.
El pytest -q del repositorio raíz ignora esta carpeta (conftest.py
collect_ignore) — el venv de la raíz, reducido al mínimo, no tiene
mcp/httpx.
Ejecuciones supervisadas (supervise.sh)
Un único comando que encadena una ejecución completa: comprobar que el pod
está en ejecución → derivar con dry-run un tope de tiempo de reloj finito
→ launch(auto_stop=false) → sondear job_status → traer de forma
incondicional /workspace/jobs/<job_id>/ + sync_logs + spend_report →
stop_pod → resumen JSON persistente — de modo que el agente lo lanza
una sola vez como tarea de fondo y recibe el aviso de finalización.
Reutiliza runpod_mcp.tools.* (sin duplicación de lógica, hereda todas las
salvaguardas) y nunca llama a terminate_pod. Esta es una CLI del Mac,
no una herramienta MCP número 15: una herramienta que sondee durante
minutos bloquearía el servidor stdio.
# training run (background task)
supervise.sh --training curee --dr DR_0 --seed 1 \
[--interval 45] [--max-wait N] [--backstop 300] [--no-stop] \
[--sync-subdir rsl_rl/warpauv_direct] [--summary-path PATH]
# generic job — --sync-subdir REQUIRED (pass 'none' to skip the analysis sync;
# the job-dir pull always happens); --vehicle routes the pod (default
# hippocampus; --training mode derives it from the training vehicle instead)
supervise.sh --job-name eval --command "…" --workdir /workspace \
--sync-subdir <dir|none> [--max-runtime-sec N] [--vehicle bluerov2]Seguridad del gasto: el bucle de sondeo tiene exactamente dos salidas: salida
normal → stop_pod; o --max-wait (siempre finito) agotado mientras el
estado sigue en running → parada forzada + código de salida no cero +
marcador force_stopped en el resumen. Una denegación del lanzamiento → no
se detiene (arregla y reintenta), salida 2. El resumen
supervise-<job_id>.json, que se escribe en el directorio de logs del
vehículo (logs/pod/ para hippocampus, logs/pod/bluerov2/ para bluerov2),
es el contrato de recuperación (una sesión posterior concilia el estado de
parada a partir de él). Advertencias de vitalidad: caffeinate -i protege
contra la suspensión por inactividad pero no contra el cierre de la tapa; la
supervivencia del run_in_background_ a través del reap de WarmLifecycle no
está verificada — el tope del timeout en el trabajo es el respaldo
garantizado; el watchdog de inactividad del pod lo secundaría, pero aún no se
ha armado en ninguna puesta en marcha registrada (DIAGNOSTICO, no CERRADO —
ver el punto anterior sobre el watchdog de inactividad), así que arma el
deadman del Mac cuando ensure_pod reporte idle_watchdog: FAILED.
Cadenas de campaña (CUREE/chains/)
Un script bash por campaña (denominado por el ID de campaña, p. ej.
chain-011-CUREE_Adaptive-weights.sh): toda la secuencia de trabajos del lado
del pod de la campaña — parches, gates, entrenamientos, evaluaciones, syncs —
como enlaces ordenados y fijados por SHA. Las cadenas se lanzan con
supervise.sh (que posee la captura-y-parada), nunca a mano; son el registro
duradero de lo que ejecutó exactamente una campaña.
Dry runs
ensure_pod, run_pod_setup, run_job, launch_training,
apply_bluerov_patches aceptan dry_run=true y devuelven las cargas
útiles/ediciones/comandos exactos sin modificar nada ($0). supervise
usa esa vía de dry run para derivar su --max-wait finito antes del
lanzamiento real.
Imagen de respaldo NGC (cambio manual — leer antes)
nvcr.io/nvidia/isaac-sim:4.5.0 (respaldo de Día 1 en el RUNBOOK) no trae
sshd — lo que rompe toda la historia SSH de este servidor. Cambiarla exige
un comando docker-start que instale/arranque sshd (no es un cambio de una
línea: avisar a Kyle antes de tocar image_name en pod_defaults.yaml.
Riesgos conocidos (aceptados en la planificación)
La URL de descarga de IsaacSim 4.5.0 en pod_setup.sh puede devolver 404 — sale a la luz en el rastro del log de
job_status; el arreglo es una edición del runbook, no un cambio del MCP.La disponibilidad de la 4090 fluctúa según el DC; el volumen de red fija un DC;
gpu_availability(data_center_id=...)y la receta de sarrecuperación sin GPU de ensure_pod lo cubren; en el peor caso, crea un segundo volumen en otro DC.
Licencia
MIT — consulta LICENSE.
This server cannot be installed
Maintenance
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
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Create and manage AI agents that collaborate and solve problems through natural language interacti…
Build, validate, and deploy multi-agent AI solutions from any AI environment.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/kyle-nelson-berkeley/runpod-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server