@kodehub/mcp
MCP Server que conecta o Claude Code diretamente à sua hospedagem KodeHUB (cPanel). Deploy, leitura e gestão de arquivos sem FTP — direto do seu fluxo de desenvolvimento.
Índice
- Início Rápido
- O que o Claude Code passa a fazer
- Fluxo do agente (multi-domínio)
- Como Funciona
- Arquitetura
- Comandos do CLI
- Segurança
- Estrutura do Projeto
- Desenvolvimento
- Contrato com o Painel
- Solução de Problemas
- Roadmap
Início Rápido
O token é gerado por você, no painel KodeHUB. Este pacote não gera nem armazena credenciais — ele apenas recebe o seu token e o valida contra o painel.
- Acesse Portal do Cliente → Painel de Hospedagem → Integração Claude Code (MCP).
- Clique em Gerar novo token e copie o JWT exibido (ele aparece uma única vez).
- Registre no Claude Code:
claude mcp add kodehub -- npx -y @kodehub/mcp --token <SEU_TOKEN>
- Reinicie o Claude Code e pronto — diga algo como:
"sobe esse projeto para o public_html da minha hospedagem"
O que o Claude Code passa a fazer
| Tool | Escopo | Descrição |
|---|---|---|
list_sites |
mcp:read |
Lista os domínios/sites da conta, o diretório de cada um e quais já têm WordPress |
list_files |
mcp:read |
Lista arquivos e diretórios do home da conta |
read_file |
mcp:read |
Lê arquivos (até 10MB, UTF-8) |
write_file |
mcp:exec |
Cria/atualiza arquivos (cria diretórios automaticamente) — não sobrescreve existentes sem overwrite: true |
delete_file |
mcp:exec |
Remove arquivos/diretórios (exige confirm: true) |
move_file |
mcp:exec |
Move ou renomeia dentro do home |
mysql_list_databases |
mcp:read |
Lista bancos MySQL da conta (uso de disco e usuários) |
mysql_create_database |
mcp:exec |
Cria banco MySQL (prefixo da conta aplicado automaticamente) |
mysql_create_user |
mcp:exec |
Cria usuário MySQL com senha forte gerada — exibida uma única vez |
mysql_assign_user |
mcp:exec |
Associa usuário a banco (default ALL PRIVILEGES, aceita lista granular) |
mysql_delete_database |
mcp:exec |
Remove banco MySQL e todos os dados (exige confirm: true) |
postgresql_list_databases |
mcp:read |
Lista bancos PostgreSQL da conta |
postgresql_create_database |
mcp:exec |
Cria banco PostgreSQL (prefixo automático, sem maiúsculas) |
postgresql_create_user |
mcp:exec |
Cria usuário PostgreSQL com senha forte gerada — exibida uma única vez |
postgresql_assign_user |
mcp:exec |
Concede todos os privilégios do banco ao usuário |
postgresql_delete_database |
mcp:exec |
Remove banco PostgreSQL e todos os dados (exige confirm: true) |
O cliente entra direto no /home/{conta} e navega livremente dentro dele
(public_html, mail, logs...). A única fronteira é o próprio home — qualquer
path fora dele é bloqueado antes de tocar o servidor.
Tokens podem ser emitidos somente-leitura (apenas mcp:read) para auditoria.
Fluxo do agente (multi-domínio)
Uma conta de hospedagem quase nunca tem só um site: no mesmo /home/{conta} podem
coexistir vários domínios, subdomínios e instalações WordPress. Para o Claude Code
não subir arquivos no lugar errado nem quebrar um site existente, o pacote entrega ao
agente — no handshake MCP — um conjunto de instruções de comportamento. Na prática,
ao conectar o agente passa a:
- Listar os sites primeiro. Antes de qualquer upload, ele chama
list_sitese mostra os domínios da conta, o diretório de cada um e quais já têm WordPress instalado. - Conversar por domínio, não por caminho. Em vez de perguntar "qual pasta?", ele
pergunta "em qual site você quer trabalhar?" —
exemplo.com,exemplo1.com,loja.exemplo.com… - Dar exemplos concretos de destino. Ex.: "posso subir na raiz de
exemplo.com(está vazia) ou emexemplo.com/site". - Nunca sobrescrever nada sem confirmação.
write_filerecusa gravar por cima de um arquivo existente a menos que você confirme (overwrite: true). Se o site já tem WordPress ou arquivos, o agente avisa antes e sugere um subdiretório vazio.
Exemplo de conversa:
Você: "quero publicar meu site"
Claude Code: "Sua conta tem 4 sites: meusite.com.br (WordPress instalado), loja.meusite.com.br (vazio), blog.meusite.com.br (com arquivos) e app.meusite.com.br (WordPress). Em qual deles quer publicar? Posso subir na raiz de loja.meusite.com.br, que está vazia, ou num subdiretório de outro site."
Assim o deploy é sempre explícito e seguro, mesmo numa conta cheia de sites.
Como Funciona
1. Cliente gera token JWT (RS256) no painel KodeHUB
2. Token vai para o Claude Code via `claude mcp add`
3. No boot, o pacote:
a. Valida a assinatura via JWKS público do painel
b. Confirma no painel que o token não foi revogado
4. Na primeira operação, troca o token por uma sessão cPanel efêmera (~15 min)
5. Ao conectar, o agente lista os sites (`list_sites`) e confirma o destino por domínio
6. Opera arquivos via API do cPanel, renovando a sessão automaticamente
7. Cada operação é auditada no painel (tool, path, sucesso, IP)
Arquitetura
Claude Code (cliente)
│ stdio
▼
@kodehub/mcp (processo local Node.js)
│
├─► Edge Functions KodeHUB (Supabase)
│ mcp-jwks ← chave pública (JWKS) para validar o JWT
│ mcp-check-jti ← revogação/expiração (recheck a cada 60s)
│ mcp-resolve-hosting ← resolve cliente → servidor WHM → sessão cPanel
│ mcp-touch-token ← marca último uso (fire-and-forget)
│ mcp-log-access ← auditoria por operação (fire-and-forget)
│
└─► cPanel (sessão efêmera via WHM create_user_session)
UAPI: DomainInfo::domains_data (list_sites)
Fileman::list_files / get_file_content / save_file_content
API2: Fileman::mkdir / fileop (unlink, move)
Multi-servidor: o painel mantém a tabela servidores_whm (host + credenciais
WHM por servidor). O mcp-resolve-hosting resolve automaticamente em qual servidor
a conta do cliente vive — o pacote não precisa saber nada disso.
Comandos do CLI
npx @kodehub/mcp --token <JWT> # inicia o MCP Server (stdio) — uso pelo Claude Code
npx @kodehub/mcp status --token <JWT> # valida o token e mostra os dados da hospedagem
npx @kodehub/mcp --help
O token também pode ser fornecido via variável de ambiente KODEHUB_TOKEN.
Exemplo de saída do status:
[kodehub-mcp] Token válido ✔
[kodehub-mcp] Cliente: 91cc6dc4-...
[kodehub-mcp] Escopos: mcp:read, mcp:exec
[kodehub-mcp] Conta cPanel: minhaconta
[kodehub-mcp] Domínio: meusite.com.br
[kodehub-mcp] Home: /home/minhaconta
Segurança
- JWT RS256 assinado pelo painel — a chave privada nunca sai do backend;
o pacote valida com a chave pública (JWKS) e rejeita
alg: none/HS256. - Revogação em até 60s: cada operação recheca o token no painel (cache 60s). Revogou no painel → o acesso morre, mesmo com a sessão MCP aberta.
- Zero credencial permanente na máquina do cliente: nada de senha ou chave SSH — apenas sessões cPanel efêmeras (~15 min), renovadas sob demanda.
- Sandbox por path: todo caminho é resolvido e validado contra o home da conta
antes de qualquer chamada; traversal (
../) e cross-tenant são bloqueados localmente. - Escopos por tool: leitura (
mcp:read) e escrita (mcp:exec) separados. - Auditoria completa: toda operação registrada no painel com tool, path,
resultado e IP (
mcp_access_log). - stdout limpo: logs somente em stderr — stdout é exclusivo do protocolo MCP.
Estrutura do Projeto
├── bin/
│ └── cli.js # Entrypoint (commander): server stdio | status
├── src/
│ ├── config.js # BASE_URL (env KODEHUB_API_URL), TTLs, limites
│ ├── server.js # Monta o McpServer, registra tools, auditoria
│ ├── auth/
│ │ └── verify.js # JWKS (jose) + check-jti com cache de 60s
│ ├── api/
│ │ ├── kodehub.js # Cliente das edge functions (Bearer JWT)
│ │ └── cpanel.js # Sessão cPanel + UAPI/API2 + renovação automática
│ ├── tools/ # As 6 tools MCP (uma por arquivo)
│ └── utils/
│ ├── sandbox.js # Path guard (anti-traversal / cross-tenant)
│ ├── scopes.js # mcp:read / mcp:exec
│ ├── http.js # fetch com timeout (AbortSignal)
│ └── logger.js # Logs em stderr
└── test/ # node:test — 46 testes
Desenvolvimento
npm install
npm test # 46 testes (node --test)
./node_modules/.bin/c8 --reporter=text node --test # cobertura
node bin/cli.js --help
| Variável | Uso |
|---|---|
KODEHUB_TOKEN |
Token MCP (alternativa ao --token) |
KODEHUB_API_URL |
Sobrescreve a URL base das edge functions (dev/staging) |
Publicação (mantenedores) — automática via GitHub Actions:
# 1. Bump de versão em package.json E src/config.js (PKG_VERSION)
# 2. npm install --package-lock-only && git commit && git push (CI roda os testes)
gh release create vX.Y.Z --title "vX.Y.Z" --notes "..."
# → o workflow publish.yml publica no npm usando o secret NPM_TOKEN
Contrato com o Painel KodeHUB
O pacote consome estas edge functions (todas autenticadas com Authorization: Bearer <JWT>,
exceto o JWKS que é público):
| Endpoint | Quando | Resposta |
|---|---|---|
GET /mcp-jwks |
Boot (cacheado) | JWKS com a chave pública RS256 |
POST /mcp-check-jti |
Boot + a cada 60s | { valid, cliente_id, jti, scopes, exp } |
POST /mcp-resolve-hosting |
1ª operação + renovação | { hosting, server, session: { url, expires }, scopes } |
POST /mcp-touch-token |
Após cada tool | { ok: true } |
POST /mcp-log-access |
Após cada tool | corpo: { tool, resource_path, success, error_message? } |
Solução de Problemas
| Sintoma | Causa provável | Ação |
|---|---|---|
Token inválido: token_revoked |
Token revogado no painel | Gerar novo token no Portal do Cliente |
Token inválido: token_expired |
Token venceu | Gerar novo token |
Token sem o escopo necessário: mcp:exec |
Token somente-leitura | Gerar token com escopo de escrita |
Arquivo já existe: ... overwrite: true |
Proteção contra sobrescrita | Confirmar a substituição (o agente reenvia com overwrite: true) |
Timeout de 60s aguardando cPanel ... |
Servidor lento/instável ou IP bloqueado pelo WAF (Imunify360) | Repetir; se persistir, admin verifica o servidor / whitelist do IP |
session_error: whm_http_403 |
Painel sem acesso ao WHM do servidor | Admin: conferir host/token em servidores_whm |
session_error: server_not_configured |
Hospedagem sem servidor vinculado | Admin: vincular servidor no cadastro |
| Tools não aparecem no Claude Code | Registro MCP incorreto | Refazer claude mcp add e reiniciar |
Roadmap
- v1.0 (atual) — Tools de filesystem + auditoria (stdio)
- v1.1 — MySQL:
list_databases,run_query - v1.2 —
tail_logs(error_log/access_log do domínio) - v1.3 — Cron jobs
- v2.0 — VPS Virtualizor (SSH efêmero)
Licença
MIT KodeHUB — kodehub.com.br