SSH MCP Server

oficial

Execute comandos, mova arquivos, pesquise logs e audite máquinas via SSH a partir do seu agente.

O que você pode fazer com SSH MCP?

  • Executar comandos com proteções de segurança — Peça ao seu assistente para executar comandos únicos ou em lote via ssh_exec, com proteção contra comandos destrutivos que bloqueia operações irreversíveis antes que cheguem ao servidor.
  • Ler, escrever e listar arquivos remotos — Use ssh_file_read, ssh_file_write e ssh_file_list para inspecionar ou modificar arquivos, com gravações atômicas e verificação opcional de SHA-256.
  • Pesquisar logs e verificar a saúde do servidor — Consulte ssh_log_search ou ssh_log_tail em arquivos e contêineres, ou obtenha um instantâneo estruturado da saúde com ssh_snapshot e ssh_audit_baseline.
  • Transferir arquivos com verificações de integridade — Envie ou baixe arquivos e diretórios via ssh_upload e ssh_download, com fallback automático para scp legado em dispositivos mais antigos.
  • Gerenciar jobs em segundo plano de longa duração — Desanexe operações lentas com ssh_exec e acompanhe-as via ssh_job_status, ssh_job_output e ssh_job_kill, sobrevivendo a desconexões.

Documentação

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

SSH MCP Server

Um servidor MCP SSH — uma multiferramenta que economiza tempo e tokens para você e seu agente de IA em depuração, desenvolvimento e manutenção de servidores.

Execute comandos, mova arquivos, leia logs e audite máquinas via SSH — uma VPS na nuvem, um servidor físico, ou o roteador BusyBox escondido no seu armário.

Ele usa o cliente OpenSSH já presente na sua máquina: suas chaves, seu ~/.ssh/config, seus hosts de salto, seu encaminhamento de agente. Nada embutido, nada para compilar, sem bindings nativos.

Funciona com Claude Code, Codex CLI, Cline, opencode, Gemini CLI, Qwen Code, Hermes e outros clientes MCP.

MCP Registry Glama Smithery npm downloads tests

Instalar · Ferramentas · Configuração · Segurança · Roadmap · Documentação · Changelog


Instale em 30 segundos

Nenhuma instalação global é necessária. npx baixa o pacote no primeiro uso:

npx -y @hypnosis/ssh-mcp-server

Adicione-o ao seu cliente MCP — Claude Code, por exemplo — para cada projeto:

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

Ou escreva manualmente — o mesmo servidor no formato de configuração que a maioria dos clientes compartilha:

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

Depois crie ~/.claude/ssh-profiles.json com pelo menos uma máquina:

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

Isso é suficiente para conectar.

Codex, opencode, Qwen Code e outros clientes são abordados em Configurar o servidor MCP SSH.

Instalar como plugin

Alguns clientes — Claude Code, por exemplo — podem receber tudo como um plugin:

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

O plugin lê ~/.claude/ssh-profiles.json a menos que SSH_PROFILES_FILE diga o contrário, então crie esse arquivo primeiro e o servidor sobe com suas máquinas já carregadas.

Requisitos

npm version Node.js TypeScript MCP SDK

Node.js 18+ e um cliente ssh de sistema no PATH. No Windows, use um perfil baseado em chave; perfis com senha e frase secreta não estão disponíveis no momento.

Prefere uma versão fixada, trabalho offline ou uma verificação de registro a menos por execução: npm install -g @hypnosis/ssh-mcp-server, depois use ssh-mcp-server como comando em vez de npx.

Para quem é isso

  • DevOps e SREs que querem auditorias mais rápidas, verificações de incidentes e trabalho rotineiro de servidor.
  • Codificadores por vibração e construtores independentes que publicam com um assistente de IA e executam o que constroem em seus próprios servidores.
  • Administradores de sistemas e engenheiros de plataforma que querem ferramentas estruturadas em vez de um shell bruto sem restrições.
  • Desenvolvedores e pequenas equipes que administram sua própria VPS sem uma equipe de operações dedicada.
  • Proprietários de homelab, NAS e roteadores cujo hardware útil sobreviveu aos seus protocolos modernos.

Por que um servidor MCP SSH em vez de um shell bruto

Menos tokens, custos de IA mais baixos

Um shell bruto dá a um agente de IA um fluxo torrencial: comandos repetidos, tabelas ASCII e despejos de log. Isso queima tokens transformando esse ruído em uma imagem do servidor — seu dinheiro.

