Servidor MCP (Model Context Protocol) para operação de hosts Oracle Linux 8+ via
SSH, com capabilities curadas em YAML — sem exec(command: string) livre. O modelo
chama capabilities nomeadas (system.disk_usage, não df -h); parâmetros são tipados e
validados; toda mutação passa por confirmação em duas etapas; e tudo é auditado.
Ver ARCHITECTURE.md para o design completo, ROADMAP.md
para o estado da implementação e SECURITY.md para modelo de ameaça e
hardening de deploy — leia o SECURITY.md antes de apontar este servidor para um host
de produção.
MCPs de SSH genéricos expõem um exec livre: qualquer texto que chegue ao contexto do
modelo (uma página web, um log, a saída de outro MCP) se torna instrução em potencial.
Este servidor inverte o default — comandos vivem num catálogo YAML versionado, com
parâmetros tipados (nunca string livre), renderização via shlex.quote, e saída remota
sempre envelopada como dado não confiável, nunca como instrução. Se um diagnóstico
realmente não cabe em capability curada, existe uma única porta de escape —
ol_raw_exec — gated por três barreiras independentes (ver SECURITY.md).
uv venv --python 3.11 --seed
source .venv/bin/activate # ou .venv\Scripts\activate no Windows
uv pip install -e ".[dev]"
# validação rápida
ruff check src tests && ruff format --check src tests
mypy --strict src
pytest -m "not integration"
# validação completa (exige podman ou docker; roda containers OL8/OL9 reais)
pytestuvx ol-ops-mcp-
Gere um par de chaves dedicado para o servidor (não reutilize uma chave pessoal):
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_claudeops -C claudeops@ol-ops-mcp -
Registre a chave pública no
authorized_keysdo usuário remoto — com as restrições descritas emSECURITY.md(restrict,pty=no,...). -
Registre a host key no seu
known_hostslocal. O servidor não aceita host desconhecido automaticamente (semAutoAddPolicy) — é preciso este passo manual:ssh-keyscan -t ed25519 -H <address> >> ~/.ssh/known_hosts
-
Copie
examples/hosts.toml.examplepara~/.config/ol-ops-mcp/hosts.toml(ou o caminho apontado porOL_OPS_MCP_CONFIG) e ajuste os hosts:mkdir -p ~/.config/ol-ops-mcp cp examples/hosts.toml.example ~/.config/ol-ops-mcp/hosts.toml chmod 600 ~/.config/ol-ops-mcp/hosts.toml
O servidor recusa subir se o arquivo estiver mais aberto que
0600(em sistemas POSIX). Um esqueleto mínimo:[server] audit_path = "~/.local/state/ol-ops-mcp/audit.jsonl" known_hosts = "~/.ssh/known_hosts" [defaults] mode = "readonly" user = "claudeops" key_file = "~/.ssh/id_ed25519_claudeops" [hosts.meu-host] address = "10.0.0.10" description = "Descrição do host" capability_sets = ["system", "storage", "systemd", "network"]
-
Se algum host precisa de mutação (
mode = "operator"ou acima) com sudo, gere o sudoers a partir do catálogo em vez de escrever à mão:ol-ops-mcp emit-sudoers --host meu-host --output /etc/sudoers.d/ol-ops-mcp
Só estas três têm efeito — nenhuma outra é lida pelo servidor:
| Variável | Efeito |
|---|---|
OL_OPS_MCP_CONFIG |
Caminho do hosts.toml. Default: ~/.config/ol-ops-mcp/hosts.toml. |
OL_OPS_MCP_ALLOW_RAW |
Precisa ser 1 para ol_raw_exec funcionar, mesmo em host com allow_raw = true. Ver SECURITY.md. |
OL_OPS_MCP_LOG_LEVEL |
Nível de log do processo (DEBUG, INFO, WARNING, ...). |
Por padrão, sem argumentos, o processo sobe o servidor MCP via stdio:
ol-ops-mcpExistem também subcomandos de CLI que não sobem o servidor:
# consulta o audit log local
ol-ops-mcp audit --host meu-host --since 24h --format table
# gera o bloco de sudoers a partir da config atual de um host
ol-ops-mcp emit-sudoers --host meu-host
# compara o sudoers instalado no host remoto com o que a config geraria
ol-ops-mcp verify --host meu-hostVer docs/claude-integration.md para o passo a passo
completo (claude mcp add, configuração equivalente no Claude Desktop e como confirmar
que a conexão subiu).
| Tool | O que faz |
|---|---|
ol_list_hosts |
Lista hosts configurados: endereço, modo, capability_sets. |
ol_list_capabilities |
Lista capabilities do catálogo, opcionalmente por domínio. |
ol_describe_capability |
Detalha uma capability: template, parâmetros, risco, timeout. |
ol_run_capability |
Executa uma capability. safe executa direto; risco maior devolve PlanResponse para confirmar com ol_confirm. |
ol_plan / ol_confirm |
Two-phase commit explícito para qualquer capability, mesmo safe. |
ol_describe_host |
Retrato agregado de um host (release, kernel, memória, disco, unidades com falha, interfaces) numa chamada. |
ol_fan_out |
Executa a mesma capability safe em vários hosts, concorrentemente. Nunca aceita capability de risco acima de safe. |
ol_audit_query |
Consulta o audit log local por host, capability, janela de tempo ou risco mínimo. |
ol_fetch_file |
Lê um arquivo de texto via SFTP, restrito a allow_read_paths. |
ol_tail_log |
Últimas linhas de log — de uma unit systemd (journalctl) ou de um arquivo (tail). |
ol_raw_exec |
Escape hatch gated — comando arbitrário, sempre two-phase, sempre com justification. Ver SECURITY.md antes de habilitar. |
Depois de conectado, um fluxo típico de diagnóstico via um cliente MCP:
> ol_list_hosts
[{"name": "meu-host", "mode": "readonly", ...}]
> ol_describe_host(host="meu-host")
{"release": "Oracle Linux Server 8.10", "disk": [...], "failed_units": [], ...}
> ol_run_capability(host="meu-host", capability="storage.disk_usage")
{"parsed": [{"filesystem": "/dev/sda1", "use_pct": 78, ...}], ...}
Para uma mutação (ex. reiniciar um serviço na allowlist do host):
> ol_plan(host="meu-host", capability="systemd.restart", params={"service": "mariadb"})
{"rendered_command": "sudo /usr/bin/systemctl restart mariadb", "confirm_token": "...", "expires_at": "..."}
> ol_confirm(confirm_token="...")
{"exit_code": 0, ...}
O comando renderizado aparece por completo antes de qualquer execução — o token expira em 120 segundos e só pode ser usado uma vez.
- Leia
SECURITY.mdantes de usar em produção. Em particular: este servidor não é um sandbox à prova de operador malicioso — ele protege contra prompt injection e erro de julgamento do modelo, não contra alguém que configure deliberadamentemode = "raw"com sudo irrestrito. - Hosts de produção devem começar em
mode = "readonly". Escalar paraoperatorourawé ato explícito nohosts.toml, nunca default. - Nunca coloque senha em texto claro na configuração — só
key_fileé aceito. - Redaction de segredos na saída remota (
core/redact.py) é heurística, não garantia criptográfica. Trate qualquer stdout/stderr retornado como dado potencialmente sensível até prova em contrário. - Este projeto cobre diagnóstico e operação do sistema operacional. Backup/recovery, HA,
auditoria de segurança avançada e tuning dentro do banco estão fora de escopo — ver
ARCHITECTURE.mdseção 1.3.
Apache-2.0.