Files
claude-plugins/infraestrutura/skills/mcp-dev/SKILL.md
T
ealmeida 18e48db490 feat(infraestrutura): mcp-dev v3.0 — SDK TypeScript v2 e transporte HTTP obrigatórios
Regra de Ouro adicionada ao topo da skill: SDK v2 (@modelcontextprotocol/server),
API de alto nível McpServer+registerTool (API de baixo nível Server+setRequestHandler
proibida), transporte HTTP obrigatório (stdio só como excepção documentada), e
proibição explícita de interpolação de dados em comandos shell/SSH.

Motivado por revisão de segurança ao mcp-kivicare (19-08-2026): 8 bugs reais
corrigidos em produção, incluindo injecção de comandos shell crítica e hooks
nativos disparados com o tipo errado. Regras adicionadas para nunca mais acontecer
em silêncio.

- SKILL.md: nova secção Regra de Ouro, API/annotations/capabilities actualizadas
  para v2, transportes HTTP obrigatório, changelog v3.0.0, healing log com os
  3 bugs mais graves do incidente.
- references/templates.md: reescrito para createMcpHandler + createMcpExpressApp
  (HTTP) e serveStdio (excepção), package.json com pacotes v2.
- references/best-practices.md: capabilities/annotations/error handling
  actualizados para API v2, checklist de segurança com regra anti-injecção de
  comandos shell, tabela de transportes com HTTP obrigatório.
- references/evaluation-guide.md: script de evaluations reescrito para
  Client+StreamableHTTPClientTransport in-process (sem porta/socket).
- infraestrutura: 1.2.2 -> 1.3.0
2026-08-19 09:16:31 +01:00

14 KiB

name, description
name description
mcp-dev Desenvolvimento e teste de servidores MCP — criação, configuração e gestão de MCPs customizados. SDK TypeScript v2 (@modelcontextprotocol/server) e transporte HTTP são obrigatórios, sem excepção silenciosa.

/mcp-dev - Desenvolvimento de MCPs

Skill para criação, configuração e gestão de servidores MCP customizados.

Regra de Ouro — obrigatória, sem excepção silenciosa

Todo MCP novo, e toda a edição estrutural de um MCP existente, tem de cumprir isto:

  1. SDK oficial v2 (ts.sdk.modelcontextprotocol.io/v2) — pacotes @modelcontextprotocol/server (+ @modelcontextprotocol/client só em testes/evaluations). @modelcontextprotocol/sdk (v1) está descontinuado nesta casa — nunca instalar, nunca copiar código de um MCP antigo que o use sem migrar primeiro. API de alto nível McpServer + registerTool/registerResource/registerPrompt — a API de baixo nível Server + setRequestHandler(Schema, …) está proibida (reintroduz classes de bugs que o v2 elimina por desenho, incluindo o anti-padrão de capabilities manuais que causava o erro 471).
  2. Transporte HTTP obrigatório — createMcpHandler (Streamable HTTP), tipicamente montado com @modelcontextprotocol/express + @modelcontextprotocol/node. stdio (serveStdio) só é aceitável quando o host tem de lançar o processo directamente e não existe gateway — nesse caso documentar a excepção no README do MCP com a razão concreta, e usar sempre serveStdio do SDK v2 (nunca StdioServerTransport manual).
  3. Node.js 20+, ESM ("type": "module"), zod/v4 (peer ^4.2.0) — nunca zod v3, nunca require().
  4. Nunca construir comandos shell/SQL por interpolação de string quando o MCP faz ponte para SSH/CLI externos (ex.: WP-CLI). Dados do utilizador passam sempre por STDIN (texto ou base64), nunca concatenados num comando ssh ... "...". Ver references/best-practices.md §Segurança — regra escrita depois de uma injecção de comandos real ter sido encontrada e corrigida em produção (mcp-kivicare, 19-08-2026, ver Healing Log no fim deste ficheiro).

