mcp-ssh-toolkit
mcp-ssh-toolkit (Python)
Servidor MCP (Model Context Protocol) para executar comandos via SSH em servidores nomeados, definidos em um servers.json.
O foco aqui é ser prático e seguro:
Configuração por servidor e por grupo (
groups).Hot reload do
servers.json(não precisa reiniciar o MCP a cada mudança).Suporte a políticas (
policy) para permitir/bloquear comandos por regex.Suporte a senha sem colocar senha no JSON (via
passwordEnv,passwordCommandoupasswordKeyring).
Configuração via agente (LLM)
Depois que o MCP estiver ativo no seu host (opencode / Claude Desktop / etc), você pode pedir para o agente LLM configurar tudo pra você chamando as tools:
ssh_add_serverpara adicionar/atualizar servidoresssh_reload(se quiser forçar recarregar, embora exista hot reload)ssh_list/ssh_infopara validar o que ficou configurado
A recomendação é passar segredos por env var e só salvar no servers.json referências como passwordEnv.
Related MCP server: SSH MCP Server
Arquivos
mcp_ssh_server.py: entrypoint compatível do servidor MCP viastdio.mcp_ssh/: codigo modular do MCP (main.py,config.py,models.py,errors.py,policy.py,audit.py,ssh_exec.py,tools.py,handlers.py).web_admin_server.py: entrypoint compatível do painel web local.web_admin/: estrutura MVC do painel web (model.py,view.py,controller.py,app.py).web_admin_ui.html: template HTML do painel web.servers.json: sua configuração local (não commitar).servers.example.json: exemplo pronto (pode commitar).USAGE.txt: resumo rápido.tests/test_mcp_ssh_server.py: testes unitários básicos.
Requisitos
Python
>= 3.10OpenSSH no
PATH(para auth por chave/agent) ouparamiko(para auth por senha)
Opcional:
paramiko(quando usar senha):pip install paramikokeyring(quando usarpasswordKeyring):pip install keyring
Como rodar
1) Rodar manualmente (stdio)
python mcp_ssh_server.py --config servers.jsonOpcional (modo pacote):
python -m mcp_ssh.main --config servers.jsonVocê também pode usar a env var:
MCP_SSH_CONFIG=...(se não passar--config)
Painel web local (admin)
Se você quiser uma interface amigavel para gerenciar servers.json, executar comandos e consultar historico:
python web_admin_server.py --config servers.json --host 127.0.0.1 --port 8787Opcional (modo pacote):
python -m web_admin.app --config servers.json --host 127.0.0.1 --port 8787Depois abra no navegador:
http://127.0.0.1:8787O painel usa o mesmo servers.json e o mesmo arquivo de audit log configurado em logging.file.
2) Usar no opencode
Edite o arquivo de config do opencode do seu usuário (ex.: C:\Users\SEU_USUARIO\.config\opencode\opencode.json) e adicione um MCP local.
Opção A (Anaconda):
{
"mcp": {
"mcp-ssh": {
"type": "local",
"command": [
"C:\\Users\\SEU_USUARIO\\anaconda3\\python.exe",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\mcp_ssh_server.py",
"--config",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\servers.json"
],
"enabled": true
}
}
}Opção B (Python “normal” no PATH):
{
"mcp": {
"mcp-ssh": {
"type": "local",
"command": [
"python",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\mcp_ssh_server.py",
"--config",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\servers.json"
],
"enabled": true
}
}
}No Windows, se você usa o launcher, também costuma funcionar com py (ex.: trocar python por py).
Reinicie o opencode depois de alterar o opencode.json.
3) Usar no Claude Desktop (Anthropic)
O Claude Desktop suporta MCP via config (procure por claude_desktop_config.json). Em Windows, normalmente fica em:
%APPDATA%\\Claude\\claude_desktop_config.json(Windows)
Exemplo (Python no PATH):
{
"mcpServers": {
"mcp-ssh": {
"command": "python",
"args": [
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\mcp_ssh_server.py",
"--config",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\servers.json"
]
}
}
}Exemplo (Anaconda):
{
"mcpServers": {
"mcp-ssh": {
"command": "C:\\Users\\SEU_USUARIO\\anaconda3\\python.exe",
"args": [
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\mcp_ssh_server.py",
"--config",
"C:\\Users\\SEU_USUARIO\\Desktop\\mcp-ssh-python\\servers.json"
]
}
}
}Dica: se você precisa passar senhas via env vars (passwordEnv), configure as env vars no processo do Claude Desktop (ou inicie o Claude Desktop a partir de um terminal já com as env vars setadas, se aplicável).
Configuração (servers.json)
Estrutura (v1):
{
"version": 1,
"defaults": {
"user": "ubuntu",
"port": 22,
"identityFile": "~/.ssh/id_ed25519",
"strictHostKeyChecking": "accept-new|yes|no",
"knownHostsFile": "~/.ssh/known_hosts",
"extraArgs": ["-o", "BatchMode=yes"]
},
"policy": {
"allow": ["^uptime$"],
"deny": ["(?i)\\brm\\s+-rf\\b"]
},
"defaultServer": "nome-do-servidor",
"groups": {
"prod": ["prod-web", "prod-db"],
"staging": ["staging"]
},
"servers": {
"nome-do-servidor": {
"host": "10.0.0.10",
"port": 22,
"user": "ubuntu",
"identityFile": "~/.ssh/id_ed25519",
"strictHostKeyChecking": "accept-new|yes|no",
"knownHostsFile": "~/.ssh/known_hosts",
"extraArgs": ["-o", "BatchMode=yes"],
"passwordEnv": "SSH_PASSWORD_ENVVAR",
"passwordCommand": ["op", "read", "op://vault/item/field"],
"passwordKeyring": {"service": "mcp-ssh", "username": "ubuntu"},
"policy": {
"allow": ["^(uptime|whoami)$"],
"deny": ["(?i)\\bshutdown\\b"]
}
}
}
}Policy (allow/deny): modelo de decisão
A policy pode existir no root (policy) e também por servidor (servers.<nome>.policy). O modelo é:
denysempre bloqueia: se QUALQUER regex emdenybater, o comando é negado.allowé allowlist: se existir pelo menos um regex emallow, o comando só é permitido se bater em pelo menos um.Se
allowestiver vazio/ausente, o padrão é "allow all" (exceto o que for negado pordeny).Root + servidor são mesclados (acumulam):
allow_final = allow_global + allow_servidor,deny_final = deny_global + deny_servidor.
Segurança: comando remoto e shell
ssh_execenviacommandcomo uma string para o host remoto. Na prática, isso significa que o comando é interpretado no lado remoto (normalmente por um shell), então metacaracteres como;,&&,|,>,<,$(), crases, etc. podem alterar o que de fato executa.Isso é diferente de
passwordCommand, que roda localmente semshell=True(logo, não sofre interpretação de shell local).
Se você quiser um modo mais "hardening", a recomendação é:
Preferir
policy.allowcom regex ancorada (ex.:^(uptime|whoami)$) para permitir só comandos simples.(Opcional) Bloquear metacaracteres via
policy.deny.
Exemplo de deny para bloquear metacaracteres comuns (ajuste conforme sua necessidade):
{
"policy": {
"deny": ["[;&|><`$()\\n\\r]"]
}
}Autenticação (sem expor senha)
Recomendado:
Chave SSH (
identityFile) / ssh-agent (usa OpenSSH)
Para servidor com senha (usa paramiko):
passwordEnv: pega a senha de uma env varpasswordCommand: roda um comando e usa o stdout como senha (semshell=True)passwordKeyring: lê do keyring do OS
Evite:
passwordem texto plano no JSON
Hot reload (não reiniciar sempre)
O MCP recarrega o servers.json automaticamente quando o arquivo muda (por mtime).
Além disso, existe:
Tool
ssh_reload: força recarregar imediatamente.
Audit logging (comandos executados)
Por padrão, o audit log fica habilitado e registra os comandos executados (ssh_exec / ssh_exec_parallel) com horário e servidor.
O formato é JSON Lines (.jsonl), 1 evento por linha.
Para desabilitar explicitamente:
"logging": {"enabled": false}ou env var:
MCP_SSH_AUDIT_LOG_DISABLE=1
Exemplo:
{
"logging": {
"enabled": true,
"file": "~/.mcp-ssh-toolkit/audit.jsonl",
"format": "jsonl",
"includeCommand": true,
"includeResult": true,
"includeStdout": false,
"includeStderr": false,
"logTests": false
}
}Também dá pra apontar o arquivo via env var:
MCP_SSH_AUDIT_LOG_FILE=/caminho/para/audit.jsonl
Log paralelo de upload/delete (file ops)
Uploads e exclusoes remotas geram um log separado (file_ops.jsonl) para facilitar auditoria operacional.
Config no servers.json:
{
"fileOpsLogging": {
"enabled": true,
"file": "~/.mcp-ssh-toolkit/file_ops.jsonl",
"format": "jsonl"
}
}Env vars:
MCP_SSH_FILEOPS_LOG_FILE=/caminho/para/file_ops.jsonlMCP_SSH_FILEOPS_LOG_DISABLE=1
Tools disponíveis
ssh_list: lista servidores/grupos/defaults/policyssh_info: mostra config sanitizada de um servidor (sem segredos)ssh_test: testa conexão/auth (server ou group)ssh_exec: executa emserverougroup(sequencial)ssh_exec_parallel: executa emgroup(paralelo)ssh_upload: envia arquivo local para remoto via SFTP (serverougroup)ssh_delete: exclui arquivo/diretorio remoto via SFTP (serverougroup)ssh_add_server: adiciona/atualiza server e opcionalmente inclui em gruposssh_reload: recarrega config do disco
Exemplos de uso
Executar em um servidor
{"server":"kali-192.168.1.33","command":"cat /etc/os-release && uname -a","timeout_ms":30000}Executar em um grupo
{"group":"lab","command":"uptime"}Executar em grupo (paralelo)
{"group":"lab","command":"uname -a","max_parallel":8}Testar política deny/allow
Se você configurar
policy.denycom(?i)\\brm\\s+-rf\\be tentar:
{"server":"kali-192.168.1.33","command":"rm -rf /tmp/test"}O MCP deve retornar erro -32602 informando que o comando foi bloqueado pela policy.
Upload e exclusao remota
Upload para um servidor:
{
"server": "autopago-target",
"local_path": "C:/tmp/app.tar.gz",
"remote_path": "/tmp/app.tar.gz",
"overwrite": true,
"make_dirs": true
}Excluir arquivo remoto:
{
"server": "autopago-target",
"remote_path": "/tmp/app.tar.gz"
}Excluir diretório remoto recursivo:
{
"server": "autopago-target",
"remote_path": "/tmp/build-dir",
"recursive": true,
"missing_ok": true
}Tool ssh_add_server (adicionar sem reiniciar)
Exemplo: adiciona srv1, coloca no grupo prod e define como default:
{
"server": "srv1",
"host": "10.0.0.10",
"port": 22,
"user": "ubuntu",
"identityFile": "~/.ssh/id_ed25519",
"groups": ["prod"],
"setDefault": true
}Observação:
Por padrão,
ssh_add_servernão aceitapasswordem texto plano.Se você quiser liberar isso no laboratório, rode com:
MCP_SSH_ALLOW_PLAINTEXT_PASSWORD=1
Testes
python -m unittest discover -s tests -p "test*.py"Cheque rápido de sintaxe (opcional):
python -m py_compile mcp_ssh_server.py web_admin_server.pyTroubleshooting
"ssh executable not found": instale/ative OpenSSH no Windows.
Senha via env não funciona: a env var precisa existir no processo que inicia o MCP/opencode.
Config mudou e não refletiu: use
ssh_reload(ou confira permissões/mtime do arquivo).
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Run commands and read/write files on your servers over Termalin's keyless tunnels (hosted MCP).
Scoped, audited SSH exec, sessions, and SFTP on your saved servers without exposing credentials
A Model Context Protocol (MCP) server for Selise Blocks Cloud integration
Related MCP Servers
- AlicenseAqualityCmaintenanceA Model Context Protocol server implementation that enables secure remote command execution via SSH, with features for managing and using SSH credentials.51 npm11MIT
- AlicenseBqualityDmaintenanceA server that enables remote command execution over SSH through the Model Context Protocol (MCP), supporting both password and private key authentication.11 npm2MIT
- FlicenseAqualityDmaintenanceA local Model Context Protocol server that allows LLMs to securely execute shell commands on remote Linux and Windows systems via SSH connections.63 npm2-
- AlicenseAqualityAmaintenanceA Model Context Protocol server that allows LLMs to securely execute shell commands on remote Linux and Windows systems via SSH. It supports password and key-based authentication, command timeouts, and sudo elevation for administrative tasks.146,728 npm763MIT