SSH MCP Server

oficial

Ejecuta comandos, mueve archivos, busca registros y audita máquinas a través de SSH desde tu agente.

¿Qué puedes hacer con SSH MCP?

  • Ejecutar comandos con salvaguardas de seguridad — Pídele a tu asistente que ejecute comandos individuales o por lotes mediante ssh_exec, con protección contra comandos destructivos que bloquea operaciones irreversibles antes de que lleguen al servidor.
  • Leer, escribir y listar archivos remotos — Usa ssh_file_read, ssh_file_write y ssh_file_list para inspeccionar o modificar archivos, con escrituras atómicas y verificación opcional SHA-256.
  • Buscar registros y verificar el estado del servidor — Consulta ssh_log_search o ssh_log_tail en archivos y contenedores, u obtén una instantánea estructurada del estado con ssh_snapshot y ssh_audit_baseline.
  • Transferir archivos con verificaciones de integridad — Sube o descarga archivos y directorios mediante ssh_upload y ssh_download, con respaldo automático de scp heredado para dispositivos más antiguos.
  • Gestionar trabajos en segundo plano de larga duración — Desacopla operaciones lentas con ssh_exec y rastréalas mediante ssh_job_status, ssh_job_output y ssh_job_kill, sobreviviendo a desconexiones.

Documentación

SSH MCP Server — Herramientas de servidor remoto para agentes de IA

SSH MCP Server

Un servidor MCP SSH: una multiherramienta que te ahorra a ti y a tu agente de IA tiempo y tokens en depuración, desarrollo y mantenimiento de servidores.

Ejecuta comandos, mueve archivos, lee registros y audita máquinas a través de SSH: un VPS en la nube, una máquina física o el router BusyBox que tienes en el armario.

Utiliza el cliente OpenSSH que ya está en tu máquina: tus claves, tu ~/.ssh/config, tus hosts de salto, tu reenvío de agente. Nada incluido, nada que compilar, sin enlaces nativos.

Funciona con Claude Code, Codex CLI, Cline, opencode, Gemini CLI, Qwen Code, Hermes y otros clientes MCP.

MCP Registry Glama Smithery npm downloads tests

Instalar · Herramientas · Configuración · Seguridad · Hoja de ruta · Documentación · Registro de cambios


Instalar en 30 segundos

No se requiere instalación global. npx descarga el paquete en el primer uso:

npx -y @hypnosis/ssh-mcp-server

Añádelo a tu cliente MCP — Claude Code, por ejemplo — para cada proyecto:

claude mcp add ssh -s user \
  -e SSH_PROFILES_FILE="$HOME/.claude/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

O escríbelo a mano: el mismo servidor con la forma de configuración que comparten la mayoría de los clientes:

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": ["-y", "@hypnosis/ssh-mcp-server"],
      "env": {
        "SSH_PROFILES_FILE": "~/.claude/ssh-profiles.json"
      }
    }
  }
}

Luego crea ~/.claude/ssh-profiles.json con al menos una máquina:

{
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin",
      "privateKeyPath": "~/.ssh/your_private_key"
    }
  }
}

Eso es suficiente para conectarse.

Codex, opencode, Qwen Code y otros clientes están cubiertos en Configurar el servidor MCP SSH.

Instalar como plugin

Algunos clientes — Claude Code, por ejemplo — pueden tomar todo el conjunto como un plugin en su lugar:

/plugin marketplace add hypnosis/ssh-mcp-server
/plugin install ssh-mcp-server@ssh-mcp-server

El plugin lee ~/.claude/ssh-profiles.json a menos que SSH_PROFILES_FILE indique lo contrario, así que crea ese archivo primero y el servidor se iniciará con tus máquinas ya cargadas.

Requisitos

npm version Node.js TypeScript MCP SDK

Node.js 18+ y un cliente ssh del sistema en PATH. En Windows, usa un perfil basado en claves; los perfiles de contraseña y frase de contraseña no están disponibles actualmente.

¿Prefieres una versión fija, trabajo sin conexión o una comprobación de registro menos por inicio? npm install -g @hypnosis/ssh-mcp-server, luego usa ssh-mcp-server como comando en lugar de npx.

Para quién es esto

  • DevOps y SRE que quieren auditorías más rápidas, comprobaciones de incidentes y trabajo rutinario de servidores.
  • Codificadores de vibraciones y creadores independientes que publican con un asistente de IA y ejecutan lo que construyen en sus propios servidores.
  • Administradores de sistemas e ingenieros de plataformas que quieren herramientas estructuradas en lugar de un shell sin restricciones.
  • Desarrolladores y equipos pequeños que gestionan su propio VPS sin un equipo de operaciones dedicado.
  • Propietarios de homelab, NAS y routers cuyo hardware útil ha superado sus protocolos modernos.

Por qué un servidor MCP SSH en lugar de un shell sin procesar

Menos tokens, menores costos de IA

Un shell sin procesar le da a un agente de IA un torrente: comandos repetidos, tablas ASCII y volcados de registros. Quema tokens convirtiendo ese ruido en una imagen del servidor: tu dinero.