Se qualquer um destes 4 pontos não puder ser cumprido, parar e perguntar antes de prosseguir — não decidir sozinho por uma alternativa mais rápida.

Contexto NotebookLM

Consultar ANTES de executar:

mcp__notebooklm__notebook_query({
  notebook_id: "73102308-70ef-403e-9be9-eae0cfc62d55",
  query: "<adaptar ao contexto do pedido>"
})

Procedimentos obrigatórios — consultar antes de criar/modificar MCPs:

Regra #48: Novos MCPs são desenvolvidos localmente no desktop em /media/ealmeida/Dados/Dev/<nome-mcp> (CT 102 extinto em 20-04-2026). Após validação, mover para ~/mcp-servers/ em produção.


Comandos

Comando Descrição
/mcp-dev create <nome> Criar scaffold TypeScript completo
/mcp-dev config <nome> Configurar MCP em ~/.claude.json
/mcp-dev test <nome> Testar conexão e listar ferramentas
/mcp-dev eval <nome> Executar evaluations do MCP
/mcp-dev docs <nome> Gerar documentação Obsidian
/mcp-dev list Listar MCPs em ~/mcp-servers/
/mcp-dev status Estado dos MCPs activos na sessão

Workflow de 4 Fases

Fase 1: Research

  1. Consultar NotebookLM (notebook acima)
  2. Verificar MCPs existentes — evitar duplicação
  3. Identificar ferramentas necessárias e nomear segundo padrão
  4. Transporte: HTTP obrigatório (Streamable HTTP via SDK v2, createMcpHandler). stdio só com justificação escrita explícita — ver secção Transportes.
  5. Criar spike/PoC se tecnologia desconhecida

Nomenclatura de tools: {serviço}_{acção}_{recurso} em snake_case, máx. 40 caracteres.

# Correcto
get_customer_notes, create_project_task, list_invoice_items

# Errado
getCustomerNotes (camelCase), get_customer_notes_with_all_billing_details (>40 chars)

Fase 2: Implementation

  1. Scaffold local no desktop: /media/ealmeida/Dados/Dev/<nome-mcp>/
  2. Implementar tools com annotations obrigatórias e validação Zod (z.object(...) de zod/v4)
  3. McpServer deriva capabilities automaticamente de registerTool/registerResource/registerPrompt — nunca declarar capabilities à mão (isso é API de baixo nível v1, proibida)
  4. Responses em dual format: Markdown (text) + JSON (structuredContent)
  5. Erros accionáveis: causa + próximos passos

Annotations obrigatórias em cada tool — vão directo na config de registerTool (sem passo de inferência separado no v2):

server.registerTool(
  'get_customer',
  {
    description: 'Obtém dados de um cliente pelo ID',
    inputSchema: z.object({ customer_id: z.number().int().positive() }),
    annotations: {
      readOnlyHint: true,       // não modifica estado
      destructiveHint: false,   // não é destrutiva
      idempotentHint: true,     // mesmo resultado em chamadas repetidas
      openWorldHint: false,     // opera em sistema fechado (interno)
    },
  },
  async ({ customer_id }) => { /* ... */ }
);

Dual format de resposta:

return {
  content: [{ type: 'text', text: `# Cliente ${d.name}\n**Email:** ${d.email}` }],
  structuredContent: { id: d.id, name: d.name, email: d.email }
};

Erros accionáveis:

return {
  content: [{
    type: 'text',
    text: [
      `Erro ao obter cliente ID ${id}.`,
      `Causa: ${error.message}`,
      `Verificar: 1) ID existe  2) Permissões  3) Conexão BD`
    ].join('\n')
  }],
  isError: true
};

Fase 3: Review

  1. Checklist de segurança (ver references/best-practices.md)
  2. pnpm audit — sem vulnerabilidades críticas
  3. Validar limites de nomes de tools (máx. 40 chars)
  4. Testar build: npm run build
  5. Testar manualmente via HTTP: curl -s -X POST http://127.0.0.1:32XX/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
  6. Documentar decisões em ADR se necessário