Depuração de servidor mais rápida

Ferramentas projetadas para propósito específico agrupam verificações rotineiras, limitam saídas ruidosas e retornam a parte que importa. O agente gasta menos tempo traduzindo saída de terminal e chega à correção mais cedo.

Menos suposições, menos erros de IA

Respostas estruturadas dizem o que foi encontrado, o que não pôde ser medido e o que foi truncado. Isso deixa menos espaço para o agente preencher lacunas com uma alucinação — e dá a você menos correções ruins, deploys mais calmos e código mais confiável.

Compatibilidade SSH: servidores modernos, equipamentos legados e Windows

Use sua configuração OpenSSH existente

Nenhuma implementação SSH embutida, nenhum binding nativo, nenhuma recompilação por plataforma. Comandos usam o cliente ssh do sistema, então suas chaves, seu ~/.ssh/config, seus hosts de salto e seu encaminhamento de agente continuam funcionando exatamente como em um terminal. Quando suportado, uma única conexão multiplexada compartilhada por destino significa que você autentica uma vez, não uma vez por comando.

Suporte SSH para servidores legados, roteadores e dispositivos NAS

Envie um arquivo para um roteador com um scp moderno e você recebe isto:

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

Nada está quebrado — um scp atual fala o novo protocolo, e o roteador não o conhece. Em um terminal, você agora vai ler um tópico de fórum e volta com uma flag extra. Aqui você não faz nada: a transferência é tentada, a recusa é reconhecida, o protocolo antigo é usado em vez disso, e essa máquina é lembrada para que o próximo arquivo vá direto para lá.

Alternativas para clientes SSH mais antigos e ferramentas ausentes

Equipamentos antigos recebem uma alternativa, não um beco sem saída. Quando um recurso moderno está ausente, o servidor segue o caminho mais antigo onde puder:

Sua máquinaO que você recebe
Um roteador ou NAS pequeno demais para transferência de arquivos modernaO arquivo ainda chega — o protocolo antigo é usado automaticamente
Um servidor de dez anos atrásO fluxo de trabalho ainda funciona; apenas abre uma conexão nova por comando em vez de reutilizar uma
Uma imagem enxuta sem como gerar hash de arquivoO upload diz "não foi possível verificar" em vez de afirmar uma correspondência que ninguém verificou
Uma máquina onde uma ferramenta simplesmente não está instaladaA resposta diz "não medido" — nunca um zero que pareça "nada aqui"

Construído para o Model Context Protocol

Construído no SDK MCP oficial, TypeScript em todo o código, mais de 2500 testes unitários além de uma suíte ao vivo que roda contra contêineres reais em vez de mocks.


SSH bruto vs um servidor MCP SSH: o mesmo trabalho, de ambas as formas

Verificação de saúde do servidor SSH

Situação: Um deploy acabou de sair. O servidor parece lento, e você não sabe se disco, memória, serviços, contêineres ou erros são os culpados.

Pergunta: "Esta máquina está saudável?"

SSH bruto

$ 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'.

Isso ainda é um resultado resumido. Uma verificação completa precisa de mais comandos para CPU, estados de serviço, contagens de contêineres e erros recentes, cada um com seu próprio formato de saída. Pior, uma máquina sem ss pode parecer que tem zero listeners quando a verificação de porta nunca rodou.

Resultado MCP estruturado

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": []
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
Vários comandos e tabelas ASCIICampos nomeados em um resultadoUma chamada, campos nomeados e menos idas e voltas
Uma ferramenta ausente pode parecer saída vaziaunavailable nomeia o que não foi medidoMenos suposições e menos correções ruins
Você vasculha discos, serviços e errosOs sinais do problema já estão na superfícieDepuração mais rápida

Um resultado completo de ssh_audit_baseline pode ser mais longo que um punhado de saídas de comandos brutos — cerca de 1.077 tokens contra 765 em nossa medição de laboratório. A economia vem do fluxo de trabalho completo, não de tornar uma resposta mais curta.

Em uma sessão real de solução de problemas, ferramentas de propósito específico reduziram 49 chamadas de comando separadas para 4 chamadas MCP. Cada chamada adicional inicia outra rodada do modelo com a conversa acumulada. O cache de prompt pode reduzir o custo de entrada repetida, mas novos comandos e suas saídas ainda consomem contexto. Menos idas e voltas significam menos tokens na sessão, menos análise repetida e um caminho mais rápido para a resposta.

