Python SSH MCP

Un servidor MCP SSH escrito en Python. Que se basa en una capa sofisticada de herramientas y permisos. Incluye Skills, conjunto de herramientas Docker y Systemctl, y algunos runbooks.

Documentación

Python SSH MCP

Python FastMCP License Tests

Un servidor MCP SSH construido en Python sobre FastMCP. El objetivo: darle a un LLM acceso SSH real a muchos hosts mientras se mantiene un control fino sobre lo que puede y no puede hacer. La superficie de configuración es deliberadamente amplia — probablemente excesiva si solo quieres una única herramienta ssh_exec, pero vale la pena una vez que empiezas a conectar más de un host o a restringir al agente a rutas, comandos y niveles de visibilidad específicos. Si una herramienta que necesitas no está aquí, abre un issue.

Actualmente implementado: 100 herramientas en 10 grupos, 1649 pruebas unitarias que pasan + 6 pruebas de integración con sshd dockerizado + una suite tests/e2e/ opcional que ejecuta cada herramienta contra el hosts.toml real del operador. known_hosts estricto por defecto, confinamiento por lista de permitidos de rutas en cada herramienta que maneja rutas, registro de auditoría con hash SHA-256, hooks conectables por el operador. Política de redacción de secretos que permite al LLM leer archivos de configuración sin ver los secretos (marcadores de hash HMAC-SHA256; redact_paths_globs con modos de bypass block/warn/audit_only). Cinco herramientas de nivel sudo que manejan rutas y respetan la política de rutas bajo sudo (read/read_redacted/write/edit/sftp_list). Modo de transmisión a disco local en upload/deploy/download/sudo_write para que archivos grandes eviten el canal base64 del LLM. La mayoría de las herramientas devuelven resultados Pydantic tipados para que los clientes MCP vean esquemas reales en tools/list (no object genéricos); las pocas que legítimamente producen cargas útiles fusionadas o bimodales permanecen como dict[str, Any] con la justificación documentada en la función. Destinos SSH POSIX soportados de extremo a extremo; destinos SSH Windows soportados para SFTP + operaciones de archivos + ssh_file_hash vía PowerShell -EncodedCommand (ver ADR-0023); CLI de Docker intercambiable por Podman vía SSH_DOCKER_CMD / docker_cmd por host.

Contenido

En este archivo:

Inicio rápido

  • Instala python-ssh-mcp
  • Escribe tu primera entrada de hosts.toml (Tutorial §3)
  • Configura tu cliente MCP (Claude Desktop, Claude Code, Cursor, ...)
  • Pide al LLM que ejecute ssh_host_ping contra tu objetivo — verifica agente + known_hosts + pool de extremo a extremo
  • Activa los indicadores de nivel que necesites (ALLOW_LOW_ACCESS_TOOLS, ALLOW_DANGEROUS_TOOLS, ALLOW_SUDO) y el LLM desbloqueará operaciones de archivos, exec, sudo — ver CONFIGURATION.md → Niveles de acceso

CONFIGURATION.md — configuración de más hosts, niveles de acceso, lista de permitidos/bloqueados, grupos de herramientas, Docker/Podman, identidad SSH por host, gestión de known_hosts, sudo. ADVANCED.md — runbooks (FastMCP Skills), hooks, observabilidad, pruebas, rotación de claves, arquitectura, contribución.

