Python SSH MCP
Um servidor MCP SSH escrito em Python. Que se baseia em uma camada sofisticada de ferramentas e permissões. Incluindo Skills, conjunto de ferramentas Docker e Systemctl e alguns runbooks.
Documentação
Python SSH MCP
Um servidor MCP SSH construído em Python sobre o FastMCP. O objetivo: dar a um LLM acesso SSH real a muitos hosts, mantendo controle fino sobre o que ele pode e não pode fazer. A superfície de configuração é deliberadamente ampla — provavelmente exagero se você só quer uma única ferramenta ssh_exec, mas compensa assim que você começa a conectar mais de um host ou a restringir o agente a caminhos, comandos e níveis de visibilidade específicos. Se uma ferramenta que você precisa não estiver aqui, abra uma issue.
Atualmente implementado:
100 ferramentas em 10 grupos, 1649 testes unitários aprovados + 6 testes de integração com sshd dockerizado + uma suíte tests/e2e/ opcional que aciona todas as ferramentas contra o hosts.toml real do operador. known_hosts estrito por padrão, confinamento por allowlist de caminhos em toda ferramenta que lida com caminhos, log de auditoria com hash SHA-256, hooks plugáveis pelo operador. Política de redação de segredos que permite ao LLM ler arquivos de configuração sem ver os segredos (marcadores de hash HMAC-SHA256; redact_paths_globs com modos de bypass block/warn/audit_only). Cinco ferramentas de nível sudo que lidam com caminhos e respeitam a política de caminhos sob sudo (read/read_redacted/write/edit/sftp_list). Modo de streaming em disco local em upload/deploy/download/sudo_write para que arquivos grandes ignorem o canal base64 do LLM. A maioria das ferramentas retorna resultados Pydantic tipados, para que clientes MCP vejam schemas reais em tools/list (não object genéricos); as poucas que legitimamente produzem payloads mesclados ou bimodais permanecem como dict[str, Any] com a justificativa documentada na função. Alvos SSH POSIX suportados de ponta a ponta; alvos SSH Windows suportados para SFTP + operações de arquivo + ssh_file_hash via PowerShell -EncodedCommand (veja ADR-0023); CLI do Docker substituível por Podman via SSH_DOCKER_CMD / docker_cmd por host.
Conteúdo
Neste arquivo:
- Início Rápido
- Recursos
- Instalação
- Configuração do Cliente
- Passo a passo — seu primeiro host em 5 minutos
- Solução de Problemas
- Aviso Legal
- Suporte
Início Rápido
- Instale o python-ssh-mcp
- Escreva sua primeira entrada de
hosts.toml(Passo a passo §3) - Configure seu Cliente MCP (Claude Desktop, Claude Code, Cursor, ...)
- Peça ao LLM para executar
ssh_host_pingcontra seu alvo — verifica agente +known_hosts+ pool de ponta a ponta - Ative os flags de nível que você precisa (
ALLOW_LOW_ACCESS_TOOLS,ALLOW_DANGEROUS_TOOLS,ALLOW_SUDO) e o LLM desbloqueia operações de arquivo, exec, sudo — veja CONFIGURATION.md → Níveis de acesso
CONFIGURATION.md — configurando mais hosts, níveis de acesso, allowlist/blocklist, grupos de ferramentas, Docker/Podman, identidade SSH por host, gerenciamento de known_hosts, sudo.
ADVANCED.md — runbooks (FastMCP Skills), hooks, observabilidade, testes, rotação de chaves, arquitetura, contribuição.
Recursos
- Servidor compatível com MCP expondo SSH via stdio (ou HTTP, se preferir); o transporte fala MCP diretamente, sem shim.
- Modelo de acesso em quatro níveis —
read/low-access/dangerous/sudo. Cada nível é ativado com seu próprio flag de ambiente e aplicado via transformaçõesVisibilitydo FastMCP. Padrão: somente leitura. - Dez grupos de ferramentas ortogonais aos níveis (
host,session,sftp-read,file-ops,exec,sudo,shell,docker,systemctl,pkg).SSH_ENABLED_GROUPSreduz o catálogo ao que um assistente específico realmente precisa. - 100 ferramentas: veja TOOLS.md para a referência completa por ferramenta. Destaques:
- Sondas somente leitura (ping, informações do host, uso de disco, processos, alertas, verificação de known-hosts, informações do usuário, notas do host, server-info)
- Recurso
mcp://ssh-mcp/server-info+ ferramenta de fallbackssh_server_info— identidade do servidor + superfície de capacidades para que o LLM (ou operador) possa auto-inspecionar "qual versão é este servidor / quais níveis estão desbloqueados / quantas ferramentas estão visíveis" sem vasculhar o catálogo (v1.5.0) - Leituras SFTP (list, stat, download, find, file_hash) com confinamento por realpath remoto
ssh_read_redacted— lê configurações (.env,.yml, ...) com segredos substituídos inline por marcadores de hash HMAC-SHA256, para que o LLM obtenha informações estruturais mas nunca o texto puro (v1.4.0)- Operações de arquivo de baixo acesso (cp, mv, mkdir, delete, delete_folder, edit, patch, upload, deploy, link, transfer) — SFTP primeiro, gravações atômicas.
upload/deploy/sftp_downloadsuportamlocal_path=para transmitir arquivos grandes sem idas e voltas base64 (v1.3.0) - Nível exec com timeout por chamada, variante de streaming, transmissão entre hosts e uma folha de dicas ativada por padrão que captura
cat/tee/sudo cat/... e redireciona para a ferramenta nativa correta - Nível sudo —
ssh_sudo_execmais cinco ferramentas de nível sudo que lidam com caminhos (ssh_sudo_read,_read_redacted,_write,_edit,_sftp_list) para que arquivos de propriedade do root permaneçam dentro da política de caminhos em vez de contorná-la viasudo catbruto (v1.4.0). Senha enviada via stdin, nunca em argv; senhas em variáveis de ambiente rejeitadas na inicialização - 27 ferramentas Docker (ps, logs, inspect, stats, events, system_df, images, volumes, compose up/down/logs/..., ciclo de vida de contêineres, exec, run, prune)
- 17 ferramentas systemctl (leitura + mutações de ciclo de vida) e 8 auxiliares journalctl/list
- 9 ferramentas APT/pacotes — leitura (
apt_list,apt_search,apt_show,apt_show_holds) + mutações (apt_install,apt_upgrade,apt_remove,apt_autoremove,apt_mark). Hosts não-Debian recebem umPlatformNotSupportedlimpo - Sessões de shell persistentes com rastreamento de cwd (sem PTY remoto, estado baseado em sentinela)
known_hostsestrito — sem aceitação automática; chaves desconhecidas ou incompatíveis falham de forma segura.- Confinamento de caminho em tudo — cada ferramenta que lida com caminhos canonicaliza via
realpathremoto (ou realpath SFTP no Windows) e verifica a allowlist, com exceçõesrestricted_pathspara zonas sensíveis. - Política por host em
hosts.toml— usuários, chaves, allowlists, modo sudo, plataforma, cadeias de proxy, limites de alerta, opt-out de sessão persistente. - Suporte a alvos SSH Windows para SFTP + operações de arquivo (veja ADR-0023); ferramentas somente POSIX recusam alvos Windows com um
PlatformNotSupportedlimpo que nomeia a capacidade ausente. - Log de auditoria — uma linha JSON por chamada de ferramenta (todos os níveis), caminhos/comandos com hash SHA-256, o campo
errorcontém apenas a classe da exceção (texto completo permanece em DEBUG localmente). - Hooks do operador: importe qualquer módulo via
SSH_HOOKS_MODULEpara eventosSTARTUP/SHUTDOWN/PRE_TOOL_CALL/POST_TOOL_CALL. Timeout limitado por hook, isolamento de exceções, aviso de backlog quando tarefas pendentes se acumulam. - Runbooks via FastMCP Skills — arquivos
SKILL.mdpor ferramenta dão ao LLM documentação prática e escopada sob demanda. - Busca de ferramentas BM25 (opcional) — substitui
tools/listporsearch_tools+call_toolquando 50+ schemas começam a consumir contexto. - Visão geral do catálogo de ferramentas registrada na inicialização (contagens por nível e por grupo) para que operadores vejam exatamente o que será oferecido ao LLM.
Instalação
Python SSH MCP é um pacote Python padrão PEP 621 (backend de build hatchling). Use o instalador de sua preferência — uv é o caminho recomendado:
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 dependências opcionais:
.[tasks]— adiciona o cliente Redis (redis>=5.0.0) para um backend de tarefas de produção. O runtime de tarefas do FastMCP em si (docket, em memória por padrão) é uma dependência obrigatória viafastmcp[tasks]e acompanha o pacote independentemente — instale este extra apenas ao apontarFASTMCP_DOCKET_URLpara um Redis real (perda de tarefas na reinicialização importa em produção comALLOW_DANGEROUS_TOOLS=true; veja_warn_task_backend)..[telemetry]— distribuição OpenTelemetry + exportador OTLP..[dev]— pytest, ruff, mypy.
Clientes MCP (Claude Desktop, Claude Code, Cursor) descobrem o servidor via fastmcp.json.
Configuração do Cliente
Todo cliente MCP importante aceita um trecho JSON que informa como iniciar o
servidor. O formato é padronizado em torno de um objeto mcpServers — apenas o
caminho do arquivo difere por cliente. Escolha seu cliente, cole o trecho no
arquivo correto, reinicie o cliente para que o subprocesso seja reiniciado.
Atenção: o bloco
deployment.envdofastmcp.json(se você mantiver um no projeto) sobrescreve as variáveis de ambiente do cliente incondicionalmente — mantenha os flags de nível fora desse bloco e deixe que venham da configuração do cliente ou do seu.env. Se o cliente parecer manter um subprocesso obsoleto após mudanças de código, veja Solução de Problemas — a maioria dos clientes inicia e é dona do subprocesso do servidor, então reiniciar apenas o terminal não é suficiente.
O trecho base (usado por Claude Desktop, Cursor, Windsurf, Kilocode — a maioria dos clientes fala esse dialeto):
{
"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 compila e executa o servidor em um ambiente efêmero
gerenciado por uv; nenhum venv persistente é necessário no lado do cliente.
Alternativa: substitua por "command": "fastmcp", "args": ["run", "<path-to-clone>/fastmcp.json"] se você já tiver um venv
com fastmcp no PATH.
Ative os flags ALLOW_* conforme você concede capacidades ao assistente. Mantenha
somente leitura como padrão e abra os níveis exec/sudo apenas onde precisar
deles.
Claude Desktop
Arquivo de configuração:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Cole o trecho base. Saia completamente do Claude Desktop (ícone da bandeja → Quit) e reabra — recarregar NÃO reinicia subprocessos MCP.
Claude Code
Comando CLI, sem necessidade de editar JSON:
claude mcp add --transport stdio ssh-mcp -- uvx --from git+https://github.com/Nightreaver/python-ssh-mcp ssh-mcp
Para controle de escopo: --scope user (global), --scope project (commits
.mcp.json ao repositório atual), --scope local (padrão, apenas este
projeto). Variáveis de ambiente via flags --env KEY=VALUE repetidos, ou editando
~/.claude/mcp.json depois.
Cursor
Arquivo de configuração:
- Global:
~/.cursor/mcp.json - Por workspace:
<workspace>/.cursor/mcp.json
Mesmo formato mcpServers do trecho base. O Cursor capta mudanças de
configuração na próxima sessão de chat — sem necessidade de reinicialização completa.
VS Code (GitHub Copilot Chat / Agent Mode)
O suporte MCP do VS Code (1.102+) usa uma chave ligeiramente diferente. Arquivo de configuração:
- Por workspace:
<workspace>/.vscode/mcp.json - Configurações globais do usuário:
settings.json→"mcp.servers"
.vscode/mcp.json do workspace:
{
"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"
}
}
}
}
Observe que a chave de nível superior é servers (não mcpServers) e cada entrada
carrega um discriminador "type": "stdio". Recarregue a janela do VS Code
(Developer: Reload Window) para reiniciar.
Windsurf (Codeium)
Arquivo de configuração: ~/.codeium/windsurf/mcp_config.json. Mesmo formato mcpServers
do trecho base. Reinicie o Windsurf após editar.
Kilocode
Arquivo de configuração: ~/.kilocode/mcp.json (ou o equivalente na sua instalação
do Kilocode — a documentação da extensão lista o caminho exato). Mesmo formato mcpServers
do trecho base. Recarregue a janela do VS Code após editar.
Continue.dev
Arquivo de configuração: ~/.continue/config.json. O Continue usa uma chave aninhada:
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "git+https://github.com/Nightreaver/python-ssh-mcp", "ssh-mcp"]
}
}
]
}
}
Observe: lista de objetos, não um mapa nomeado. Variáveis de ambiente vão dentro do
bloco transport.
Zed
Configuração via Paleta de Comandos: assistant: configure context servers,
ou edite ~/.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 desenvolvimento)
Para depurar o servidor antes de conectá-lo a um cliente real:
fastmcp dev inspector
Detecta automaticamente fastmcp.json, inicia a UI web com um MCP
Inspector ao vivo anexado. Hot-reload em mudanças de código.
Passo a passo — seu primeiro host em 5 minutos
O caminho mais rápido: autenticação de agente + um host + nível somente leitura. Cinco etapas:
1. Carregue sua chave em um agente
- Linux/macOS:
ssh-add ~/.ssh/id_ed25519 - Windows: inicie o Pageant e carregue sua
.ppk(ou executessh-agent+ssh-add)
Verifique se o agente está acessível:
uv run python -c "import asyncio; from ssh_mcp.ssh.agent import list_agent_fingerprints; print(asyncio.run(list_agent_fingerprints()))"
Você deve ver uma ou mais linhas de SHA256:.... Copie a que pretende usar — você fará referência a ela abaixo.
2. Fixe a chave de host do alvo (verifique ANTES de confiar)
A verificação estrita de known_hosts está ativada por padrão (sem aceitação automática). A fixação é um fluxo de três etapas — nunca acrescente a saída de ssh-keyscan diretamente em 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)
Compare essa SHA256:... com uma fonte confiável que não seja a rede que você acabou de escanear: a saída do provisionador do host, uma sessão de console, uma saída do terraform, a mensagem do sysadmin no Signal. Se não corresponderem, pare. Um erro de digitação ou um MITM fixaria uma chave hostil como confiável.
# 2c. Only after the out-of-band fingerprint matches, append and clean up.
cat /tmp/web01.hostkey >> ~/.ssh/known_hosts
rm /tmp/web01.hostkey
O servidor MCP se recusa a conectar se known_hosts estiver ausente, vazio ou não corresponder.
3. Escreva hosts.toml
Copie o modelo inicial anotado e edite:
cp hosts.toml.example hosts.toml
# Replace the SHA256:REPLACE-WITH-... fingerprints with yours from step 1.
Ou escreva do zero — o bloco mínimo viável:
[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"]
Consulte hosts.toml.example para bastion / proxy-jump, substituições de chave por host e o padrão de chave em disco + senha do keychain. Para receitas multi-host (bastions, chaves por função, hosts legados), consulte CONFIGURATION.md → Configurando mais hosts.
Herdando de ~/.ssh/config
Se você já mantém um ~/.ssh/config populado (aliases de host, ProxyJump, IdentityFile, substituições de Ciphers/MACs para equipamentos legados), aponte SSH_CONFIG_FILE para ele e evite repetir esses campos em hosts.toml:
SSH_CONFIG_FILE=~/.ssh/config
Precedência: hosts.toml sempre vence. ~/.ssh/config apenas preenche campos que você não definiu por host — a configuração do OpenSSH não pode ampliar o que path_allowlist, command_allowlist ou a lista de bloqueio de hosts permitem. Os logs de inicialização registram ssh_config: honoring <abs-path> (ou um WARNING se o arquivo estiver ausente) para que uma configuração incorreta apareça imediatamente.
4. Escreva .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. Verifique de ponta a ponta
uv run ssh-mcp
De um cliente MCP (ou de um shell Python rápido), chame:
from ssh_mcp.server import mcp_server
# tools: ssh_host_ping, ssh_host_info, ssh_sftp_list, ssh_find, ...
ssh_host_ping(host="web01") deve retornar {reachable: true, auth_ok: true, latency_ms: N, ...}.
Se falhar, consulte Solução de problemas.
Solução de problemas
no SSH agent reachable
A ordem de resolução do agente é: identity_agent explícito em hosts.toml → variável de ambiente SSH_AUTH_SOCK → detecção automática do Windows (Pageant / pipe OpenSSH). Verifique:
# 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
A impressão digital em hosts.toml não corresponde a nenhuma chave que o agente expõe. Liste o que está realmente carregado:
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())]"
Copie uma das impressões digitais relatadas para identity_fingerprint.
HostKeyMismatch / UnknownHost
Ou a chave do host mudou (rotação ou MITM) ou known_hosts está sem a entrada. Não contorne isso pelo LLM e não >> uma varredura diretamente em known_hosts sem verificação. Use o fluxo de três etapas da Seção 2 do passo a passo:
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
O host não está em hosts.toml e não está em SSH_HOSTS_ALLOWLIST. A resolução tenta a entrada primeiro como uma chave de hosts.<alias>, depois contra hosts.*.hostname e depois contra a lista de permissões do ambiente. Adicione uma entrada de hosts.toml ou adicione o nome de host literal a SSH_HOSTS_ALLOWLIST.
HostBlocked
A negação vence — verifique SSH_HOSTS_BLOCKLIST. Isso é intencional; remova a entrada se o bloqueio foi um erro, mas primeiro confirme com o operador que o adicionou.
PathNotAllowed
O caminho resolvido (canonicalizado) está fora de todas as raízes em path_allowlist. Verifique:
- O caminho está correto? Ferramentas de baixo acesso resolvem symlinks antes de verificar, então um symlink apontando para fora de
/opt/appserá rejeitado mesmo que o link em si esteja lá. - O
hosts.<name>.path_allowlistcobre o alvo?
command_allowlist is empty but ALLOW_DANGEROUS_TOOLS=true
O carregador avisa se você habilitar exec sem definir o escopo dos comandos permitidos. Defina SSH_COMMAND_ALLOWLIST ou um command_allowlist vazio por host (explícito = sem restrição).
Ferramentas não visíveis no cliente MCP
- Verifique o nível:
ALLOW_LOW_ACCESS_TOOLS/ALLOW_DANGEROUS_TOOLS/ALLOW_SUDOsão negados por padrão. - Verifique o grupo:
SSH_ENABLED_GROUPS(vazio = todos; explícito = filtro). - Reinicie o cliente MCP — as listas de ferramentas são armazenadas em cache por versão do servidor MCP.
Consultando logs de auditoria
Cada chamada de ferramenta grava uma linha JSON no logger Python ssh_mcp.audit — incluindo ferramentas de nível de leitura (desde v1.4.0, todos os níveis são auditados). Não há ferramenta em processo para consultar o log de auditoria — isso é intencional (INC-052): se o LLM pudesse ler seu próprio rastro de auditoria, um agente comprometido ou com jailbreak poderia se automonitorar quanto ao que foi pego fazendo e se ajustar em torno disso. A auditoria flui em uma única direção, para os operadores.
Conecte ssh_mcp.audit ao destino de sua escolha (arquivo, Loki, Splunk, Datadog, journald, ...) na sua própria configuração de logging. Para depuração local ou triagem rápida de incidentes, grave as linhas em um arquivo e consulte com 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 linha é um único objeto JSON compacto. Esquema:
| campo | tipo | observações |
|---|---|---|
ts | float | segundos Unix epoch |
correlation_id | str | 16 caracteres hexadecimais; forma par com a linha de erro completo em nível DEBUG em ssh_mcp.audit |
tool | str | O nome da ferramenta MCP (ex.: ssh_exec_run, ssh_broadcast) |
tier | str | read / low-access / dangerous / sudo |
host | str | Nome de host resolvido (ou ? para ferramentas de fan-out como ssh_broadcast) |
result | str | ok / error |
duration_ms | int | duração em tempo real da chamada da ferramenta |
path_hash | str | sha256:<16hex> do caminho canônico (quando a ferramenta tocou em um) |
command_hash | str | sha256:<16hex> do comando com dados ocultos (quando a ferramenta executou um) |
exit_code | int | Quando aplicável |
error | str | Apenas o nome da classe de exceção — o texto completo permanece no nível DEBUG (INC-008) |
Receitas úteis 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
Os campos command_hash e path_hash são auxílios de deduplicação, não controles de privacidade — prefixos curtos de SHA-256 são trivialmente vulneráveis a rainbow tables para comandos comuns e caminhos canônicos. Se a confidencialidade da auditoria for importante, aplique-a por meio de criptografia de transporte (TLS para seu backend de logs) e controle de acesso no próprio destino.
Aviso legal
Python SSH MCP é uma infraestrutura local que concede a um LLM (ou a qualquer cliente MCP) a capacidade de executar comandos em sistemas remotos via SSH. Use por sua conta e risco. As flags de nível negadas por padrão e a aplicação estrita de known_hosts protegem contra os erros óbvios, mas nenhum software pode proteger contra um operador que ativa todas as flags para true sem entender o raio de impacto.
Leia DECISIONS.md antes de habilitar o nível perigoso ou sudo em produção. Audite as linhas JSON de ssh_mcp.audit regularmente. Em caso de dúvida, deixe um nível desativado.
Este projeto não é afiliado nem endossado por nenhum provedor SSH, FastMCP ou MCP.
Suporte
Construir e manter este servidor MCP exige tempo e esforço reais, mesmo com assistência de IA. Se este SSH MCP facilitou seu fluxo de trabalho e sua vida, considere me apoiar:
Problemas, dúvidas e feedback: abra uma issue no GitHub. Se você achar Python SSH MCP útil, considere dar uma estrela no repositório — isso realmente ajuda.