Precisa do quadro completo em vez do pulso? ssh_audit_baseline agrupa sistema, disco, memória, portas, sshd, unidades com falha, Docker, firewall e atualizações. Os resultados chegam como CRÍTICO / AVISO / OK; seções não medidas são nomeadas em vez de silenciosamente lidas como zero.

Busca de log em servidor Linux

Situação: A API está expirando, mas a mesma mensagem pode estar no nginx, syslog, journald ou em um log de aplicação que você não consegue ler com seu usuário normal.

Pergunta: "De onde veio esse erro?"

SSH bruto

$ 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

O terceiro comando parece limpo, mas 2>/dev/null também escondeu um erro de permissão. "Nada correspondeu" e "nada foi lido" agora parecem idênticos. Um log movimentado também pode retornar milhares de linhas e empurrar o resto do incidente para fora do contexto do agente.

Resultado MCP estruturado

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
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
Quatro buscas e quatro saídasUma busca em arquivos e globsMenos tokens e idas e voltas
Erros de permissão podem desaparecerfiles_unreadable nomeia cada caminho perdidoSem conclusão falsa de "logs limpos"
A saída pode crescer sem um teto útillimited e truncated expõem cada corteDecisões mais seguras a partir de resultados parciais

since usa o relógio do servidor, namesOnly: true retorna apenas caminhos correspondentes, e ssh_log_tail lê as últimas N linhas de vários logs em uma chamada.

Edições seguras de configuração remota

Situação: Você precisa substituir uma configuração do nginx em um servidor ativo. Uma conexão perdida, modo errado ou cópia não verificada pode deixar o serviço com um arquivo quebrado.

Pergunta: "Posso substituir esta configuração sem deixar um arquivo parcial?"

SSH bruto

$ 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

Código de saída zero diz que o shell terminou. Não prova quais bytes chegaram, e > truncou o arquivo antigo antes do primeiro byte do novo chegar. Se a conexão cair no meio da escrita, o serviço fica com uma configuração parcial.

Resultado MCP estruturado

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 }]
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
O destino é truncado antes da cópia completarUm arquivo temporário completo o substitui com um renameSem configuração meio escrita
Apenas código de saídaBytes e resultado de verificação são nomeadosVocê sabe o que realmente chegou
Permissões vivem dentro do texto do shellsudo, mode e verify são campos por arquivoPropriedade previsível e menos erros de aspas

verified tem três resultados honestos: verified, unavailable quando o servidor não tem ferramenta de hash, e skipped quando a verificação não foi solicitada. Para leituras, ssh_file_read aceita uma lista de caminhos; ssh_file_list lida com globs, recursão, tamanhos e modos.

Execute comandos SSH em lote com sudo

Situação: Um deploy está pronto, mas a sintaxe do nginx, o estado do serviço e erros recentes devem todos ser verificados antes que o tráfego mude. Uma verificação com falha não deve desaparecer dentro de um despejo combinado.

Pergunta: "Todas as verificações de pré-flight passaram?"

SSH bruto

$ 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

Três conexões retornam três saídas não relacionadas. Se os comandos são unidos com ;, o shell relata apenas o último código de saída; se são unidos com &&, verificações posteriores desaparecem após a primeira falha.

Resultado MCP estruturado

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
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
Três chamadas e saídas não relacionadasUma lista de comandos ordenadaMenos idas e voltas
Um shell combinado pode esconder status intermediárioCada comando mantém seu próprio exit_codeNenhuma verificação com falha perdida
sudo e aspas são repetidos no texto do comandosudo se aplica ao lote inteiroMenos erros de aspas

A proteção de comandos destrutivos verifica a lista completa antes do primeiro comando rodar. Se uma entrada for recusada, todas as outras são marcadas como não executadas e nada é enviado ao servidor. Cada comando carrega seu próprio stdout e stderr. Um comando que foi executado e não imprimiu nada tem uma string vazia; um comando que nunca foi executado não tem esse campo de forma alguma, então os dois não podem ser confundidos. Saída acima de 128 KB por comando mantém ambas as extremidades — o cabeçalho para tabelas, o final para logs — com uma costura no meio nomeando a quantidade, e clipped_bytes diz quanto foi cortado. O corte acontece em limites de bytes e recua até a borda de um caractere, então uma resposta truncada nunca carrega uma marca de substituição.