Características

  • Servidor compatible con MCP que expone SSH sobre stdio (o HTTP si lo prefieres); el transporte habla MCP directamente, sin shim.
  • Modelo de acceso de cuatro nivelesread / low-access / dangerous / sudo. Cada nivel se activa con su propio indicador de entorno y se aplica mediante transformaciones Visibility de FastMCP. Por defecto: solo lectura.
  • Diez grupos de herramientas ortogonales a los niveles (host, session, sftp-read, file-ops, exec, sudo, shell, docker, systemctl, pkg). SSH_ENABLED_GROUPS recorta el catálogo a lo que un asistente dado realmente necesita.
  • 100 herramientas: ver TOOLS.md para la referencia completa por herramienta. Destacados:
    • Sondas de solo lectura (ping, información del host, uso de disco, procesos, alertas, verificación de known-hosts, información de usuario, notas del host, información del servidor)
    • Recurso mcp://ssh-mcp/server-info + herramienta de respaldo ssh_server_info — identidad del servidor + superficie de capacidades para que el LLM (o el operador) pueda auto-inspeccionar "qué versión es este servidor / qué niveles están desbloqueados / cuántas herramientas son visibles" sin revisar el catálogo (v1.5.0)
    • Lecturas SFTP (list, stat, download, find, file_hash) con confinamiento de realpath remoto
    • ssh_read_redacted — lee configuraciones (.env, .yml, ...) con secretos reemplazados en línea por marcadores de hash HMAC-SHA256 para que el LLM obtenga información estructural pero nunca el texto plano (v1.4.0)
    • Operaciones de archivos de bajo acceso (cp, mv, mkdir, delete, delete_folder, edit, patch, upload, deploy, link, transfer) — primero SFTP, escrituras atómicas. upload/deploy/sftp_download soportan local_path= para transmitir archivos grandes sin idas y vueltas base64 (v1.3.0)
    • Nivel exec con tiempo de espera por llamada, variante de transmisión, difusión entre hosts y una hoja de referencia activada por defecto que detecta cat/tee/sudo cat/... y redirige a la herramienta nativa correcta
    • Nivel sudo — ssh_sudo_exec más cinco herramientas de nivel sudo que manejan rutas (ssh_sudo_read, _read_redacted, _write, _edit, _sftp_list) para que los archivos propiedad de root permanezcan dentro de la política de rutas en lugar de eludirla vía sudo cat crudo (v1.4.0). Contraseña enviada por stdin, nunca por argv; contraseñas en entorno rechazadas de forma estricta al inicio
    • 27 herramientas Docker (ps, logs, inspect, stats, events, system_df, images, volumes, compose up/down/logs/..., ciclo de vida de contenedores, exec, run, prune)
    • 17 herramientas systemctl (lectura + mutaciones de ciclo de vida) y 8 ayudantes journalctl/list
    • 9 herramientas APT/paquetes — lectura (apt_list, apt_search, apt_show, apt_show_holds) + mutaciones (apt_install, apt_upgrade, apt_remove, apt_autoremove, apt_mark). Los hosts no Debian reciben un PlatformNotSupported limpio
    • Sesiones de shell persistentes con seguimiento de cwd (sin PTY remoto, estado basado en centinelas)
  • known_hosts estricto — sin auto-aceptación; claves desconocidas o no coincidentes fallan de forma segura.
  • Confinamiento de rutas en todo — cada herramienta que maneja rutas canonicaliza vía realpath remoto (o realpath SFTP en Windows) y verifica la lista de permitidos, con exclusiones restricted_paths para zonas sensibles.
  • Política por host en hosts.toml — usuarios, claves, listas de permitidos, modo sudo, plataforma, cadenas de proxy, umbrales de alerta, exclusión de sesiones persistentes.
  • Soporte de destinos SSH Windows para SFTP + operaciones de archivos (ver ADR-0023); las herramientas solo POSIX rechazan destinos Windows con un PlatformNotSupported limpio que nombra la capacidad faltante.
  • Registro de auditoría — una línea JSON por llamada de herramienta (todos los niveles), rutas/comandos con hash SHA-256, el campo error es solo la clase de excepción (el texto completo permanece en DEBUG localmente).
  • Hooks del operador: importa cualquier módulo vía SSH_HOOKS_MODULE para eventos STARTUP / SHUTDOWN / PRE_TOOL_CALL / POST_TOOL_CALL. Tiempo de espera acotado por hook, aislamiento de excepciones, advertencia de acumulación cuando las tareas pendientes se amontonan.
  • Runbooks vía FastMCP Skills — archivos SKILL.md por herramienta dan al LLM documentación práctica y acotada bajo demanda.
  • Búsqueda de herramientas BM25 (opcional) — reemplaza tools/list con search_tools + call_tool una vez que 50+ esquemas empiezan a consumir contexto.
  • Resumen del catálogo de herramientas registrado al inicio (conteos por nivel y por grupo) para que los operadores vean exactamente lo que se le ofrecerá al LLM.