Depuración de servidores más rápida

Las herramientas diseñadas específicamente agrupan comprobaciones rutinarias, limitan la salida ruidosa y devuelven la parte que importa. El agente dedica menos tiempo a traducir la salida del terminal y llega antes a la solución.

Menos conjeturas, menos errores de IA

Las respuestas estructuradas indican qué se encontró, qué no se pudo medir y qué se truncó. Eso deja al agente menos margen para rellenar vacíos con una alucinación, y te da menos arreglos malos, despliegues más tranquilos y código más confiable.

Compatibilidad SSH: servidores modernos, equipos heredados y Windows

Usa tu configuración OpenSSH existente

Sin implementación SSH incluida, sin enlaces nativos, sin recompilación por plataforma. Los comandos usan el cliente ssh del sistema, así que tus claves, tu ~/.ssh/config, tus hosts de salto y tu reenvío de agente siguen funcionando exactamente como en un terminal. Cuando se admite, una única conexión multiplexada compartida por destino significa que te autenticas una vez, no una vez por comando.

Soporte SSH para servidores heredados, routers y dispositivos NAS

Envía un archivo a un router con un scp moderno y obtienes esto:

scp app.conf router:/etc/
# scp: subsystem request failed on channel 0

Nada está roto: un scp actual habla el nuevo protocolo, y el router no lo sabe. En un terminal ahora vas a leer un hilo de foro y vuelves con una bandera extra. Aquí no haces nada: se intenta la transferencia, se reconoce la negativa, se usa el protocolo antiguo en su lugar, y esa máquina se recuerda para que el siguiente archivo vaya directamente allí.

Alternativas para clientes SSH antiguos y herramientas faltantes

El equipo antiguo recibe una alternativa, no un callejón sin salida. Cuando falta una función moderna, el servidor toma el camino más antiguo cuando puede:

Tu máquinaLo que obtienes
Un router o NAS demasiado pequeño para transferencia de archivos modernaEl archivo sigue llegando: el protocolo antiguo se usa automáticamente
Un servidor de hace diez añosEl flujo de trabajo sigue funcionando; solo abre una conexión nueva por comando en lugar de reutilizar una
Una imagen reducida sin forma de calcular hash de un archivoLa subida dice "no se pudo verificar" en lugar de afirmar una coincidencia que nadie comprobó
Una máquina donde una herramienta simplemente no está instaladaLa respuesta dice "no medido": nunca un cero que se lea como "no hay nada"

Construido para el Protocolo de Contexto de Modelos

Construido sobre el SDK MCP oficial, TypeScript en todo el código, más de 2500 pruebas unitarias más una suite en vivo que se ejecuta contra contenedores reales en lugar de simulaciones.


SSH sin procesar vs un servidor MCP SSH: el mismo trabajo, de ambas maneras

Verificación de salud del servidor SSH

Situación: Acaba de salir un despliegue. El servidor se siente lento y no sabes si el disco, la memoria, los servicios, los contenedores o los errores son los culpables.

Pregunta: "¿Está saludable esta máquina?"

SSH sin procesar

$ uptime
 10:42:17 up 18 days,  3:21,  2 users,  load average: 0.42, 0.31, 0.28
$ df -hT
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/sda1      ext4    40G   35G  5.0G  87% /
overlay        overlay  40G   35G  5.0G  87% /var/lib/docker/overlay2/...
$ free -h
               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       4.9Gi       612Mi       121Mi       2.2Gi       2.5Gi
$ systemctl --failed
  UNIT              LOAD   ACTIVE SUB    DESCRIPTION
● api-worker.service loaded failed failed API background worker
$ docker ps -a
CONTAINER ID   IMAGE          STATUS                     PORTS
8e14d0b41c2a   api:latest     Up 3 minutes               0.0.0.0:8080->8080/tcp
65b894af2430   worker:latest  Exited (1) 2 minutes ago
$ ss -tulpn
Netid  State   Local Address:Port   Process
tcp    LISTEN  0.0.0.0:22          users:(("sshd",pid=842,fd=3))
tcp    LISTEN  0.0.0.0:8080        users:(("docker-proxy",pid=1942,fd=4))
$ journalctl -p err --since -1h | tail -50
Aug 20 10:39:14 prod api-worker[22104]: database connection timed out
Aug 20 10:39:14 prod systemd[1]: api-worker.service: Failed with result 'exit-code'.

Eso sigue siendo un resultado abreviado. Una verificación completa necesita más comandos para CPU, estados de servicios, conteos de contenedores y errores recientes, cada uno con su propio formato de salida. Peor aún, una máquina sin ss puede parecer que tiene cero oyentes cuando la verificación de puertos nunca se ejecutó.

Resultado MCP estructurado

ssh_snapshot({ "profile": "production" })
{
  "disk_pct": 87,
  "mem_pct": 64,
  "cpu_pct": 12,
  "load": "0.42 0.31 0.28",
  "containers": 7,
  "ports": 14,
  "services_running": 3,
  "recent_errors": 21,
  "unavailable": []
}