Grep de validação rápida:

grep -rn '`.*\${.*}`' src/ | grep -i 'select\|insert\|update\|delete'
grep -rn 'Math.random' src/
# Comandos shell/ssh interpolados (ver Regra de Ouro §4) — qualquer resultado exige revisão manual
grep -rn 'exec(\|execSync(\|spawn(.*sh\b' src/ | grep -i '\${'

Fase 4: Evaluations

Criar e executar testes estruturados antes do deploy.

10 evaluations obrigatórias por MCP (ver references/evaluation-guide.md):

# Pergunta Cenário
1 Tool principal funciona com input válido? Input mínimo válido
2 Input inválido retorna erro accionável? Parâmetro obrigatório em falta
3 Recurso inexistente retorna erro claro? ID=99999
4 Operações idempotentes são estáveis? Chamada repetida com mesmos params
5 Operações destrutivas apagam correctamente? Delete em recurso existente
6 Tools read-only não alteram estado? Get + verificar estado antes/depois
7 Paginação funciona com listas grandes? 1000+ registos, página 2
8 Auth inválida é rejeitada graciosamente? API key removida
9 structuredContent é consistente com text? Comparar campos nos dois formatos
10 Performance < 5s em p95? 10 chamadas consecutivas

Executar:

npm run eval       # evaluations
npm run eval:ci    # build + evaluations (para CI/CD)

Estrutura de Projecto

/media/ealmeida/Dados/Dev/mcp-<nome>/   # Desenvolvimento (local, desktop)
├── package.json
├── tsconfig.json
├── src/
│   ├── server.ts               # Factory McpServer + registerTool (partilhado)
│   ├── http.ts                 # Entry point HTTP (createMcpHandler + Express) — obrigatório
│   └── stdio.ts                # Entry point stdio (serveStdio) — só se excepção justificada
├── eval/
│   └── run-evals.ts           # Evaluations automáticas (Client + StreamableHTTPClientTransport in-process)
├── .env.example
├── README.md
└── .gitignore

/home/ealmeida/mcp-servers/mcp-<nome>/   # Produção

Configuração

~/.claude.json (HTTP — obrigatório):

{
  "mcpServers": {
    "<nome>": { "type": "http", "url": "http://127.0.0.1:32XX/mcp" }
  }
}

~/.claude.json (stdio — apenas excepção documentada):

{
  "mcpServers": {
    "<nome>": { "command": "node", "args": ["/home/ealmeida/mcp-servers/<nome>/dist/stdio.js"] }
  }
}

Transportes

Transporte Estado Quando usar
Streamable HTTP (SDK v2) Obrigatório Todos os MCPs novos — acesso remoto, gateway, múltiplos clientes
stdio (SDK v2, serveStdio) Excepção documentada Só quando o host lança o processo directamente e não há gateway. Justificar no README do MCP.
SSE Deprecated Retrocompatibilidade apenas — nunca usar em MCP novo

MCPs Existentes (Referência)

MCP Path Tools Transporte
desk-crm-v3 ~/mcp-servers/desk-crm-v3/ 150+ SSE :3100
mem0 gateway.descomplicar.pt/v1/mem0/mcp (remoto) 5 HTTP
google-workspace (npm package) 42 stdio
filesystem (npm package) 8 stdio

Referências

Ficheiro Conteúdo
references/best-practices.md Nomenclatura, annotations, segurança (incl. anti-injecção de comandos shell), SQL Perfex
references/evaluation-guide.md Guia completo de evaluations, script automatizado (Client v2 in-process)
references/templates.md Templates TypeScript v2 prontos (server factory, HTTP obrigatório, stdio excepcional, systemd)

Agente especializado: mcp-protocol-developer — desenvolvimento complexo, debug, optimização.


Changelog