Instalación

Python SSH MCP es un paquete Python estándar PEP 621 (backend de compilación hatchling). Usa el instalador que prefieras — uv es la ruta recomendada:

uv sync                      # create .venv + install runtime deps + dev extras
uv run ssh-mcp               # start the server on stdio

# Or without syncing a venv first — build + run in an ephemeral environment:
uvx --from . ssh-mcp

# Plain pip also works (PEP 517):
pip install -e ".[dev]"
ssh-mcp

# FastMCP shortcuts (once the package is installed):
fastmcp dev inspector        # dev UI: MCP Inspector + hot reload; auto-finds fastmcp.json
fastmcp run                  # run the server; auto-finds fastmcp.json
fastmcp run -t http -p 8000  # HTTP transport instead of stdio

Grupos de dependencias opcionales:

  • .[tasks] — añade el cliente Redis (redis>=5.0.0) para un backend de tareas de producción. El runtime de tareas FastMCP en sí (docket, en memoria por defecto) es una dependencia dura vía fastmcp[tasks] y se incluye de todos modos — instala este extra solo cuando apuntes FASTMCP_DOCKET_URL a un Redis real (la pérdida de tareas al reiniciar importa en producción con ALLOW_DANGEROUS_TOOLS=true; ver _warn_task_backend).
  • .[telemetry] — distro OpenTelemetry + exportador OTLP.
  • .[dev] — pytest, ruff, mypy.

Los clientes MCP (Claude Desktop, Claude Code, Cursor) descubren el servidor vía fastmcp.json.

Configuración del cliente

Cada cliente MCP importante acepta un fragmento JSON que le dice cómo iniciar el servidor. La forma está estandarizada alrededor de un objeto mcpServers — solo la ruta del archivo difiere por cliente. Elige tu cliente, pega el fragmento en el archivo correcto, reinicia el cliente para que el subproceso se reinicie.

Aviso: el bloque deployment.env de fastmcp.json (si mantienes uno en el proyecto) anula el entorno del cliente incondicionalmente — mantén los indicadores de nivel fuera de ese bloque y deja que vengan de la configuración del cliente o de tu .env. Si el cliente parece mantener un subproceso obsoleto después de cambios de código, ver Solución de problemas — la mayoría de los clientes inician y poseen el subproceso del servidor, por lo que un reinicio del lado del terminal no es suficiente.

El fragmento base (usado por Claude Desktop, Cursor, Windsurf, Kilocode — la mayoría de los clientes hablan este dialecto):

{
  "mcpServers": {
    "ssh-mcp": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/Nightreaver/python-ssh-mcp", "ssh-mcp"],
      "env": {
        "LOG_LEVEL": "INFO",
        "ALLOW_LOW_ACCESS_TOOLS": "false",
        "ALLOW_DANGEROUS_TOOLS": "false",
        "ALLOW_SUDO": "false"
      }
    }
  }
}

uvx --from <path> ssh-mcp construye y ejecuta el servidor en un entorno efímero gestionado por uv; no se necesita venv persistente en el lado del cliente. Alternativa: reemplaza con "command": "fastmcp", "args": ["run", "<path-to-clone>/fastmcp.json"] si ya tienes un venv con fastmcp en PATH.

Activa los indicadores ALLOW_* a medida que otorgas capacidades al asistente. Mantén solo lectura como predeterminado y abre los niveles exec/sudo solo donde los necesites.