sudo alcança o servidor sem um terminal: a resposta do perfil é entregue ao sudo na entrada padrão. Qual segredo é esse vem de sudoPassword quando o perfil nomeia um e de password caso contrário — um perfil que faz login por chave não tem senha de login alguma, e onde uma máquina mantém os dois separados, o de login é a resposta errada. Quando não há nada com que responder, a resposta diz isso e nomeia as saídas, em vez de deixar o próprio conselho do sudo sobre -S e auxiliares askpass. Um comando que lê sua própria entrada padrão nunca recebe a senha, que de outra forma acabaria misturada nos dados.

Executar trabalhos SSH de longa duração

Situação: Um backup ou migração vai rodar por mais tempo que a sessão do agente. A conexão pode fechar, mas você ainda precisa do estado, da saída e do código de saída depois.

Pergunta: "Este trabalho vai sobreviver à conversa?"

SSH bruto

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

O terminal se foi. Agora você precisa reconectar, encontrar o processo, inspecionar o arquivo de destino e adivinhar se o backup terminou ou parou no meio do caminho.

Resultado MCP estruturado

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"
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
O trabalho está preso a uma sessão SSHO trabalho remoto tem um id persistenteDesconexões e reinícios seguros
Reconectar significa procurar processos e arquivosStatus e código de saída têm estados nomeadosSem adivinhação se terminou
Ler a saída novamente repete texto antigoA saída continua de um deslocamento de bytesMenor uso de tokens em trabalhos longos

O estado do trabalho vive no disco remoto, não na memória deste servidor. ssh_job_status distingue running, finished e lost; ssh_job_output continua do último deslocamento de bytes; e ssh_job_kill sinaliza o grupo de processos inteiro em vez de apenas seu shell.

Transferir arquivos para roteadores e NAS legados

Situação: Um cliente OpenSSH atual tenta SFTP, mas o roteador ou NAS só entende o protocolo scp clássico. O arquivo ainda deve chegar intacto e substituir seu destino com segurança.

Pergunta: "Este dispositivo antigo ainda consegue receber um arquivo verificado?"

SSH bruto

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

O próximo passo usual é lembrar do sinalizador legado, tentar a cópia novamente e então executar um comando de hash separado — se o dispositivo tiver uma ferramenta de hash.

Resultado MCP estruturado

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
  }]
}

O que o agente ganha

SSH brutoMCP estruturadoSeu ganho
O modo SFTP moderno para no primeiro erroO fallback scp clássico é automático e lembradoEquipamento antigo ainda funciona
Uma cópia bem-sucedida não prova integridadeA verificação SHA-256 tem um resultado nomeadoCorrupção não é confundida com sucesso
Substituição direta pode deixar um destino parcialUm arquivo temporário é movido para o lugar após a transferênciaO arquivo de trabalho sobrevive a interrupções

Se o dispositivo não tiver nem sha256sum nem openssl, o resultado diz unavailable e nomeia o motivo em vez de relatar uma correspondência falsa. Diretórios inteiros usam recursive: true e verificam seus hashes em um único lote.

Proteção contra comandos destrutivos para agentes de IA

A proteção roda localmente, antes de um comando chegar ao SSH. Ela separa operações que podem ser recuperadas daquelas que destroem o contêiner que contém os dados, e verifica a ordem dos comandos dentro de cadeias e lotes.

Parar uma cadeia destrutiva antes que ela comece

Uma sequência segura de backup-e-substituição:

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

As mesmas operações na ordem errada:

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

O shell excluiria o diretório e só então descobriria que a fonte do backup se foi. A proteção vê que passos posteriores leem um destino já destruído por um passo anterior, então a chamada inteira fica na sua máquina. A mesma verificação pega dropdb app && pg_dump app > backup.sql.

Recusar perda irreversível, avisar sobre mudanças recuperáveis

Recusado — o próprio contêinerApenas avisado — seu conteúdo
DROP DATABASE, dropdbDROP TABLE, TRUNCATE, DELETE FROM
docker volume rm, docker compose down -vdocker rm -f <name>
crontab -reditar um trabalho
mkfs, wipefs -a, lvremove, zfs destroychmod 777
reboot, shutdown, haltgit reset --hard

