ssh-mcp-server
ssh-mcp-server
Servidor MCP sobre SSH: el agente ejecuta comandos en máquinas remotas, mientras que las claves, contraseñas y sudo permanecen de nuestro lado.
Fork de classfang/ssh-mcp-server bajo ISC.
Русский | English
Qué es
ssh-mcp-server es un puente entre un cliente MCP (Claude Code, Cursor, Cline) y SSH. El agente invoca herramientas, el servidor se conecta a la máquina y devuelve la salida. El modelo no ve ni la clave privada, ni la contraseña, ni la contraseña de sudo: todo esto se lee desde la configuración local y las variables de entorno del proceso.
Un solo servidor atiende cualquier número de hosts. El host se selecciona sobre la marcha mediante un alias de ~/.ssh/config, por lo que no es necesario escribir cada máquina en la configuración del cliente MCP.
Related MCP server: ssh-mcp-server
Qué se ha añadido en este fork
Funcionalidad | Para qué |
Hosts de | Un solo MCP para todo el parque. El alias se pasa en |
ProxyJump | El host detrás de un bastión es accesible por alias, la cadena |
sudo desde variable de entorno | El agente solicita |
Núcleo prohibido | Lista de operaciones que nunca se ejecutan: ni con sudo, ni en ningún perfil, ni a través de SFTP |
Perfiles de guardias | Conjunto listo de prohibiciones |
Túneles | SOCKS5 (equivalente a |
Verificación de claves de host |
|
Criptografía moderna | Ed25519 primero en la lista, sin SHA-1, CBC ni DSA |
Registro de auditoría | Cada llamada se escribe en JSONL con rotación y archivos gzip |
Sin carga de archivos |
|
Herramientas
Herramienta | Qué hace |
| Ejecuta un comando, admite |
| Descarga un archivo del servidor |
| Muestra las conexiones configuradas, su estado y el perfil de guardias activo |
| Muestra los alias de la configuración SSH disponibles como |
| Levanta un proxy SOCKS5 o un reenvío de puerto a través de la conexión |
| Cierra un túnel |
| Muestra los túneles abiertos y los contadores de conexiones |
list-ssh-hosts solo aparece con la bandera --ssh-config-hosts; las herramientas de túnel se eliminan con la bandera --disable-tunnels. La herramienta upload no está en la lista: solo se publica con la bandera --enable-upload.
Datos del host sin comandos adicionales
Al conectarse, el servidor captura una vez el estado de la máquina: nombre, direcciones, SO, kernel, uptime, disco, memoria, número de procesos. Todas las sondas se combinan con marcadores en un solo comando, de modo que es una sola sesión ssh, no seis.
El servidor mantiene el resultado en caché y lo entrega en list-servers:
[connected] prod-1 | deploy@10.0.0.5:22 | hostname=prod-1 | os=Linux | updated=2026-08-19T18:14:23Z
Raw JSON:
[{"name":"prod-1","connected":true,"guards":"guards=safe ruleset=2026.08.19 ...",
"status":{"reachable":true,"osVersion":"Ubuntu 24.04.1 LTS","kernelVersion":"6.8.0-51-generic",
"uptime":"12 days","diskSpace":{"free":"9.8G","total":"229.6G"},
"memory":{"free":"5.6G","total":"15.5G"},"processes":{"running":214}}}]Es decir, no hace falta preguntar por uname -a, df -h, free -h ni uptime: las respuestas ya han llegado. El agente llama a list-servers una vez y lee el estado desde allí.
Las sondas pasan por los guardias una a una. Con la lista blanca, en el estado solo quedarán los campos permitidos. Un estado incompleto no significa que el host esté inaccesible.
Un comando exitoso sin salida devuelve [exit code] 0, no una cadena vacía. Una respuesta vacía el modelo la lee como un resultado poco claro y va a verificar de nuevo con echo $?, lo que supone una sesión extra al servidor y tokens adicionales.
Inicio rápido: un servidor para todo el parque
Configuración del cliente MCP:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"-y",
"@perhamm/ssh-mcp-server",
"--ssh-config-hosts",
"--guards-profile", "safe"
],
"env": {
"SSH_MCP_SUDO_PASSWORD": "..."
}
}
}
}A partir de ahí, el agente funciona así:
Llama a
list-ssh-hostsy encuentra el alias necesario, por ejemplor-ulybka-prod-master. En configuraciones grandes la lista se recorta, por lo que el agente pasafilter: una subcadena o un patrón del tipor-ulybka-*.Llama a
execute-commandconconnectionName: "r-ulybka-prod-master".El servidor lee el alias de
~/.ssh/config, toma de allíHostName,User,Port,IdentityFileyProxyJump, establece la conexión y ejecuta el comando.
La clave no abandona la máquina: el servidor lee el archivo por sí mismo; en el diálogo solo aparece la ruta de la configuración SSH. Si no se especifica IdentityFile, se toma el ssh-agent de SSH_AUTH_SOCK. Un alias sin HostName se conecta por su propio nombre, como hace ssh.
Solo es alcanzable el alias que esté declarado en la configuración como bloque Host independiente. El bloque Host * proporciona valores por defecto, pero no convierte un nombre arbitrario en un host alcanzable.
La lista de alias se puede acotar:
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--ssh-config-hosts",
"--allowed-hosts", "r-ulybka-*,*-stage-*",
"--ssh-config-file", "/home/user/.ssh/config_work"
]Los patrones admiten * y ?. Si el alias no coincide con ningún patrón, la conexión no se establece y el agente recibe el error SSH_HOST_NOT_ALLOWED.
Modo seguro y guardias
Los guardias son un conjunto versionado de reglas que verifica cada comando antes de enviarlo al servidor. Las reglas están en guards/default-guards.json y se actualizan junto con el repositorio.
Perfiles
Perfil | Comportamiento |
| Las reglas del perfil están desactivadas; solo funciona el núcleo prohibido. Valor por defecto |
| Además prohíbe comandos destructivos; el resto lo permite |
| Solo permite lectura y diagnóstico; hereda todas las prohibiciones de |
"args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"]Lo que safe detecta además del núcleo: shutdown y reboot, reinicio del firewall, detención de sshd y kubelet, kubectl delete, helm uninstall, docker system prune, eliminación de paquetes, DROP DATABASE, curl | sh, git push --force, limpieza de logs, descarga de módulos del kernel, editores interactivos. La lista completa con motivos está en el JSON.
readonly además exige que cada parte del comando esté en la lista blanca: ls, cat, grep, find, ps, ss, df, journalctl, systemctl status, kubectl get/describe/logs, docker ps/logs y similares. En este perfil sudo está completamente prohibido, junto con su, doas y pkexec.
Núcleo prohibido
Parte de las operaciones nunca se ejecutan: ni en el perfil off, ni con sudo, ni mediante un archivo de guardias propio, ni a través de SFTP para eludir los comandos. La lista vive en el bloque forbidden.
Categoría | Qué queda cerrado |
Cuentas |
|
sudo | Escritura en |
Programaciones |
|
systemd | Escritura de unidades y temporizadores en |
SSH | Edición de |
Intérpretes |
|
Borrado masivo |
|
Discos y secretos |
|
El trabajo habitual sigue funcionando: crontab -l, cat /etc/ssh/sshd_config, systemctl restart nginx, rm -rf /var/lib/myapp/cache/tmp pasan. Un bash -c "..." analizable también funciona: su contenido se verifica con las mismas reglas.
El núcleo también cierra las herramientas de archivos. download no tomará /etc/shadow ni el contenido de ~/.ssh, y allowedRemotePaths no puede revertir eso. El lado local también está protegido: download no colocará un archivo en nuestro propio ~/.ssh.
La carga de archivos está completamente desactivada. La herramienta upload no se publica hasta que se pasa --enable-upload, y el perfil readonly rechaza la carga incluso con esa bandera.
Si el servidor se necesita precisamente para crear usuarios o editar el cron, el núcleo habrá que modificarlo en el fork de forma consciente: no existe una bandera que lo desactive.
Por qué no se elude con un punto y coma
El comando se divide en partes por ;, |, &&, ||, &, saltos de línea y sustituciones $(...), y cada parte se verifica por separado. Las comillas se tienen en cuenta al analizar. Así, ls; rm -rf / no pasa en ningún perfil, aunque la línea completa empiece por el permitido ls.
Los envoltorios se eliminan antes de la verificación: sudo, env, timeout 5, nohup y asignaciones del tipo LC_ALL=C no ocultan el comando a las reglas. El script dentro de bash -c "..." se analiza por separado y se verifica con las mismas reglas. La longitud del comando está limitada a 5000 caracteres.
Los guardias cubren errores del agente, no una evasión intencionada. Un intérprete con código arbitrario dentro, como python -c, las reglas no lo analizarán. Allí donde la evasión sea inaceptable, limitamos los permisos del propio usuario SSH.
Actualización de reglas
Tres formas de mantener las reglas al día:
Fusionamos el upstream en nuestro fork. El archivo de reglas está versionado con el campo
version; la versión se ve enlist-serversy en el texto de rechazo.Mantenemos nuestro propio archivo y lo indicamos con
--guards-file /etc/ssh-mcp/guards.json. Las reglas de ese archivo se añaden a las integradas; la versión pasa a ser2026.08.19+local-1.Actualizamos el archivo según un horario:
node scripts/update-guards.js https://example.com/guards.json /etc/ssh-mcp/guards.jsonEl script verifica el JSON y compila cada expresión regular, y solo entonces reemplaza el archivo. Una descarga corrupta no rompe el conjunto de reglas en funcionamiento.
Formato de nuestro propio archivo:
{
"version": "local-1",
"profiles": {
"safe": {
"deny": [
{ "id": "no-ansible", "pattern": "^ansible-playbook\\b", "reason": "выкат идёт из CI" }
]
}
}
}El campo scope: "command" obliga a la regla a verificar el comando completo, no por partes. Así funcionan las reglas sobre curl | sh y SQL. En el bloque forbidden de nuestro propio archivo se pueden añadir prohibiciones propias, pero las integradas no se pueden quitar: las listas se suman.
Los antiguos --whitelist y --blacklist no han desaparecido y se verifican antes que los guardias.
sudo sin contraseña en el diálogo
La contraseña de sudo está en la variable de entorno del proceso del servidor. El agente envía sudo: true, pero no ve la contraseña ni en los argumentos de la llamada ni en la salida.
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"],
"env": {
"SSH_MCP_SUDO_PASSWORD": "..."
}
}
}
}Llamada a la herramienta:
{
"tool": "execute-command",
"params": {
"cmdString": "systemctl restart nginx",
"connectionName": "r-ulybka-prod-master",
"sudo": true
}
}El comando viaja al servidor como sudo -S -k -p '' -u root -- /bin/sh -c '<команда>' y la contraseña se escribe en el stdin del canal. No aparece en la línea de comandos, por lo que no llega a ps ni al historial. El pseudoterminal se desactiva para estos comandos; de lo contrario, la tty haría eco de la entrada en la salida. Por si acaso, la contraseña se elimina de la salida y del texto de los errores.
El nombre de la variable y del usuario de destino se cambian con las opciones --sudo-password-env y --sudo-user. Si la variable está vacía, la llamada falla con SUDO_PASSWORD_MISSING incluso antes de conectarse. El perfil readonly prohíbe sudo por completo.
En el modo shell, la contraseña se añade en una línea aparte justo después del comando, porque sudo lee el mismo stdin que el propio shell. La opción -k garantiza que la contraseña se pida siempre y que la línea no se ejecute como comando. Para sudo es mejor el modo exec.
Túneles
open-tunnel levanta un listener local y envía el tráfico a través de la conexión SSH. Resulta útil cuando no hay acceso directo a los servicios del clúster, pero sí al nodo.
SOCKS5 en el puerto 8777:
{
"tool": "open-tunnel",
"params": {
"type": "socks5",
"localPort": 8777,
"connectionName": "r-ulybka-prod-master"
}
}A partir de ahí, cualquier cliente pasa por el proxy; los nombres se resuelven en el lado remoto:
curl --socks5-hostname 127.0.0.1:8777 http://prometheus.monitoring.svc:9090/api/v1/query?query=up
kubectl --request-timeout=30s ... # через HTTPS_PROXY=socks5h://127.0.0.1:8777Reenvío de un puerto, equivalente a ssh -L:
{
"tool": "open-tunnel",
"params": {
"type": "local",
"localPort": 15432,
"remoteHost": "pg-master.internal",
"remotePort": 5432
}
}Si no se indica localPort, el sistema elige un puerto y lo devuelve en la respuesta. Los túneles viven hasta close-tunnel, hasta que se interrumpe la conexión SSH o hasta que se detiene el servidor.
Las restricciones se definen con las opciones:
Opción | Valor por defecto | Qué hace |
|
| Dirección en la que escuchan los túneles |
| sin restricciones | Lista de puertos que se pueden ocupar |
| 8 | Cuántos túneles mantenemos a la vez |
| desactivado | Quita las herramientas de túnel de la lista |
El listener se levanta en loopback por defecto. Una dirección más amplia que loopback expone el proxy a tu red, así que debe cambiarse con conocimiento de causa.
Verificación de claves de host
La clave del servidor se comprueba contra known_hosts en cada conexión, incluidos los hosts intermedios de la cadena ProxyJump. Por defecto el modo es strict: que el host no esté en known_hosts significa rechazo.
Modo | Comportamiento |
| Por defecto. Solo nos conectamos a hosts de |
| Un host desconocido se registra en la primera conexión; la discrepancia de clave sigue siendo un rechazo |
| No hay comprobación; comportamiento del upstream |
Se comprueban ~/.ssh/known_hosts, ~/.ssh/known_hosts2 y /etc/ssh/ssh_known_hosts; para un alias con UserKnownHostsFile, se comprueba el archivo indicado en la configuración SSH. La lista propia se define con la opción --known-hosts-file. Se admiten registros con hash, patrones, el formato [host]:port y la marca @revoked.
El rechazo llega con el código SSH_HOST_KEY_REJECTED y un texto con la huella:
Host key of prod.example.com is not in known_hosts (~/.ssh/known_hosts): ssh-ed25519 SHA256:xxxx.
Verify that fingerprint, add the host to known_hosts, or start the server with --host-key-checking accept-new.La discrepancia de clave no se acepta nunca, en ningún modo: el servidor se niega a conectar y escribe que el host ha sido recreado o que alguien se ha interpuesto en medio.
Para la primera toma de contacto con el parque de máquinas, conviene pasar una vez con --host-key-checking accept-new y luego volver a strict.
Log de auditoría
Cada llamada se escribe como una línea JSON: comando, conexión, opción sudo, veredicto de la guarda, duración y volumen de salida. El contenido de la salida no entra en el log; la contraseña de sudo se elimina.
{"time":"2026-08-19T08:12:44.101Z","pid":8123,"event":"command","result":"blocked","connection":"r-ulybka-prod-master","command":"useradd deploy","sudo":true,"code":"COMMAND_VALIDATION_FAILED","reason":"Blocked by the forbidden core ..."}
{"time":"2026-08-19T08:12:51.880Z","pid":8123,"event":"command","result":"ok","connection":"r-ulybka-prod-master","command":"systemctl status nginx","sudo":false,"durationMs":412,"bytes":1840}Se registran los eventos connect, command, download, upload, tunnel-open, tunnel-close y host-key.
Por defecto, el archivo se encuentra en $XDG_STATE_HOME/ssh-mcp-server/audit.jsonl, es decir, normalmente ~/.local/state/ssh-mcp-server/audit.jsonl, con permisos 0600.
Opción | Por defecto | Qué hace |
| directorio de estado XDG | Ruta al log; el valor |
| 10485760 | Tamaño tras el cual el archivo se rota. |
| 10 | Cuántos archivos gzip conservamos |
La rotación está integrada: al alcanzar el límite, el archivo actual pasa a audit.jsonl.1.gz, los archivos antiguos se desplazan y se elimina todo lo que quede fuera de --audit-keep. Diez archivos de 10 MiB suponen unos cien megabytes sin comprimir y bastante menos después de gzip.
Si los logs ya los gestiona logrotate, ponemos --audit-max-size 0 y configuramos la rotación con el modo copytruncate.
Un error de escritura no hace fallar el comando: el servidor lo escribe una vez en stderr y sigue funcionando.
Métodos de conexión
A continuación, escenarios de menor a mayor complejidad. En args, cada opción y su valor son dos elementos separados del array: "--host", "192.168.1.1", no "--host 192.168.1.1".
Usuario y contraseña
{
"mcpServers": {
"ssh-mcp-server": {
"command": "npx",
"args": [
"-y",
"@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--port", "22",
"--username", "root",
"--password", "pwd123456"
]
}
}
}Clave privada
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--privateKey", "~/.ssh/id_rsa",
"--passphrase", "pwd123456"
]La contraseña de la clave no es necesario escribirla en la configuración; se puede poner en la variable SSH_MCP_PASSPHRASE.
Un alias de ~/.ssh/config
"args": ["-y", "@perhamm/ssh-mcp-server", "--host", "myserver"]El servidor lee HostName, Port, User, IdentityFile y ProxyJump del bloque Host myserver, incluidas las directivas Include y los patrones. Las opciones de línea de comandos tienen prioridad: --port 2222 anula el puerto de la configuración.
Bastión y ProxyJump
Si el alias tiene ProxyJump, la cadena se levanta sola:
Host r-ulybka-prod-master
HostName 10.20.30.40
User ops
ProxyJump bastion
IdentityFile ~/.ssh/prod_keyCada salto siguiente se conecta a través del canal del anterior, como hace ssh -J. La cadena también se puede indicar manualmente: --proxy-jump "bastion,gateway:2222". La profundidad de la cadena está limitada a cinco saltos.
Proxy
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--password", "pwd123456",
"--proxy", "socks5://user:pwd@proxy-host:1080"
]Se admiten socks://, socks5://, http:// y https://. HTTP y HTTPS usan el método CONNECT con autenticación Basic; el puerto por defecto es 80 y 443. Para SOCKS5, el puerto es obligatorio. La antigua opción --socksProxy sigue funcionando, pero solo acepta SOCKS. --proxy y --proxy-jump no se usan juntos.
Host de salto con shell interactivo
transportMode por defecto es exec. Cambiamos a shell si, tras un inicio de sesión correcto, los comandos no se ejecutan o el dispositivo solo ofrece una sesión interactiva:
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "bastion.example.com",
"--username", "ops",
"--password", "pwd123456",
"--transport-mode", "shell",
"--shell-ready-timeout", "15000"
]En el modo shell, los comandos pasan en cola por una única sesión persistente, y upload y download no funcionan: en ese modo SFTP está desactivado.
Autenticación de dos factores
La opción --try-keyboard activa keyboard-interactive. La contraseña y la clave se rellenan automáticamente; el código del segundo factor se lee de la variable SSH_MCP_2FA_CODE.
Varias conexiones en un mismo servidor
Además de los alias de la configuración SSH, queda el método antiguo: un archivo con la descripción de las conexiones.
[
{
"name": "dev",
"host": "1.2.3.4",
"port": 22,
"username": "alice",
"privateKey": "~/.ssh/dev_key",
"guardProfile": "safe",
"commandTimeoutMs": 120000
},
{
"name": "prod",
"host": "5.6.7.8",
"port": 22,
"username": "bob",
"privateKey": "~/.ssh/prod_key",
"guardProfile": "readonly",
"allowedRemotePaths": ["/var/log", "/tmp"]
}
]"args": ["-y", "@perhamm/ssh-mcp-server", "--config-file", "/abs/path/ssh-config.json"]También se admite el formato de objeto en el que la clave es el nombre de la conexión. La conexión se selecciona con el parámetro connectionName; sin él, se toma la primera.
Restricciones de comandos y rutas
Listas blanca y negra
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--privateKey", "~/.ssh/id_rsa",
"--whitelist", "^ls( .*)?,^cat .*,^df.*",
"--blacklist", "^rm .*,^shutdown.*"
]Los patrones son expresiones regulares separadas por comas. El comando se comprueba primero contra la lista blanca, luego contra la negra y después contra el perfil de guardas, y debe superar las tres comprobaciones.
Plantilla de comando
--command-template envuelve cada comando. <quotedCommand> sustituye el comando como un argumento escapado; <command> lo inserta tal cual. La plantilla se aplica después de la sustitución del directorio de trabajo.
su root -c <quotedCommand>
docker exec -i mycontainer sh -c <quotedCommand>Rutas para operaciones con archivos
--allowed-local-paths amplía la lista de directorios locales disponibles para upload y download (por defecto, solo el directorio actual). --allowed-remote-paths limita las rutas remotas; ahí se escriben rutas POSIX absolutas separadas por comas. Sin esta opción, SFTP ve todo el sistema de archivos del host; el servidor lo advierte al arrancar.
Timeouts y límite de salida
Parámetro | Por defecto | Qué limita |
| no | Un solo comando; anula la configuración de la conexión |
| 30000 | El comando en modo |
| 30000 | El comando en modo |
| 30000 | El establecimiento de la conexión y el handshake |
| 300000 | Las operaciones SFTP |
| 10485760 | La salida capturada de un comando |
| 10000 | El intervalo de keepalive |
Al superar el límite de salida, el comando se interrumpe y la herramienta devuelve OUTPUT_LIMIT_EXCEEDED junto con el fragmento ya recopilado. Los errores llegan con una estructura formada por code, message y retriable.
Opciones de línea de comandos
--config-file <path> Файл с описанием соединений
--ssh-config-file <path> Путь к SSH-конфигу (по умолчанию ~/.ssh/config)
--ssh <config> Соединение как JSON или пары key=value
-h, --host <host> Хост или алиас из SSH-конфига
-p, --port <port> Порт
-u, --username <name> Пользователь
-w, --password <password> Пароль
-k, --privateKey <path> Путь к приватному ключу
-P, --passphrase <passphrase> Пароль от ключа
-a, --agent <path> Сокет ssh-agent
-W, --whitelist <patterns> Белый список команд, через запятую
-B, --blacklist <patterns> Чёрный список команд, через запятую
--proxy <url> Прокси SOCKS5, HTTP или HTTPS
-s, --socksProxy <url> Старый флаг только для SOCKS5
--allowed-local-paths <paths> Локальные каталоги для upload и download
--allowed-remote-paths <paths> Удалённые каталоги для SFTP
--transport-mode <mode> exec или shell (по умолчанию exec)
--shell-ready-timeout <ms> Таймаут готовности shell (по умолчанию 10000)
--command-template <template> Шаблон с <command> или <quotedCommand>
--pty Псевдотерминал для exec (по умолчанию включён)
--try-keyboard Keyboard-interactive для 2FA
--pre-connect Подключиться ко всем хостам при старте
--ssh-config-hosts Разрешить хосты из SSH-конфига на лету
--allowed-hosts <patterns> Шаблоны разрешённых алиасов, через запятую
--proxy-jump <chain> Цепочка ProxyJump, через запятую
--guards-profile <name> off, safe или readonly (по умолчанию off)
--guards-file <path> Свой набор правил поверх встроенного
--sudo-password-env <var> Переменная с паролем sudo
--sudo-user <user> Пользователь для sudo (по умолчанию root)
--host-key-checking <mode> strict, accept-new или off (по умолчанию strict)
--known-hosts-file <paths> Свои файлы known_hosts, через запятую
--host-key-algorithms <list> Алгоритмы хост-ключа, через запятую
--enable-upload Опубликовать инструмент upload (по умолчанию выключен)
--audit-log <path|off> Путь к аудит-логу (по умолчанию каталог состояния XDG)
--audit-max-size <bytes> Порог ротации, 0 отключает (по умолчанию 10485760)
--audit-keep <count> Сколько архивов держим (по умолчанию 10)
--disable-tunnels Убрать туннельные инструменты
--tunnel-bind-address <addr> Адрес для туннелей (по умолчанию 127.0.0.1)
--allowed-tunnel-ports <ports> Разрешённые порты туннелей, через запятую
--max-tunnels <count> Лимит одновременных туннелей (по умолчанию 8)
--version, -v Версия пакета
--help СправкаSeguridad
Para producción activamos
--guards-profile safe; para el análisis de incidentes de guardia sirvereadonly. Conoff, solo permanece un núcleo de comandos prohibidos; todo lo demás se ejecutará, algo que el servidor advierte en el log.La clave, su contraseña y la contraseña de sudo se leen de archivos y variables de entorno. En la configuración del cliente MCP guardamos la ruta a la clave, no la clave en sí.
Los túneles escuchan en loopback. SOCKS5 no tiene autenticación, por lo que un proxy en
0.0.0.0abre la red interna a cualquiera que pueda alcanzar el puerto; el servidor escribe una advertencia al respecto al arrancar.Sin
--allowed-remote-paths, a través de SFTP se lee y se escribe cualquier ruta del host, incluida~/.ssh/authorized_keys.La clave del host se comprueba contra
known_hostsen modostrict. Solo merece la pena desactivar la comprobación con--host-key-checking offen un laboratorio.No hay límites de frecuencia de llamadas.
Desarrollo
npm install
npm run build
npm testLos tests se ejecutan con el runner integrado de Node.js y están en test/.
Upstream y licencia
El proyecto surgió de classfang/ssh-mcp-server (autor junki.cn), con licencia ISC. El copyright del upstream se conserva en LICENSE, donde también está el enlace al repositorio original.
El conjunto de guardas está parcialmente inspirado en las ideas de tufantunc/ssh-mcp (MIT).
El paquete en NPM: @perhamm/ssh-mcp-server.
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 Servers
- AlicenseBqualityFmaintenanceAn MCP server that allows AI models to execute system commands on local machines or remote hosts via SSH, supporting persistent sessions and environment variables.13228MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables remote SSH command execution and bidirectional file transfers through a standardized interface. It allows AI assistants to securely manage remote servers while keeping credentials isolated and applying command-level security controls.ISC
- AlicenseAqualityBmaintenanceMCP server for managing multiple SSH servers via AI assistants, offering tools for remote command execution, file operations, and system monitoring.11MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI agents SSH capabilities to execute commands, transfer files, and inspect remote systems through a preconfigured host list.43MIT
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server connecting AI agents to non-custodial staking data across 130+ networks.
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/perhamm/ssh-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server