Lo que gana el agente

SSH sin procesarMCP estructuradoTu ganancia
Varios comandos y tablas ASCIICampos con nombre en un solo resultadoUna llamada, campos con nombre y menos viajes de ida y vuelta
Una herramienta faltante puede parecer salida vacíaunavailable nombra lo que no se midióMenos conjeturas y menos arreglos malos
Tú ordenas discos, servicios y erroresLas señales del problema ya están en la superficieDepuración más rápida

Un resultado completo de ssh_audit_baseline puede ser más largo que un puñado de salidas de comandos sin procesar: alrededor de 1,077 tokens frente a 765 en nuestra medición de laboratorio. El ahorro viene del flujo de trabajo completo, no de hacer una respuesta más corta.

En una sesión real de resolución de problemas, las herramientas diseñadas específicamente redujeron 49 llamadas de comandos separadas a 4 llamadas MCP. Cada llamada adicional inicia otro turno del modelo con la conversación acumulada. El almacenamiento en caché de indicaciones puede reducir el costo de la entrada repetida, pero los comandos nuevos y su salida aún consumen contexto. Menos viajes de ida y vuelta significan menos tokens en toda la sesión, menos análisis repetido y un camino más rápido hacia la respuesta.

¿Necesitas el panorama completo en lugar del pulso? ssh_audit_baseline agrupa sistema, disco, memoria, puertos, sshd, unidades fallidas, Docker, firewall y actualizaciones. Los hallazgos llegan como CRÍTICO / ADVERTENCIA / OK; las secciones no medidas se nombran en lugar de leerse silenciosamente como cero.

Búsqueda de registros en servidor Linux

Situación: La API está agotando el tiempo de espera, pero el mismo mensaje puede estar en nginx, syslog, journald o un registro de aplicación que no puedes leer con tu usuario normal.

Pregunta: "¿De dónde vino ese error?"

SSH sin procesar