Claude Desktop

Archivo de configuración:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Pega el fragmento base. Cierra completamente Claude Desktop (icono de bandeja → Quit) y reinícialo — recargar NO reinicia los subprocesos MCP.

Claude Code

Comando CLI, sin necesidad de editar JSON:

claude mcp add --transport stdio ssh-mcp -- uvx --from git+https://github.com/Nightreaver/python-ssh-mcp ssh-mcp

Para control de alcance: --scope user (global), --scope project (confirma .mcp.json al repositorio actual), --scope local (predeterminado, solo este proyecto). Variables de entorno vía indicadores --env KEY=VALUE repetidos, o editando ~/.claude/mcp.json después.

Cursor

Archivo de configuración:

  • Global: ~/.cursor/mcp.json
  • Por espacio de trabajo: <workspace>/.cursor/mcp.json

Misma forma mcpServers que el fragmento base. Cursor detecta los cambios de configuración en la próxima sesión de chat — no se necesita reinicio completo.

VS Code (GitHub Copilot Chat / Agent Mode)

El soporte MCP de VS Code (1.102+) usa una clave ligeramente diferente. Archivo de configuración:

  • Por espacio de trabajo: <workspace>/.vscode/mcp.json
  • Configuración global de usuario: settings.json"mcp.servers"

.vscode/mcp.json del espacio de trabajo:

{
  "servers": {
    "ssh-mcp": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "git+https://github.com/Nightreaver/python-ssh-mcp", "ssh-mcp"],
      "env": {
        "LOG_LEVEL": "INFO",
        "ALLOW_LOW_ACCESS_TOOLS": "false",
        "ALLOW_DANGEROUS_TOOLS": "false",
        "ALLOW_SUDO": "false"
      }
    }
  }
}

Nota que la clave de nivel superior es servers (no mcpServers) y cada entrada lleva un discriminador "type": "stdio". Recarga la ventana de VS Code (Developer: Reload Window) para reiniciar.

Windsurf (Codeium)

Archivo de configuración: ~/.codeium/windsurf/mcp_config.json. Misma forma mcpServers que el fragmento base. Reinicia Windsurf después de editar.

Kilocode

Archivo de configuración: ~/.kilocode/mcp.json (o el equivalente en tu instalación de Kilocode — los documentos de la extensión listan la ruta exacta). Misma forma mcpServers que el fragmento base. Recarga la ventana de VS Code después de editar.

Continue.dev

Archivo de configuración: ~/.continue/config.json. Continue usa una clave anidada:

{
  "experimental": {
    "modelContextProtocolServers": [
      {
        "transport": {
          "type": "stdio",
          "command": "uvx",
          "args": ["--from", "git+https://github.com/Nightreaver/python-ssh-mcp", "ssh-mcp"]
        }
      }
    ]
  }
}

Nota: lista de objetos, no un mapa con nombre. Las variables de entorno van dentro del bloque transport.

Zed

Configuración vía la Paleta de Comandos: assistant: configure context servers, o edita ~/.config/zed/settings.json:

{
  "context_servers": {
    "ssh-mcp": {
      "source": "custom",
      "command": {
        "path": "uvx",
        "args": ["--from", "git+https://github.com/Nightreaver/python-ssh-mcp", "ssh-mcp"],
        "env": {}
      }
    }
  }
}

MCP Inspector (UI de desarrollo)

Para depurar el servidor antes de conectarlo a un cliente real:

fastmcp dev inspector

Detecta automáticamente fastmcp.json, lanza la UI web con un MCP Inspector en vivo adjunto. Recarga en caliente ante cambios de código fuente.


Tutorial — tu primer host en 5 minutos

El camino más rápido: autenticación de agente + un host + nivel de solo lectura. Cinco pasos:

1. Carga tu clave en un agente

  • Linux/macOS: ssh-add ~/.ssh/id_ed25519
  • Windows: inicia Pageant y carga tu .ppk (o ejecuta ssh-agent + ssh-add)

Verifica que el agente sea accesible:

uv run python -c "import asyncio; from ssh_mcp.ssh.agent import list_agent_fingerprints; print(asyncio.run(list_agent_fingerprints()))"

Deberías ver una o más líneas SHA256:.... Copia la que planeas usar; la referenciarás más adelante.

2. Fija la clave de host del objetivo (verifica ANTES de confiar)

La verificación estricta de known_hosts está activada por defecto (sin auto-aceptación). El fijado es un flujo de tres pasos: nunca agregues la salida de ssh-keyscan directamente en known_hosts.

# 2a. Scan to a scratch file. This does NOT trust anything yet.
ssh-keyscan -t ed25519,ecdsa,rsa web01.example.com > /tmp/web01.hostkey

# 2b. Print the fingerprint and compare OUT-OF-BAND.
ssh-keygen -lf /tmp/web01.hostkey
# → 256 SHA256:abc123... web01.example.com (ED25519)

Compara esa SHA256:... contra una fuente de confianza que no sea la red que acabas de escanear: la salida del aprovisionador del host, una sesión de consola, una salida de terraform, el mensaje de Signal del administrador del sistema. Si no coinciden, detente. Un error tipográfico o un MITM fijaría una clave hostil como confiable.

# 2c. Only after the out-of-band fingerprint matches, append and clean up.
cat /tmp/web01.hostkey >> ~/.ssh/known_hosts
rm /tmp/web01.hostkey

El servidor MCP se niega a conectarse si known_hosts falta, está vacío o no coincide.

3. Escribe hosts.toml

Copia la plantilla inicial anotada y edítala:

cp hosts.toml.example hosts.toml
# Replace the SHA256:REPLACE-WITH-... fingerprints with yours from step 1.

O escríbela desde cero: el bloque mínimo viable:

[defaults]
user = "deploy"

[defaults.auth]
method = "agent"
identity_fingerprint = "SHA256:<paste-your-fingerprint-here>"
identities_only = true

[hosts.web01]
hostname = "web01.example.com"
path_allowlist = ["/opt/app", "/var/log"]

Consulta hosts.toml.example para bastión / salto por proxy, anulaciones de clave por host y el patrón de clave en disco + frase de contraseña del llavero. Para recetas multi-host (bastiones, claves por rol, hosts heredados) consulta CONFIGURATION.md → Configurando más hosts.

Heredando de ~/.ssh/config

Si ya mantienes un ~/.ssh/config poblado (alias de host, ProxyJump, IdentityFile, anulaciones de Ciphers/MACs para equipos heredados), apunta SSH_CONFIG_FILE a él y omite reafirmar esos campos en hosts.toml:

SSH_CONFIG_FILE=~/.ssh/config

Precedencia: hosts.toml siempre gana. ~/.ssh/config solo completa los campos que no configuraste por host: la configuración de OpenSSH no puede ampliar lo que path_allowlist, command_allowlist o la lista de bloqueo de hosts permiten. Los registros de inicio muestran ssh_config: honoring <abs-path> (o una ADVERTENCIA si el archivo falta) para que la configuración incorrecta aparezca de inmediato.

4. Escribe .env

# Start locked down — only read-only tools are active.
ALLOW_LOW_ACCESS_TOOLS=false
ALLOW_DANGEROUS_TOOLS=false
ALLOW_SUDO=false

# Optional safety rail
SSH_HOSTS_BLOCKLIST=

5. Verifica de extremo a extremo

uv run ssh-mcp

Desde un cliente MCP (o desde un shell rápido de Python), llama:

from ssh_mcp.server import mcp_server
# tools: ssh_host_ping, ssh_host_info, ssh_sftp_list, ssh_find, ...

ssh_host_ping(host="web01") debería devolver {reachable: true, auth_ok: true, latency_ms: N, ...}.