docker compose down -v é recusado porque -v remove volumes Docker nomeados, incluindo um volume de banco de dados. Sem -v, parar os serviços não é tratado como a mesma ação irreversível.

Exclusão recursiva da raiz do sistema de arquivos, de um diretório home ou de árvores do sistema como /etc, /var e /usr também é recusada, inclusive quando um link simbólico leva até lá. Um destino não resolvido como rm -rf "$DIR"/* também é recusado: "não foi possível verificar" não é tratado como "seguro".

Nomeie o que você está parando

Um comando que encontra seu destino em vez de nomeá-lo não é enviado. O servidor o expande e responde com o que está por trás do 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 um processo, a resposta adiciona os sinais de que está em uso: há quanto tempo está rodando, em quais portas aceita conexões, quantas conexões está carregando. Destinos nomeados não custam nada extra e passam em silêncio — docker kill web-1, kill 4871, systemctl stop app.

Para prosseguir, nomeie o que está sendo parado. Os nomes são verificados contra o que o comando realmente alcança, então uma máscara que se desviou para outra coisa é recusada em vez de confirmada:

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

Um padrão sobre linhas de comando é um caso à parte. Ele corresponde ao próprio comando que o carrega, então o shell que o executa é sinalizado antes do destino e a resposta se interrompe no meio. Tal ataque não é confirmado, mas reescrito — por número, ou com um caractere escrito como uma classe para que o padrão pare de corresponder a si mesmo:

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

Três resultados permanecem separados: destinos encontrados, a expansão não alcançou nada e nada com que perguntar — sem mecanismo na máquina, uma resposta truncada, uma conexão que falhou. Os dois últimos são recusas também: não saber não é motivo para prosseguir.

Confirmar um comando destrutivo intencional

Nada é proibido permanentemente. Adicione # CONFIRMED-DESTRUCTIVE a um comando revisado e ele é permitido. Quando a proteção recusa uma entrada em um lote, o lote completo para antes da execução, então o servidor nunca fica após uma operação meio executada.

A proteção funciona dentro de uma única chamada. Ela não pode conectar uma exclusão em uma invocação com uma leitura na próxima, ou raciocinar sobre ferramentas que não reconhece. É um cinto de segurança, não um mecanismo de política: operações recuperáveis continuam sendo sua decisão. Restrições de caminho e regras de citação estão documentadas em docs/security.md.

Ferramentas

18 ferramentas MCP SSH para operações de servidor. Parâmetros completos e exemplos estão em docs/tools.md.

FerramentaO que faz
ssh_execExecuta um comando ou um lote, com a proteção de comando destrutivo e desconexão opcional
ssh_file_readLê um ou vários arquivos, texto ou binário
ssh_file_writeEscreve arquivos com renomeação atômica e verificação SHA-256 opcional
ssh_file_listLista um diretório, com glob e recursão opcionais
ssh_uploadEnvia um arquivo ou diretório via SSH, seguro para binários com verificações de integridade; um diretório substitui o destino ou mescla nele
ssh_downloadBaixa um arquivo ou diretório via SSH, seguro para binários com verificações de integridade
ssh_job_statusEstado de um trabalho em segundo plano: rodando, concluído ou perdido
ssh_job_outputLê a saída acumulada a partir de um deslocamento de bytes
ssh_job_listLista trabalhos, removendo os concluídos além do TTL
ssh_job_killSinaliza o grupo de processos inteiro de um trabalho
ssh_log_tailÚltimas N linhas de um ou vários logs, com suporte a glob; um contêiner por nome
ssh_log_searchBusca por padrão em logs, ou através do log de um contêiner
ssh_snapshotInstantâneo de saúde único: serviços, recursos, Docker, rede, erros
ssh_monitorControle de transporte: estatísticas, recarregar, testar, listar, fechar
ssh_audit_baselineSistema, disco, memória, rede, ssh, serviços, Docker, firewall, atualizações
ssh_tls_checkExpiração de certificado, SAN, cadeia e gancho de renovação para um domínio
ssh_disk_breakdownPara onde o disco foi: du top-N, Docker, journald, caches
ssh_service_statussystemctl status mais um final journalctl para uma unidade

Anotações de segurança de ferramentas MCP

Anotações MCP padrão informam aos clientes quais ferramentas são somente leitura, destrutivas, idempotentes ou de mundo aberto. Veja a tabela completa.

Executar comandos SSH e gerenciar arquivos remotos

Comandos, leituras e escritas de arquivos, listagens de diretórios — o trabalho comum em uma máquina, cada resposta já analisada.

Monitorar trabalhos SSH de longa duração

Trabalhos lentos são desconectados e acompanhados em vez de aguardados: cada olhada diz até onde chegou.

Buscar logs e verificar a saúde do servidor

Logs de arquivos e contêineres, e uma imagem única da máquina, com saída limitada para que um final não consuma a janela de contexto.

Enviar e baixar arquivos via SSH

Transferências seguras para binários com verificações de integridade. Detalhes em docs/transfer.md.

Para binários e arquivos grandes use ssh_upload / ssh_download — blocos base64 e heredocs não são seguros para binários nem atômicos.

Auditar servidores Linux via SSH

Somente leitura e em lote em uma única ida e volta. Detalhes em docs/audit.md.

Modo de compatibilidade SSH Windows

O Windows usa o modo de compatibilidade automaticamente. Quando a multiplexação de conexão está indisponível, o servidor alterna para uma conexão por comando. As mesmas ferramentas permanecem disponíveis via SSH baseado em chave — sem configuração separada ou implementação específica para Windows.

A proteção de comando destrutivo é coberta em Proteção contra comandos destrutivos para agentes de IA.

Configurar o servidor SSH MCP

Execute o pacote de Instalar em 30 segundos primeiro, depois crie um arquivo de perfil.

Criar perfis de conexão SSH

Coloque-o onde quiser — próximo à configuração do seu próprio agente é a escolha usual. Os exemplos abaixo usam ~/.claude/ssh-profiles.json; para outros agentes troque o diretório (~/.codex/, ~/.qwen/, ~/.config/opencode/):

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

Escolha um perfil SSH explicitamente

Não há perfil para o qual o servidor recaia: cada um é uma máquina diferente, e um comando enviado para a máquina errada não é algo que uma mensagem de erro possa desfazer depois. Pergunte sem um nome e a resposta lista os nomes para escolher:

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

Um perfil que o servidor não pode usar para SSH — sem host, sem username, ou mode: "local" — é ignorado sem reclamação, e campos que ele não reconhece são deixados de lado, então o arquivo pode ser compartilhado com outras ferramentas. Um perfil com um campo quebrado é um caso diferente: ele é nomeado junto com o campo e o valor, e seus vizinhos saudáveis continuam funcionando.

Cada perfil opcionalmente aceita um bloco pathSecurity que permite ou bloqueia os caminhos que as ferramentas de arquivo podem tocar — veja docs/security.md.

Um perfil que faz login por chave mas precisa de sudo no lado remoto aceita um sudoPassword — o segredo sudo com o qual se responde, que em muitas máquinas não é a senha de login. Mantenha-o no arquivo de segredos em vez de aqui.

Manter senhas e frases secretas SSH fora dos perfis

Preferir chaves. Se uma senha ou frase secreta de chave criptografada for inevitável, mantenha-a em um arquivo de segredos separado, nunca no próprio perfil:

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

O arquivo de segredos é indexado pelo nome do perfil — veja secrets.json.example:

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

sudoPassword é o que sudo responde naquela máquina. Um perfil que faz login por chave não tem senha de login para oferecer, e quando os dois diferem, a senha de login é a resposta errada; sem ela, password é usado.

O arquivo de segredos deve ser legível apenas por você (chmod 600). Caminhos relativos são resolvidos a partir do arquivo de perfis; segredos ficam fora de argv e são mascarados nos logs. Veja segurança de credenciais.

Configurar Claude Code, Codex e outros clientes MCP

Escolha o cliente que você usa e aponte-o para o mesmo arquivo de perfis.

Claude Code

Um comando; -s user disponibiliza o servidor em todos os projetos:

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

Coloque em ~/.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

Um comando, igual aos outros:

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

Outros clientes MCP

Gemini CLI, Hermes, Cline, um plugin de editor ou seu próprio agente funcionam da mesma forma. Tudo o que precisam é de um comando para executar e uma variável de ambiente.

Reinicie seu cliente MCP

Reinicie o cliente e execute ssh_monitor({ action: "list" }) para confirmar que o perfil foi carregado.

Configuração do SSH MCP server

VariávelO que fazPadrão
SSH_PROFILES_FILECaminho para o JSON de perfis — obrigatório
SSH_MCP_LOG_LEVELdebug, info, warn, errorinfo
LOG_LEVELAlternativa, usada apenas quando SSH_MCP_LOG_LEVEL não está definidainfo
SSH_MCP_LOG_TIMESTAMPCarimbos de data/hora nas linhas de logtrue
SSH_MCP_CONTROL_PERSISTSegundos que uma conexão compartilhada permanece ativa após o último comando; 0 a encerra imediatamente600
SSH_MCP_CONTROL_DIROnde os sockets de controle ficam~/.ssh/ssh-mcp
SSH_MCP_PROFILES_CACHE_TTLTTL do cache de perfis, em ms60000
SSH_MCP_PROFILES_WATCHRecarregar o arquivo de perfis quando ele mudartrue

A conexão compartilhada sobrevive a este processo de propósito: encerrá-la na saída cortaria o canal que outra janela na mesma máquina está usando.

Limitações do SSH MCP server

Cada limite indica o caminho para contorná-lo. Uma ferramenta que não pode fazer algo diz isso e nomeia ssh_exec, que executa comandos diretamente na máquina — um driver de log não suportado, um utilitário que a máquina não possui, um mecanismo que este servidor não fala. Você não precisa saber antecipadamente onde as ferramentas terminam: a recusa diz isso, no momento em que importa.

Três recusas permanecem deliberadamente silenciosas sobre o shell, porque ali essa é a resposta errada: um caminho que seu perfil proíbe (contornar sua própria regra não é uma correção), uma chamada malformada (a correção está na chamada) e uma recusa do próprio ssh_exec.

  • Cancelamento: uma chamada cancelada agora também interrompe o comando no servidor, enviada como uma segunda chamada pela mesma conexão. Onde o servidor não tem /proc, o comando é encontrado por meio de ps. FreeBSD não é verificado: o comportamento correto lá não é garantido. Transferências de arquivos e ssh_snapshot não aceitam cancelamento.
  • Gravações atômicas: BSD e macOS não podem pré-verificar renomeações entre sistemas de arquivos.

Roteiro do SSH MCP server

  • Execução completa de testes contra hosts SSH macOS

  • Execução de compatibilidade de ponta a ponta no Windows

  • Auditorias multi-host — comparar a saúde de vários perfis SSH em uma única chamada

  • Importar perfis do ~/.ssh/config existente

  • Transferências retomáveis para arquivos grandes e conexões instáveis

  • Linha do tempo de operações remotas — comandos, transferências e decisões de proteção em uma trilha de auditoria

  • Playbooks prontos de solução de problemas SSH

  • Logs de contêineres sem recorrer ao shellCONCLUÍDO: ssh_log_tail e ssh_log_search aceitam um nome de contêiner, perguntam ao docker onde ele grava e leem esse arquivo com o mesmo mecanismo de qualquer outro log

  • Uma recusa que deixa você travadoCONCLUÍDO: cada limite agora nomeia ssh_exec como o caminho, então atingir o limite de uma ferramenta custa uma frase em vez de um jogo de adivinhação

  • Respostas que chegam ao modeloCONCLUÍDO: saída de comandos, linhas de log correspondentes, nomes de máquinas e seções de snapshot viajam nos campos, não apenas no texto

  • Esquemas de ferramentas MCP menoresCONCLUÍDO: a lista de ferramentas ficou 10% mais leve, e um trabalho destacado agora mostra as últimas linhas que escreveu em vez de ser consultado às cegas

  • Trabalho longo sob rootCONCLUÍDO: um trabalho destacado é executado com sudo e acompanhado como root, e um perfil somente com chave responde sudo com seu próprio sudoPassword

Desenvolver e testar o SSH MCP server

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

A suíte ao vivo é executada contra contêineres reais — um BusyBox, um coreutils — porque os dois discordam silenciosamente, e um mock concorda com quem o escreveu. Veja docs/architecture.md para a estrutura.

Gostou do SSH MCP Server? ⭐

Se você gostou da ferramenta, dê uma estrela no GitHub — isso ajuda mais pessoas a descobrirem o projeto.

Contribua com o SSH MCP server

Issues e pull requests são bem-vindos em github.com/hypnosis/ssh-mcp-server.

Licença

MIT — veja LICENSE.