v3.0.0 (2026-08-19)

  • SDK TypeScript v2 obrigatório (@modelcontextprotocol/server, ver ts.sdk.modelcontextprotocol.io/v2) — @modelcontextprotocol/sdk v1 descontinuado nesta casa.
  • Transporte HTTP obrigatório; stdio passa a excepção documentada (antes era "válido" sem restrição).
  • API de baixo nível Server + setRequestHandler(Schema, …) proibida — só McpServer + registerTool/registerResource/registerPrompt.
  • Capabilities manuais removidas do fluxo (v2 deriva automaticamente) — a secção "anti-erro 471" do v1 já não se aplica ao padrão obrigatório.
  • inferAnnotations() removido (não existe em v2) — annotations sempre inline na config de registerTool.
  • Nova secção "Regra de Ouro" no topo do ficheiro, com 4 obrigações sem excepção silenciosa.
  • references/best-practices.md §Segurança recebeu regra de anti-injecção de comandos shell (bridge SSH/CLI), motivada por incidente real corrigido em mcp-kivicare (19-08-2026, 8 bugs, incl. injecção de comandos crítica).
  • Templates (references/templates.md) reescritos para a API v2 (createMcpHandler, createMcpExpressApp, serveStdio).

v2.0.0 (2026-03-10)

  • Refactorização: SKILL.md de 1163 para <500 linhas (progressive disclosure)
  • Fase 4: Evaluations adicionada ao workflow (padrão mcp-builder Anthropic)
  • Nomenclatura tools: {serviço}_{acção}_{recurso} snake_case documentada
  • Annotations obrigatórias (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)
  • inferAnnotations() mencionado como padrão automático
  • Dual format de resposta (JSON + Markdown) documentado
  • Erros accionáveis com causa + próximos passos
  • Extracto para references/: best-practices, evaluation-guide, templates

v1.3.0 (2026-01-31)

  • HTTP StreamableHTTP como padrão oficial
  • SSE marcado como deprecated
  • Checklist de segurança (audit 164 tools)

v1.2.0 (2026-01-27)

  • Template SSE com http nativo
  • systemd service template

v1.0.0 (2026-01-27)

  • Versão inicial

Quando NÃO Usar

  • Para tarefas fora do domínio de desenvolvimento MCP
  • Quando outra skill mais específica está disponível
  • Para operações simples que não requerem MCP

Protocolo

  1. Consultar NotebookLM e PROCs relevantes
  2. Executar as 4 fases: Research -> Implementation -> Review -> Evaluations
  3. Validar resultados antes de concluir
  4. Reportar status e próximos passos

Skill v3.0.0 | Descomplicar® | 2026-08-19


Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

{"date":"","issue":"","fix":"","source":"user|auto"}
{"date":"2026-08-19","issue":"mcp-kivicare: runRawSqlQuery interpolava a query directamente num comando `ssh ... wp db query \"...\"` — injecção de comandos shell explorável","fix":"query sempre por STDIN (`wp db query < stdin`), nunca interpolada no comando remoto","source":"auto"}
{"date":"2026-08-19","issue":"mcp-kivicare: hooks nativos do KiviCare (kc_appointment_status_update) disparados com um inteiro em vez do objecto do modelo — TypeError fatal num listener nativo, registo órfão em produção","fix":"recarregar o modelo (ex.: KCAppointment::find($id)) antes de disparar qualquer hook nativo; ler a assinatura real do hook no código-fonte do sistema alvo antes de o chamar","source":"auto"}
{"date":"2026-08-19","issue":"mcp-kivicare: basic_data do paciente gravado como array PHP em vez do JSON que o sistema nativo espera (json_encode com JSON_UNESCAPED_UNICODE) — corrompia a leitura no admin nativo","fix":"replicar exactamente o formato de serialização do sistema nativo (grep ao código-fonte real), nunca assumir a partir da forma dos dados em memória","source":"auto"}

Adicionar nova linha após cada erro corrigido.