Si falla, consulta Solución de problemas.


Solución de problemas

no SSH agent reachable

El orden de resolución del agente es: identity_agent explícito en hosts.toml → variable de entorno SSH_AUTH_SOCK → detección automática de Windows (Pageant / tubería OpenSSH). Verifica:

# Unix / macOS
echo $SSH_AUTH_SOCK
ssh-add -l

# Windows (PowerShell)
Get-Process Pageant -ErrorAction SilentlyContinue
uv run python -c "import asyncio; from ssh_mcp.ssh.agent import list_agent_fingerprints; print(asyncio.run(list_agent_fingerprints()))"

identity 'SHA256:...' not found in agent

La huella digital en hosts.toml no coincide con ninguna clave que exponga el agente. Enumera lo que realmente está cargado:

uv run python -c "import asyncio; from ssh_mcp.ssh.agent import list_agent_fingerprints; [print(fp) for fp in asyncio.run(list_agent_fingerprints())]"

Copia una de las huellas digitales reportadas en identity_fingerprint.

HostKeyMismatch / UnknownHost

O la clave del host cambió (rotación o MITM) o a known_hosts le falta la entrada. No omitas esto desde el LLM y no agregues >> un escaneo directamente en known_hosts sin verificación. Usa el flujo de tres pasos de Recorrido §2:

ssh-keyscan -t ed25519,ecdsa <host> > /tmp/h.hostkey
ssh-keygen -lf /tmp/h.hostkey                     # compare fingerprint out-of-band
cat /tmp/h.hostkey >> ~/.ssh/known_hosts && rm /tmp/h.hostkey

HostNotAllowed

El host no está en hosts.toml ni en SSH_HOSTS_ALLOWLIST. La resolución intenta primero la entrada como clave hosts.<alias>, luego contra hosts.*.hostname, luego contra la lista de permitidos del entorno. Agrega una entrada hosts.toml o añade el nombre de host literal a SSH_HOSTS_ALLOWLIST.

HostBlocked

La denegación gana: verifica SSH_HOSTS_BLOCKLIST. Esto es intencional; elimina la entrada si el bloqueo fue un error, pero primero confirma con el operador que la agregó.

PathNotAllowed

La ruta resuelta (canonicalizada) está fuera de cada raíz en path_allowlist. Verifica:

  • ¿Es correcta la ruta? Las herramientas de bajo acceso resuelven los enlaces simbólicos antes de verificar, por lo que un enlace simbólico que apunte fuera de /opt/app será rechazado incluso si el enlace mismo vive allí.
  • ¿Cubre hosts.<name>.path_allowlist el objetivo?

command_allowlist is empty but ALLOW_DANGEROUS_TOOLS=true

El cargador advierte si habilitas exec sin delimitar qué comandos están permitidos. Establece SSH_COMMAND_ALLOWLIST o un command_allowlist vacío por host (explícito = sin restricción).

Herramientas no visibles en el cliente MCP

  • Verifica el nivel: ALLOW_LOW_ACCESS_TOOLS / ALLOW_DANGEROUS_TOOLS / ALLOW_SUDO están denegadas por defecto.
  • Verifica el grupo: SSH_ENABLED_GROUPS (vacío = todas; explícito = filtro).
  • Reinicia el cliente MCP: las listas de herramientas se almacenan en caché por versión del servidor MCP.

Consulta de registros de auditoría

Cada llamada de herramienta escribe una línea JSON en el registrador de Python ssh_mcp.audit — incluidas las herramientas de nivel de lectura (desde v1.4.0, todos los niveles se auditan). No hay una herramienta en proceso para consultar el registro de auditoría — eso es intencional (INC-052): si el LLM pudiera leer su propio rastro de auditoría, un agente comprometido o evadido podría auto-monitorear lo que ha sido atrapado haciendo y ajustarse a su alrededor. La auditoría fluye en una sola dirección hacia los operadores.

