nano-mcp-termux

Servidor MCP de un solo archivo y sin dependencias para agentes de IA que se ejecutan nativamente en Termux (Android), Raspberry Pi y Linux: estado del dispositivo, salud del servidor y resolución de rutas de Android/Termux. Sin superficie de shell ni exec.

Documentación

nano-mcp-termux

Servidor MCP de un solo archivo y sin dependencias para agentes de IA, que se ejecuta de forma nativa en Termux (Android), Raspberry Pi y Linux.

GitHub Repository License: MIT MCP Version Docker Ready Version Tests CI Zero Dependencies

🚀 Inicio rápido

Local (Termux / Linux)

cd /path/to/nano-mcp-termux
python3 nano_mcp_termux.py

Docker

docker build -t nano-mcp-termux .
docker run -i --rm nano-mcp-termux

Verificación de salud (una sola ejecución, sin protocolo de enlace MCP)

python3 nano_mcp_termux.py --health

🛠️ Características

  • ✅ Sin dependencias: No se requieren paquetes externos
  • ✅ Un solo archivo: Toda la lógica en un script de Python
  • ✅ Multiplataforma: Funciona en Termux (Android), Raspberry Pi, Linux y dentro de Docker
  • ✅ Listo para contenedores: Dockerfile en la raíz del repositorio para la introspección de Glama
  • ✅ Formato stdio estándar: JSON-RPC delimitado por nuevas líneas (transporte oficial de MCP)
  • ✅ Negociación de versiones: Responde al protocolVersion del cliente (2024-11-05 / 2025-06-18 / 2025-11-25), con respaldo a la versión más alta compatible
  • ✅ Degradación elegante: device_status nunca falla; las entradas no disponibles se marcan, no se bloquean
  • ✅ [ciclo de vida] Sin procesos huérfanos: cada comando se ejecuta en su propio grupo de procesos; los tiempos de espera eliminan todo el árbol (SIGTERM → SIGKILL), nunca solo el shell
  • ✅ [ciclo de vida] Autoterminación: vigilante del proceso padre + detección de EOF en stdin + tiempo de inactividad opcional, para que un cliente muerto nunca deje un servidor zombie
  • ✅ [ciclo de vida] Compatible con Phantom Process Killer: informa el riesgo de recuento de procesos secundarios en Android 12+ con mitigaciones concretas
  • ✅ [rutas] Adaptador de rutas Android/Termux: resuelve /sdcard ↔ /storage/emulated/0 ↔ $HOME/storage/shared, detecta montajes noexec, sistemas de archivos sin distinción de mayúsculas y riesgos de comillas en shell

🧩 Resumen de herramientas

HerramientaDescripción
device_statusInformación agregada del dispositivo: batería / almacenamiento / arquitectura / memoria (los campos degradados se marcan como no disponibles)
server_healthSalud en tiempo de ejecución: pid/ppid/env, tiempo de actividad, contadores de solicitudes, procesos secundarios activos, política de reutilización, RSS, riesgo de Phantom Process Killer
resolve_pathResolver una ruta Android/Termux: forma canónica, punto de montaje, indicadores noexec/solo lectura, sensibilidad a mayúsculas, ortografías equivalentes, advertencias de comillas
path_adapterPerfil del entorno: clase de ejecución, $HOME/$PREFIX/$TMPDIR, raíces de almacenamiento de Android con resúmenes de montaje, lista de montajes noexec

🔗 Superficie del protocolo

MétodoComportamiento
initializeResponde a la versión compatible del cliente (2024-11-05 / 2025-06-18 / 2025-11-25), de lo contrario responde con la versión más alta compatible según la especificación MCP; declara {"tools": {}}
notifications/initializedSilencioso (sin respuesta)
pingDevuelve {}
tools/listDevuelve el catálogo de herramientas
tools/callDevuelve {"content": [{"type": "text", ...}]}
Método/herramienta desconocidoErrores JSON-RPC -32601 / -32602
JSON malformadoError de análisis -32700

🔄 Por qué 1.1.0: el error del proceso huérfano

La versión 1.0.0 ejecutaba comandos con subprocess.run(..., timeout=...). Al agotarse el tiempo de espera, Python termina solo el proceso directo — el contenedor sh -c. Cualquier cosa que el shell ya hubiera generado se reasigna a init y sobrevive para siempre. En Android, esa es exactamente la clase de fuga que activa el Phantom Process Killer y puede hacer que se elimine todo el grupo de aplicaciones.

La versión 1.1.0 corrige esto de raíz: los comandos se generan con start_new_session=True y se eliminan con os.killpg(pgid, SIGTERM) → SIGKILL, de modo que todo el árbol de procesos muere junto.

El repositorio incluye una prueba de regresión A/B reproducible para esto:

python3 test_lifecycle_orphan.py
# current  nano_mcp_termux.py           leaked_grandchildren=0
# legacy   nano_mcp_termux_v10_backup.py leaked_grandchildren=1   <- the bug
# PASS: current server leaves 0 orphaned grandchildren after timeout

✅ Pruebas

python3 test_client.py            # 32 protocol / tool / lifecycle assertions
python3 test_lifecycle_orphan.py  # orphan-leak A/B regression (1.0.0 vs 1.1.0)

⚙️ Variables de entorno

VariableValor predeterminadoPropósito
NANO_IDLE_TIMEOUT0 (desactivado)Segundos de inactividad antes de que el servidor se cierre por sí solo
NANO_NO_WATCHDOGsin definirEstablecer en 1 para desactivar el hilo de vigilancia del proceso padre

🔗 Enlaces


Este servidor está diseñado para pasar las verificaciones de introspección de Glama y servir como una implementación ligera de MCP para dispositivos móviles y de borde.