$ grep -i "timeout" /var/log/nginx/error.log
2026/08/20 10:38:54 [error] upstream timed out while reading response header
$ grep -i "timeout" /var/log/syslog
Aug 20 10:39:14 prod api-worker[22104]: database connection timed out
$ grep -i "timeout" /var/log/app/*.log 2>/dev/null
$ journalctl -u api --since "1 hour ago" | grep -i timeout
Aug 20 10:39:14 prod api[22104]: database connection timed out after 30000ms

El tercer comando parece limpio, pero 2>/dev/null también ocultó un error de permisos. "Nada coincidió" y "nada se leyó" ahora se ven idénticos. Un registro ocupado también puede devolver miles de líneas y sacar el resto del incidente del contexto del agente.

Resultado MCP estructurado

ssh_log_search({ "profile": "production",
                 "path": ["/var/log/nginx/error.log", "/var/log/syslog", "/var/log/app/*.log"],
                 "query": "timeout", "context": 2, "since": "1h" })
{
  "matches": 34,
  "lines": [
    { "file": "/var/log/nginx/error.log", "line": 4821,
      "text": "upstream timed out while reading response header", "context": false },
    { "file": "/var/log/nginx/error.log", "line": 4822,
      "text": "client closed connection", "context": true }
  ],
  "files_searched": 6,
  "files_unreadable": ["/var/log/app/private"],
  "files_skipped": 12,
  "files_undated": [],
  "limited": false,
  "truncated": false
}

Lo que gana el agente

SSH sin procesarMCP estructuradoTu ganancia
Cuatro búsquedas y cuatro salidasUna búsqueda en archivos y globsMenos tokens y viajes de ida y vuelta
Los errores de permisos pueden desaparecerfiles_unreadable nombra cada ruta omitidaSin conclusión falsa de "registros limpios"
La salida puede crecer sin un límite útillimited y truncated exponen cada corteDecisiones más seguras con resultados parciales

since usa el reloj del servidor, namesOnly: true devuelve solo las rutas coincidentes, y ssh_log_tail lee las últimas N líneas de varios registros en una sola llamada.

Ediciones seguras de configuración remota

Situación: Necesitas reemplazar una configuración de nginx en un servidor en vivo. Una conexión caída, un modo incorrecto o una copia sin verificar podrían dejar el servicio con un archivo roto.

Pregunta: "¿Puedo reemplazar esta configuración sin dejar un archivo parcial?"

SSH sin procesar

$ sudo sh -c 'cat > /etc/nginx/conf.d/api.conf' <<'EOF'
server {
    listen 80;
    location / { proxy_pass http://127.0.0.1:8080; }
}
EOF
$ echo $?
0

El código de salida cero dice que el shell terminó. No prueba qué bytes llegaron, y > truncó el archivo antiguo antes de que llegara el primer byte del nuevo. Si la conexión se cae a mitad de la escritura, el servicio queda con una configuración parcial.

Resultado MCP estructurado

ssh_file_write({ "profile": "production",
                 "files": [{ "path": "/etc/nginx/conf.d/api.conf",
                             "content": "server {\n    listen 80;\n    location / { proxy_pass http://127.0.0.1:8080; }\n}\n",
                             "mode": "644", "sudo": true, "verify": true }] })
{
  "files": [{ "path": "/etc/nginx/conf.d/api.conf", "written": true,
              "verified": "verified", "reason": null, "bytes": 79 }]
}

Lo que gana el agente

SSH sin procesarMCP estructuradoTu ganancia
El destino se trunca antes de que la copia se completeUn archivo temporal completo lo reemplaza con un solo renombradoSin configuración a medio escribir
Solo código de salidaLos bytes y el resultado de la verificación se nombranSabes qué llegó realmente
Los permisos viven dentro del texto del shellsudo, mode y verify son campos por archivoPropiedad predecible y menos errores de comillas

verified tiene tres resultados honestos: verified, unavailable cuando el servidor no tiene herramienta de hash, y skipped cuando no se solicitó verificación. Para lecturas, ssh_file_read acepta una lista de rutas; ssh_file_list maneja globs, recursión, tamaños y modos.

Ejecutar comandos SSH por lotes con sudo

Situación: Un despliegue está listo, pero la sintaxis de nginx, el estado del servicio y los errores recientes deben verificarse antes de que el tráfico se mueva. Una verificación fallida no debería desaparecer dentro de un volcado combinado.

Pregunta: "¿Pasaron todas las verificaciones previas al despliegue?"

SSH sin procesar

$ ssh admin@server.example.com 'sudo nginx -t'
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ ssh admin@server.example.com 'sudo systemctl is-active nginx'
active
$ ssh admin@server.example.com 'sudo tail -5 /var/log/nginx/error.log'
2026/08/20 10:38:54 [error] upstream timed out while reading response header

Tres conexiones devuelven tres salidas no relacionadas. Si los comandos se unen con ;, el shell informa solo el último código de salida; si se unen con &&, las verificaciones posteriores desaparecen después del primer fallo.

Resultado MCP estructurado

ssh_exec({ "profile": "production",
           "command": ["nginx -t", "systemctl is-active nginx",
                       "tail -5 /var/log/nginx/error.log"],
           "sudo": true })
{
  "commands": [
    { "command": "nginx -t", "exit_code": 0, "truncated": false, "clipped_bytes": 0,
      "stdout": "", "stderr": "nginx: configuration file /etc/nginx/nginx.conf test is successful\n" },
    { "command": "systemctl is-active nginx", "exit_code": 0, "truncated": false,
      "clipped_bytes": 0, "stdout": "active\n", "stderr": "" },
    { "command": "tail -5 /var/log/nginx/error.log", "exit_code": 0, "truncated": false,
      "clipped_bytes": 0, "stdout": "2026/08/21 09:14:02 [error] upstream timed out\n", "stderr": "" }
  ],
  "job_id": null
}

Lo que gana el agente

SSH sin procesarMCP estructuradoTu ganancia
Tres llamadas y salidas no relacionadasUna lista de comandos ordenadaMenos viajes de ida y vuelta
Un shell combinado puede ocultar el estado intermedioCada comando mantiene su propio exit_codeSin verificación fallida pasada por alto
sudo y las comillas se repiten en el texto del comandosudo se aplica a todo el loteMenos errores de comillas

El guardián de comandos destructivos verifica la lista completa antes de que se ejecute el primer comando. Si una entrada es rechazada, cada otra entrada se marca como no ejecutada y nada se envía al servidor. Cada comando lleva su propio stdout y stderr. Un comando que se ejecutó y no imprimió nada tiene una cadena vacía; un comando que nunca se ejecutó no tiene ese campo en absoluto, por lo que no se pueden confundir. La salida de más de 128 KB por comando conserva ambos extremos — el inicio para tablas, el final para registros — con una costura en medio que indica la cantidad, y clipped_bytes dice cuánto se recortó. El recorte ocurre en límites de bytes y retrocede hasta el borde de un carácter, por lo que una respuesta truncada nunca lleva una marca de reemplazo.

sudo llega al servidor sin una terminal: la respuesta del perfil se entrega a sudo en la entrada estándar. Qué secreto es ese proviene de sudoPassword cuando el perfil nombra uno y de password en caso contrario — un perfil que inicia sesión por clave no tiene contraseña de inicio de sesión en absoluto, y donde una máquina mantiene los dos separados, la de inicio de sesión es la respuesta incorrecta. Cuando no hay nada con qué responder, la respuesta lo dice y nombra las salidas, en lugar de dejar el propio consejo de sudo sobre -S y los ayudantes de askpass. Un comando que lee su propia entrada estándar nunca recibe la contraseña, que de otro modo terminaría mezclada con los datos.

Ejecutar trabajos SSH de larga duración

Situación: Una copia de seguridad o migración durará más que la sesión del agente. La conexión puede cerrarse, pero aún necesitas su estado, salida y código de salida más tarde.

Pregunta: "¿Sobrevivirá este trabajo a la conversación?"

SSH sin procesar

$ ssh admin@server.example.com 'pg_dump app | gzip > /srv/backups/app.sql.gz'
client_loop: send disconnect: Broken pipe

La terminal ha desaparecido. Ahora tienes que reconectarte, encontrar el proceso, inspeccionar el archivo de destino y adivinar si la copia de seguridad terminó o se detuvo a mitad de camino.

Resultado MCP estructurado

ssh_exec({ "profile": "production",
           "command": "pg_dump app | gzip > /srv/backups/app.sql.gz",
           "detach": true })
{
  "commands": [{
    "command": "pg_dump app | gzip > /srv/backups/app.sql.gz",
    "exit_code": null,
    "truncated": false,
    "timed_out": false,
    "blocked": false,
    "blocked_reason": null,
    "not_run": false,
    "warning": null
  }],
  "job_id": "mst0f2q1-9ab3c4d5"
}

Lo que el agente gana

SSH sin procesarMCP estructuradoTu ganancia
El trabajo está vinculado a una sesión SSHEl trabajo remoto tiene un id persistenteDesconexiones y reinicios seguros
Reconectarse significa buscar procesos y archivosEl estado y el código de salida tienen estados nombradosSin adivinar si terminó
Leer la salida de nuevo repite texto antiguoLa salida continúa desde un desplazamiento de bytesMenor uso de tokens en trabajos largos

El estado del trabajo vive en el disco remoto, no en la memoria de este servidor. ssh_job_status distingue running, finished y lost; ssh_job_output continúa desde el último desplazamiento de bytes; y ssh_job_kill señala a todo el grupo de procesos en lugar de solo a su shell.

Transferir archivos a routers y NAS heredados

Situación: Un cliente OpenSSH actual intenta SFTP, pero el router o NAS solo entiende el protocolo scp clásico. El archivo debe llegar intacto y reemplazar su destino de forma segura.

Pregunta: "¿Puede este dispositivo antiguo seguir recibiendo un archivo verificado?"

SSH sin procesar

$ scp app.conf operator@router:/etc/app.conf
subsystem request failed on channel 0
scp: Connection closed

El siguiente paso habitual es recordar la bandera heredada, reintentar la copia y luego ejecutar un comando hash por separado—si el dispositivo tiene una herramienta hash en absoluto.

Resultado MCP estructurado

ssh_upload({ "profile": "router", "local_path": "./app.conf",
             "remote_path": "/etc/app.conf", "sudo": true,
             "mode": "644", "owner": "root:root", "verify": true })
{
  "files": [{
    "path": "/etc/app.conf",
    "written": true,
    "verified": "verified",
    "reason": null,
    "bytes": 1284
  }]
}

Lo que el agente gana

SSH sin procesarMCP estructuradoTu ganancia
El modo SFTP moderno se detiene en el primer errorLa alternativa scp clásica es automática y recordadaEl equipo antiguo sigue funcionando
Una copia exitosa no prueba integridadLa verificación SHA-256 tiene un resultado nombradoLa corrupción no se confunde con éxito
El reemplazo directo puede dejar un destino parcialUn archivo temporal se mueve a su lugar después de la transferenciaEl archivo de trabajo sobrevive a interrupciones

Si el dispositivo no tiene ni sha256sum ni openssl, el resultado dice unavailable y nombra la razón en lugar de informar una coincidencia falsa. Los directorios completos usan recursive: true y verifican sus hashes en un solo lote.

Protección contra comandos destructivos para agentes de IA

La protección se ejecuta localmente, antes de que un comando llegue a SSH. Separa las operaciones que pueden recuperarse de las que destruyen el contenedor que alberga los datos, y verifica el orden de los comandos dentro de cadenas y lotes.

Detener una cadena destructiva antes de que comience

Una secuencia segura de copia de seguridad y reemplazo:

cp -r /srv/app /srv/app.bak && mv /srv/app /srv/app-old && rm -rf /srv/app

Las mismas operaciones en el orden incorrecto:

rm -rf /srv/app && cp -r /srv/app /srv/app.bak && mv /srv/app /srv/app-old
# REFUSED before the first command runs

El shell eliminaría el directorio y solo entonces descubriría que la fuente de la copia de seguridad ha desaparecido. La protección ve que los pasos posteriores leen un destino ya destruido por un paso anterior, por lo que toda la llamada permanece en tu máquina. La misma verificación detecta dropdb app && pg_dump app > backup.sql.

Rechazar pérdida irreversible, advertir sobre cambios recuperables

Rechazado — el contenedor en síSolo advertido — su contenido
DROP DATABASE, dropdbDROP TABLE, TRUNCATE, DELETE FROM
docker volume rm, docker compose down -vdocker rm -f <name>
crontab -reditar un trabajo
mkfs, wipefs -a, lvremove, zfs destroychmod 777
reboot, shutdown, haltgit reset --hard

docker compose down -v se rechaza porque -v elimina volúmenes Docker nombrados, incluido un volumen de base de datos. Sin -v, detener los servicios no se trata como la misma acción irreversible.

La eliminación recursiva de la raíz del sistema de archivos, un directorio de inicio o árboles del sistema como /etc, /var y /usr también se rechaza, incluso cuando un enlace simbólico lleva allí. Un destino no resuelto como rm -rf "$DIR"/* también se rechaza: "no se pudo verificar" no se trata como "seguro".

Nombrar lo que detienes

Un comando que encuentra su destino en lugar de nombrarlo no se envía. El servidor lo expande y responde con lo que hay detrás del destino:

docker kill $(docker ps -q --filter ancestor=web)
# BLOCKED — would stop:
#   edge — web:latest, Up 34 days, 0.0.0.0:8443->8443/tcp

Para un proceso, la respuesta añade las señales de que está en uso: cuánto tiempo ha estado ejecutándose, qué puertos acepta conexiones, cuántas conexiones está manejando. Los destinos nombrados no cuestan nada extra y pasan en silencio — docker kill web-1, kill 4871, systemctl stop app.

Para continuar, nombra lo que se está deteniendo. Los nombres se verifican contra lo que el comando realmente alcanza, por lo que una máscara que se ha desviado hacia otra cosa se rechaza en lugar de confirmarse:

docker kill $(docker ps -q --filter ancestor=web) # CONFIRMED-KILL: edge

Un patrón sobre líneas de comando es un caso aparte. Coincide con el propio comando que lo lleva, por lo que el shell que lo ejecuta recibe la señal antes que el destino y la respuesta se interrumpe a la mitad. Tal ataque no se confirma sino que se reescribe — por número, o con un carácter escrito como una clase para que el patrón deje de coincidir consigo mismo:

pkill -f relay
# BLOCKED — two ways through:
#   kill 4871
#   pkill -f '[r]elay' # CONFIRMED-KILL: 4871

Tres resultados permanecen separados: destinos encontrados, la expansión no llegó a nada, y nada con qué preguntar — sin motor en la máquina, una respuesta truncada, una conexión que falló. Los dos últimos también son rechazos: no saber no es una razón para proceder.

Confirmar un comando destructivo intencional

Nada está prohibido permanentemente. Añade # CONFIRMED-DESTRUCTIVE a un comando revisado y se permite su paso. Cuando la protección rechaza una entrada en un lote, el lote completo se detiene antes de la ejecución, por lo que el servidor nunca queda después de una operación a medio ejecutar.

La protección funciona dentro de una sola llamada. No puede conectar una eliminación en una invocación con una lectura en la siguiente, ni razonar sobre herramientas que no reconoce. Es un cinturón de seguridad, no un motor de políticas: las operaciones recuperables siguen siendo tu decisión. Las restricciones de rutas y las reglas de comillas están documentadas en docs/security.md.

Herramientas

18 herramientas MCP SSH para operaciones de servidor. Parámetros completos y ejemplos viven en docs/tools.md.

HerramientaQué hace
ssh_execEjecutar un comando o un lote, con la protección de comandos destructivos y desconexión opcional
ssh_file_readLeer uno o varios archivos, texto o binario
ssh_file_writeEscribir archivos con renombrado atómico y verificación SHA-256 opcional
ssh_file_listListar un directorio, con glob y recursión opcionales
ssh_uploadSubir un archivo o directorio por SSH, seguro para binarios con verificaciones de integridad; un directorio reemplaza el destino o se fusiona en él
ssh_downloadDescargar un archivo o directorio por SSH, seguro para binarios con verificaciones de integridad
ssh_job_statusEstado de un trabajo en segundo plano: ejecutándose, terminado o perdido
ssh_job_outputLeer la salida acumulada desde un desplazamiento de bytes
ssh_job_listListar trabajos, eliminando los terminados más allá de su TTL
ssh_job_killSeñalar a todo el grupo de procesos de un trabajo
ssh_log_tailÚltimas N líneas de uno o varios registros, con soporte de glob; un contenedor por nombre
ssh_log_searchBúsqueda de patrones en registros, o a través del registro de un contenedor
ssh_snapshotInstantánea de salud de una sola vez: servicios, recursos, Docker, red, errores
ssh_monitorControl de transporte: estadísticas, recarga, prueba, lista, cierre
ssh_audit_baselineSistema, disco, memoria, red, ssh, servicios, Docker, firewall, actualizaciones
ssh_tls_checkCaducidad de certificados, SAN, cadena y enlace de renovación para un dominio
ssh_disk_breakdownA dónde fue el disco: du top-N, Docker, journald, cachés
ssh_service_statussystemctl status más una cola journalctl para una unidad

Anotaciones de seguridad de herramientas MCP

Las anotaciones MCP estándar indican a los clientes qué herramientas son de solo lectura, destructivas, idempotentes o de mundo abierto. Consulta la tabla completa.

Ejecutar comandos SSH y gestionar archivos remotos

Comandos, lecturas y escrituras de archivos, listados de directorios — el trabajo ordinario en una máquina, cada respuesta ya analizada.

Monitorear trabajos SSH de larga duración

El trabajo lento se desconecta y se sigue en lugar de esperarlo: cada mirada dice hasta dónde ha llegado.

Buscar registros y verificar la salud del servidor

Registros de archivos y contenedores, y una imagen de una sola vez de la máquina, con salida limitada para que una cola no consuma la ventana de contexto.

Subir y descargar archivos por SSH

Transferencias seguras para binarios con verificaciones de integridad. Detalles en docs/transfer.md.

Para binarios y archivos grandes usa ssh_upload / ssh_download — los fragmentos base64 y los heredocs no son seguros para binarios ni atómicos.

Auditar servidores Linux por SSH

Solo lectura y agrupados en un solo viaje de ida y vuelta. Detalles en docs/audit.md.

Modo de compatibilidad SSH de Windows

Windows usa el modo de compatibilidad automáticamente. Cuando la multiplexación de conexiones no está disponible, el servidor cambia a una conexión por comando. Las mismas herramientas siguen estando disponibles a través de SSH basado en claves — sin configuración separada ni implementación específica de Windows.

La protección de comandos destructivos se cubre en Protección contra comandos destructivos para agentes de IA.

Configurar el servidor SSH MCP

Ejecuta el paquete desde Instalar en 30 segundos primero, luego crea un archivo de perfil.

Crear perfiles de conexión SSH

Colócalo donde quieras — junto a la configuración de tu propio agente es la elección habitual. Los ejemplos a continuación usan ~/.claude/ssh-profiles.json; para otros agentes cambia el directorio (~/.codex/, ~/.qwen/, ~/.config/opencode/):

{
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin",
      "port": 22,
      "privateKeyPath": "~/.ssh/your_private_key"
    }
  }
}

Elegir un perfil SSH explícitamente

No hay un perfil al que el servidor recurra: cada uno es una máquina diferente, y un comando enviado a la máquina equivocada no es algo que un mensaje de error pueda deshacer después. Pregunta sin un nombre y la respuesta lista los nombres para elegir:

ssh_exec({ command: "uptime" })
→ No profile specified. Name one explicitly: production

Un perfil que el servidor no puede usar para SSH — sin host, sin username, o mode: "local" — se omite sin queja, y los campos que no reconoce se dejan intactos, para que el archivo pueda compartirse con otras herramientas. Un perfil con un campo roto es un caso diferente: se nombra junto con el campo y el valor, y sus vecinos saludables siguen funcionando.

Cada perfil opcionalmente toma un bloque pathSecurity que permite o bloquea las rutas que las herramientas de archivos pueden tocar — consulta docs/security.md.

Un perfil que inicia sesión por clave pero necesita sudo en el lado remoto toma un sudoPassword — el secreto sudo con el que se responde, que en muchas máquinas no es la contraseña de inicio de sesión. Mantenlo en el archivo de secretos en lugar de aquí.

Mantener contraseñas SSH y frases de contraseña fuera de los perfiles

Preferir claves. Si una contraseña o frase de contraseña de clave cifrada es inevitable, mantenla en un archivo de secretos separado, nunca en el propio perfil:

{
  "secretsFile": "~/.config/ssh-mcp/secrets.json",
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin"
    }
  }
}

El archivo de secretos está indexado por nombre de perfil — consulta secrets.json.example:

{
  "production": { "password": "..." },
  "buildbox": { "sudoPassword": "..." }
}

sudoPassword es lo que sudo responde en esa máquina. Un perfil que inicia sesión con clave no tiene contraseña de inicio de sesión que ofrecer, y cuando ambas difieren, la de inicio de sesión es la respuesta incorrecta; sin ella, se usa password.

El archivo de secretos debe ser legible solo por ti (chmod 600). Las rutas relativas se resuelven desde el archivo de perfiles; los secretos permanecen fuera de argv y se enmascaran en los registros. Consulta seguridad de credenciales.

Configurar Claude Code, Codex y otros clientes MCP

Elige el cliente que uses y apúntalo al mismo archivo de perfiles.

Claude Code

Un comando; -s user hace que el servidor esté disponible en cada proyecto:

claude mcp add ssh -s user \
  -e SSH_PROFILES_FILE="$HOME/.claude/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

Codex CLI

codex mcp add ssh \
  --env SSH_PROFILES_FILE="$HOME/.codex/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

opencode

Ponlo en ~/.config/opencode/opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ssh": {
      "type": "local",
      "command": ["npx", "-y", "@hypnosis/ssh-mcp-server"],
      "enabled": true,
      "environment": {
        "SSH_PROFILES_FILE": "~/.config/opencode/ssh-profiles.json"
      }
    }
  }
}

Qwen Code

Un comando, igual que los demás:

qwen mcp add ssh \
  -e SSH_PROFILES_FILE="$HOME/.qwen/ssh-profiles.json" \
  npx -y @hypnosis/ssh-mcp-server

Otros clientes MCP

Gemini CLI, Hermes, Cline, un plugin de editor o tu propio agente funcionan de la misma manera. Todo lo que necesitan es un comando para ejecutar y una variable de entorno.

Reinicia tu cliente MCP

Reinicia el cliente y luego ejecuta ssh_monitor({ action: "list" }) para confirmar que el perfil se cargó.

Configuración del servidor SSH MCP

VariableQué hacePredeterminado
SSH_PROFILES_FILERuta al JSON de perfiles — obligatorio
SSH_MCP_LOG_LEVELdebug, info, warn, errorinfo
LOG_LEVELRespaldo, usado solo cuando SSH_MCP_LOG_LEVEL no está definidoinfo
SSH_MCP_LOG_TIMESTAMPMarcas de tiempo en las líneas de registrotrue
SSH_MCP_CONTROL_PERSISTSegundos que una conexión compartida permanece activa después del último comando; 0 la cierra de inmediato600
SSH_MCP_CONTROL_DIRDónde viven los sockets de control~/.ssh/ssh-mcp
SSH_MCP_PROFILES_CACHE_TTLTTL de caché de perfiles, ms60000
SSH_MCP_PROFILES_WATCHRecargar el archivo de perfiles cuando cambiatrue

La conexión compartida sobrevive a este proceso a propósito: cerrarla al salir cortaría el canal que otra ventana en la misma máquina está usando.

Limitaciones del servidor SSH MCP

Cada límite te dice cómo sortearlo. Una herramienta que no puede hacer algo lo dice y nombra ssh_exec, que ejecuta comandos directamente en la máquina — un controlador de registros no compatible, una utilidad que la máquina no tiene, un motor que este servidor no habla. No tienes que saber de antemano dónde terminan las herramientas: la negativa lo dice, en el momento en que importa.

Tres negativas permanecen deliberadamente en silencio sobre el shell, porque ahí es la respuesta incorrecta: una ruta que tu perfil prohíbe (sortear tu propia regla no es una solución), una llamada mal formada (la solución está en la llamada) y una negativa del propio ssh_exec.

  • Cancelación: una llamada cancelada ahora también detiene el comando en el servidor, enviada como una segunda llamada por la misma conexión. Donde el servidor no tiene /proc, el comando se encuentra a través de ps en su lugar. FreeBSD no está verificado: el comportamiento correcto allí no está garantizado. Las transferencias de archivos y ssh_snapshot no aceptan cancelación en absoluto.
  • Escrituras atómicas: BSD y macOS no pueden verificar previamente los cambios de nombre entre sistemas de archivos.

Hoja de ruta del servidor SSH MCP

  • Ejecución completa de pruebas contra hosts SSH de macOS

  • Ejecución de compatibilidad de extremo a extremo en Windows

  • Auditorías multi-host — comparar el estado de salud en varios perfiles SSH en una sola llamada

  • Importar perfiles desde el ~/.ssh/config existente

  • Transferencias reanudables para archivos grandes y conexiones inestables

  • Línea de tiempo de operaciones remotas — comandos, transferencias y decisiones de protección en un solo rastro de auditoría

  • Manuales de solución de problemas SSH listos para usar

  • Registros de contenedores sin recurrir al shellHECHO: ssh_log_tail y ssh_log_search aceptan un nombre de contenedor, preguntan a docker dónde escribe y leen ese archivo con el mismo mecanismo que cualquier otro registro

  • Una negativa que te deja atascadoHECHO: cada límite ahora nombra ssh_exec como la vía de salida, así que llegar al borde de una herramienta cuesta una frase en lugar de un juego de adivinanzas

  • Respuestas que llegan al modeloHECHO: la salida de comandos, las líneas de registro coincidentes, los nombres de máquinas y las secciones de instantáneas viajan en los campos, no solo en el texto

  • Esquemas de herramientas MCP más pequeñosHECHO: la lista de herramientas se redujo un 10%, y un trabajo separado ahora muestra las últimas líneas que escribió en lugar de ser consultado a ciegas

  • Trabajo largo bajo rootHECHO: un trabajo separado se ejecuta con sudo y se sigue como root, y un perfil solo de clave responde sudo con su propio sudoPassword

Desarrollar y probar el servidor SSH MCP

npm install
npm run build           # tsc
npx tsc --noEmit        # types, plus dead declarations
npm run test:unit       # unit tests
npm run lab:up          # start the two test containers
npm run test:live       # live suite against those containers

La suite en vivo se ejecuta contra contenedores reales — uno BusyBox, uno coreutils — porque los dos discrepan silenciosamente, y un simulacro está de acuerdo con quien lo escribió. Consulta docs/architecture.md para la estructura.

¿Te gusta SSH MCP Server? ⭐

Si te gusta la herramienta, dale una estrella en GitHub — ayuda a que más personas descubran el proyecto.

Contribuir al servidor SSH MCP

Los problemas y las solicitudes de extracción son bienvenidos en github.com/hypnosis/ssh-mcp-server.

Licencia

MIT — consulta LICENSE.