Conecta ssh_mcp.audit al sumidero de tu elección (archivo, Loki, Splunk, Datadog, journald, ...) en tu propia configuración de registro. Para depuración local o triaje rápido de incidentes, escribe las líneas en un archivo y consulta con jq:

# In your own bootstrap (or a custom run_server wrapper)
import logging
h = logging.FileHandler("/var/log/ssh-mcp/audit.jsonl")
h.setFormatter(logging.Formatter("%(message)s"))
logging.getLogger("ssh_mcp.audit").addHandler(h)

Cada línea es un único objeto JSON compacto. Esquema:

campotiponotas
tsfloatsegundos de época Unix
correlation_idstr16 caracteres hexadecimales; se empareja con la línea de error completo a nivel DEBUG en ssh_mcp.audit
toolstrEl nombre de la herramienta MCP (p. ej. ssh_exec_run, ssh_broadcast)
tierstrread / low-access / dangerous / sudo
hoststrNombre de host resuelto (o ? para herramientas de fan-out como ssh_broadcast)
resultstrok / error
duration_msintDuración en tiempo real de la llamada a la herramienta
path_hashstrsha256:<16hex> de la ruta canónica (cuando la herramienta tocó una)
command_hashstrsha256:<16hex> del comando redactado (cuando la herramienta ejecutó uno)
exit_codeintCuando corresponda
errorstrSolo el nombre de la clase de excepción: el texto completo permanece en nivel DEBUG (INC-008)

Recetas útiles de jq:

# All errors in the last hour, sorted by tool
jq -r 'select(.result == "error") | "\(.ts) \(.tool) \(.host) \(.error)"' \
  /var/log/ssh-mcp/audit.jsonl | sort -k2

# Slowest dangerous-tier calls (top 20 by duration_ms)
jq 'select(.tier == "dangerous")' /var/log/ssh-mcp/audit.jsonl \
  | jq -s 'sort_by(-.duration_ms) | .[:20] | .[] | {tool, host, duration_ms}'

# Count by tool to see what the LLM is actually using
jq -r '.tool' /var/log/ssh-mcp/audit.jsonl | sort | uniq -c | sort -rn

# Trace one specific call end-to-end via correlation_id
jq 'select(.correlation_id == "a1b2c3d4e5f6abcd")' /var/log/ssh-mcp/audit.jsonl

Los campos command_hash y path_hash son ayudas de deduplicación, no controles de privacidad: los prefijos cortos de SHA-256 son trivialmente vulnerables a tablas rainbow para comandos comunes y rutas canónicas. Si la confidencialidad de la auditoría importa, aplícala mediante cifrado de transporte (TLS a tu backend de registros) y control de acceso en el sumidero mismo.

Descargo de responsabilidad

Python SSH MCP es infraestructura local que otorga a un LLM (o cualquier cliente MCP) la capacidad de ejecutar comandos en sistemas remotos a través de SSH. Úsalo bajo tu propio riesgo. Las banderas de nivel denegadas por defecto y la aplicación estricta de known_hosts protegen contra los peligros obvios, pero ningún software puede proteger contra un operador que activa cada bandera a true sin comprender el radio de explosión.

Lee DECISIONS.md antes de habilitar el nivel peligroso o sudo en producción. Audita las líneas JSON de ssh_mcp.audit de forma regular. Ante la duda, deja un nivel desactivado.

Este proyecto no está afiliado ni respaldado por ningún proveedor de SSH, FastMCP o MCP.


Soporte

Construir y mantener este servidor MCP requiere tiempo y esfuerzo reales, incluso con asistencia de IA. Si este SSH MCP ha facilitado tu flujo de trabajo y tu vida, considera apoyarme:

Problemas, preguntas y comentarios: abre un issue en GitHub. Si encuentras útil Python SSH MCP, considera darle una estrella al repositorio: realmente ayuda.