Skip to main content
Glama
README.md
# MCP Server SSH

Servidor [Model Context Protocol](https://modelcontextprotocol.io) que permite ao opencode
conectar-se a uma VPS via SSH (usuário e senha **ou** chave privada) e executar operações remotas:
comandos, sessões interativas persistentes e transferência de arquivos via SFTP.

## Tools

| Tool | Descrição |
| --- | --- |
| `ssh_test` | Testa a conexão e retorna informações do servidor (hostname, SO, uptime, carga). |
| `ssh_exec` | Executa um ou mais comandos na VPS e retorna stdout/stderr/código de saída. |
| `ssh_session_open` | Abre uma sessão interativa persistente (shell com estado). Retorna um `session_id`. |
| `ssh_session_send` | Envia um comando para uma sessão aberta. O estado do shell (cwd, vars) é preservado. |
| `ssh_session_close` | Fecha uma sessão interativa. |
| `ssh_upload` | Envia um arquivo local para a VPS via SFTP. |
| `ssh_download` | Baixa um arquivo da VPS para a máquina local via SFTP. |

## Credenciais

As credenciais são lidas de **variáveis de ambiente** do servidor MCP e podem ser
sobrescritas por chamada nas tools (`host`, `port`, `username`):

| Variável | Obrigatória | Descrição |
| --- | --- | --- |
| `SSH_HOST` | sim | IP ou hostname da VPS |
| `SSH_USER` | sim | Usuário do SSH |
| `SSH_PASSWORD` | sim* | Senha do SSH (*ou `SSH_PRIVATE_KEY`) |
| `SSH_PORT` | não | Porta SSH (padrão `22`) |
| `SSH_PRIVATE_KEY` | não | Caminho de uma chave privada (alternativa à senha) |
| `SSH_PRIVATE_KEY_PASSPHRASE` | não | Passphrase da chave privada |

## Build

```bash
npm install
npm run typecheck   # verificação de tipos (tsc --noEmit)
npm run build       # compila para dist/
npm start           # roda npx dist/index.js
```

## Smoke test rápido

Sem precisar de uma VPS, dá para validar o servidor via stdio (lista as 7 tools):

```bash
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0.0"}}}\n{"jsonrpc":"2.0","method":"notifications/initialized"}\n{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}\n' | node dist/index.js
```

## Estrutura do código

```
src/
  index.ts          # entrada do servidor MCP (stdio) + encerramento limpo (SIGINT/SIGTERM)
  config.ts         # leitura/validação das credenciais (SSH_*) e overrides por chamada
  sshManager.ts     # ciclo de vida da conexão: client reutilizável, SFTP cacheado, sessões
  exec.ts           # execução one-shot e por sessão (marcador de fim de comando, truncagem)
  tools/
    shared.ts       # schemas zod e helpers comuns (formatação, execução, erro)
    exec.ts         # tools ssh_exec e ssh_test
    session.ts      # tools ssh_session_open / send / close
    transfer.ts     # tools ssh_upload e ssh_download (SFTP)
```

### Notas de implementação

- **Sessões interativas**: ao abrir, o eco do terminal é desativado (`stty -echo`) e o
  prompt limpo, para que a captura de saída seja confiável. Cada comando é delimitado por
  um marcador único (`; echo "exit=$?"; echo "__SSH_MARKER_*__"`) e a saída é lida até o
  marcador aparecer, com timeout padrão de 60s.
- **Truncagem**: a saída de cada comando fica limitada a 200 KB por **bytes** (não corta
  caracteres UTF-8 multibyte no meio).
- **Reutilização de conexão**: uma única conexão SSH é mantida entre chamadas e só é
  reaberta se host/porta/usuário/credencial mudarem. O SFTP segue o mesmo princípio.

## Configuração no opencode

Adicione o servidor em `opencode.json` (projeto) ou
`~/.config/opencode/opencode.json` (global):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ssh": {
      "type": "local",
      "command": ["node", "S:/workspace/mcp/ssh/dist/index.js"],
      "enabled": true,
      "env": {
        "SSH_HOST": "SEU_IP_OU_HOSTNAME",
        "SSH_USER": "root",
        "SSH_PASSWORD": "SUA_SENHA",
        "SSH_PORT": "22"
      }
    }
  }
}
```

> Requer Node.js >= 20 na máquina.

Depois de salvar, **reinicie o opencode** para que o servidor MCP seja carregado.

## Segurança

- A senha fica armazenada no `opencode.json`. Proteja o arquivo (ex.: `chmod 600`)
  ou use apenas `SSH_HOST`/`SSH_USER` no config e passe a senha por chamada
  quando necessário.
- Prefira `SSH_PRIVATE_KEY` com passphrase quando possível.
- As tools seguem o **princípio do menor privilégio**: certifique-se de que a
  conta configurada tem apenas as permissões necessárias na VPS.