Rene-Roscher/mcp-server-design

Projeta e revisa servidores MCP que agentes usam com segurança em produtos multi-tenant: ferramentas como um adaptador na camada de serviço, um tenant por conexão vinculado ao token, direitos verificados por chamada, classes de efeito com pré-visualização e confirmação, proteção contra repetição, kill switch, formatos de erro, avaliações de modelo. Use ao construir ou revisar ferramentas ou servidores MCP. Não se aplica a uso de servidores MCP ou design REST.

O que é mcp-server-design?

Esta skill define princípios rigorosos para projetar servidores MCP (Model Context Protocol) que expõem produtos a agentes de IA de forma segura e confiável, especialmente em ambientes multi-tenant. Ela aborda desde a arquitetura de código (ferramentas como um segundo adaptador na camada de serviço, nunca chamando APIs ou ORMs diretamente) até controles de segurança críticos, como vinculação de um tenant por conexão via token, verificação de direitos em tempo real a cada chamada, e classes de efeito (leitura, gravação silenciosa, notificação, despertar, alerta, exclusão) que determinam o comportamento do sistema. A skill é mais útil para desenvolvedores construindo ou revisando servidores MCP para produtos SaaS multi-tenant, onde um erro pode levar o modelo a agir no tenant errado, duplicar gravações, ou executar ações sem confirmação humana. Ela se baseia em padrões como o MCP schema, melhores práticas de segurança e critérios de revisão de conectores, fornecendo testes invariantes para cada regra. Não se aplica a design de APIs REST/GraphQL, chatbots não-MCP, ou configuração de clientes para usar servidores de terceiros.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Rene-Roscher/skills/tree/HEAD/plugins/api/skills/mcp-server-design

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Design de servidor MCP

Esta skill decide como um servidor MCP expõe um produto a agentes: onde as ferramentas ficam no código, como uma conexão se vincula a um tenant e uma pessoa, quais chamadas precisam de confirmação humana e como resultados e erros guiam o modelo para a próxima chamada correta. A sintaxe do protocolo segue a especificação MCP (revisão 2026-07-28 quando isto foi escrito) e a documentação do SDK. Escopo de consulta, catálogos de permissões e formatos de identificador vêm de tenant-isolation, authorization-rbac e dual-key-identifiers. A falha que isso previne: um modelo que escolhe o tenant errado, envia um e-mail para um cliente duas vezes ou age com base em texto plantado por um terceiro, porque o servidor deixou uma porta aberta para o modelo, o cliente ou a descrição de uma ferramenta.

Aplica-se quando / não se aplica

  • Aplica-se: construir um servidor MCP para um produto, adicionar ou revisar uma ferramenta, escolher como credenciais MCP se vinculam a tenants e pessoas, ferramentas que notificam clientes, contactam pessoas, silenciam alertas ou excluem, gravações duplicadas após novas tentativas do cliente, formatos de erro e resultado, nomes e descrições de ferramentas, conjuntos de ferramentas para modelos pequenos, avaliações de uso de ferramentas.
  • Não se aplica: configurar um cliente para usar o servidor MCP de outra pessoa, design de endpoints REST ou GraphQL, chatbots e comandos de barra que não são MCP, escrita de prompts para o assistente próprio de um produto, limites de taxa em rotas não-MCP.

Regras

Mais importante primeiro. Exemplos usam um sistema de reservas: reservas, clientes, técnicos.

  • [invariante] O servidor impõe o que não pode dar errado; descrições e anotações apenas orientam. Cada portão abaixo é executado no código do servidor em cada chamada. Por que: anotações são dicas, e existem clientes que aprovam automaticamente ou nunca perguntam. Teste: chame cada ferramenta protegida de um cliente JSON-RPC puro que ignora dicas; todos os guardas ainda disparam. Fonte: MCP schema 2026-07-28, ToolAnnotations: "Os clientes nunca devem tomar decisões de uso de ferramentas com base em ToolAnnotations recebidas de servidores não confiáveis" (https://modelcontextprotocol.io/specification/2026-07-28/schema, verificado em 2026-10-31).
  • [invariante] Ferramentas são um segundo adaptador na camada de serviço: elas chamam os mesmos serviços de domínio que a interface do usuário e a API, nunca a própria API HTTP em loopback e nunca o ORM diretamente. As verificações que protegem dados (limites, listas de permissão de URL contra SSRF, propriedade de registros referenciados) estão no serviço, não apenas em um controlador ou solicitação de formulário. Um caminho de gravação por função. Por que: um adaptador fino herda todas as verificações que apenas seus adaptadores irmãos executaram. Teste: um teste de arquitetura falha em chamadas de persistência em classes de ferramentas; por ferramenta de gravação, uma entrada que a API rejeita é rejeitada pela ferramenta. Fonte: reproduzível com o teste acima.
  • [invariante] Uma conexão, um tenant: o tenant é vinculado na credencial quando a conexão é criada, nenhum esquema de ferramenta tem um parâmetro de tenant, um argumento como workspace_id é rejeitado como desconhecido, e cada identificador é resolvido dentro do tenant vinculado. Uma credencial que serve vários tenants carrega o tenant no transporte (caminho ou cabeçalho) e o verifica contra a credencial, nunca em um argumento da ferramenta. Por que: um parâmetro de tenant permite que o modelo escolha o tenant. Teste: por ferramenta com uma referência, passe o identificador válido de outro tenant; espere not_found e uma linha inalterada. Fonte: especificação de ferramentas MCP, o conjunto de ferramentas "PODE variar de acordo com a autorização apresentada na solicitação" (https://modelcontextprotocol.io/specification/2026-07-28/server/tools); melhores práticas de segurança, estado chave por um ID de usuário "derivado do token verificado em vez de fornecido pelo cliente" (https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices); ambos verif. em 2026-10-31.
  • [invariante] Os direitos são cortados ao vivo: direitos efetivos = direitos do token ∩ direitos atuais da pessoa que criou a conexão, calculados em cada chamada tools/list e tools/call. Os direitos do token são limitados na criação, um criador removido ou desativado encerra a conexão, a revogação passa por um serviço que audita. Por que: direitos congelados em um token sobrevivem a uma mudança de função. Teste: remova a função do criador, chame uma ferramenta de gravação; recusado na próxima chamada. Fonte: especificação de ferramentas MCP, servidores DEVEM "Implementar controles de acesso adequados" (verif. em 2026-10-31).
  • [invariante] Nenhum usuário ambiente em solicitações MCP: o middleware vincula um contexto de conexão (tenant, criador, direitos ao vivo) e deixa o slot de usuário atual do framework vazio; as ferramentas leem o ator do contexto, os serviços recebem o ator como parâmetro. Por que: com o proprietário definido como usuário atual, uma verificação de política perdida em uma ferramenta passa porque os proprietários podem fazer tudo; sem usuário, falha fechada. Teste: um teste de arquitetura proíbe portão, política e auxiliares de usuário atual no código da ferramenta; uma verificação de política adicionada deliberadamente faz a chamada falhar. Fonte: reproduzível com o teste acima.
  • [invariante] Cada ferramenta tem exatamente uma classe de efeito: leitura, gravação silenciosa, notificar (atinge clientes ou altera o que veem), despertar (contacta ou chama uma pessoa), alertar (silencia, pausa ou redireciona alertas), excluir. Derive a classe do caminho do código (eventos, listeners, observadores, trabalhos, e-mails), não do nome, e divida uma ferramenta que abrange duas. Por que: dicas, balde de taxa, dever de pré-visualização e troca de conexão seguem da classe. Teste: com fila, e-mail e falsificações de evento, ferramentas silenciosas não despacham notificação. Fonte: critérios de revisão de conectores, ferramentas de leitura/gravação genéricas são rejeitadas e as gravações são divididas por tipo de ação (https://claude.com/docs/connectors/building/review-criteria, verif. em 2026-10-31).
  • [invariante] Notificar, despertar, alertar e excluir levam duas etapas. A ferramenta apenas prepara: armazena uma ação pendente (conexão, ferramenta, argumentos normalizados e digest, hash do conteúdo que será enviado, expiração) e retorna PREVIEW, um confirm_token e um confirm_summary escrito pelo servidor. Apenas confirm_action executa, após verificar conexão, não usado, não expirado, não rejeitado, resumo exato, um bloqueio, direitos ao vivo e interruptores, e uma preparação nova cujo hash de conteúdo ainda corresponde (senão uma nova pré-visualização, token antigo morto). Por que: nem o modelo nem o cliente perguntam a uma pessoa de forma confiável, e o texto aprovado pode mudar entre as etapas. Teste: pré-visualização sozinha não envia nada; tokens reutilizados, expirados, estrangeiros e de resumo errado falham; uma edição entre as etapas produz changed_since_preview. Fonte: especificação MCP tools, "DEVE haver sempre um humano no loop com a capacidade de negar invocações de ferramentas"; requisitos de servidor MRTR: estado ecoado por um cliente é "entrada controlada pelo atacante", vinculado ao principal, expiração curta e digest de parâmetros, uso único imposto no servidor (https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr); ambos verif. em 2026-10-31.
  • [invariante] Proteção contra repetição em cada gravação silenciosa: impressão digital = conexão + ferramenta + SHA-256 do JSON canônico dos argumentos normalizados (chaves ordenadas em todos os níveis); um acerto dentro da janela retorna o primeiro resultado com replayed: true e não executa nada. Uma idempotency_key opcional é vinculada ao digest do argumento. O cache contém saída do apresentador, nunca segredos de uso único. Por que: um stream quebrado perde a solicitação em andamento e os clientes DEVEM reenviá-la com um novo ID, então uma gravação que foi executada chega novamente. Teste: mesma chamada duas vezes com IDs JSON-RPC diferentes; uma linha, segundo resultado replayed: true. Fonte: MCP changelog 2026-07-28, mudança principal 9 (https://modelcontextprotocol.io/specification/2026-07-28/changelog); Claude Code repete uma chamada pendente para ferramentas marcadas como idempotentHint ou readOnlyHint uma vez em uma nova conexão (https://code.claude.com/docs/en/mcp); ambos verif. em 2026-10-31.
  • [invariante] Toda ferramenta de criação tem uma ferramenta de atualização irmã e um guarda de duplicação em uma chave de negócio. Um acerto retorna um erro nomeando o identificador existente e a ferramenta de atualização; criar mesmo assim precisa de separate: true e um motivo. Os guardas leem colunas síncronas (created_by, created_at), nunca um log de auditoria enfileirado. Ferramentas de edição não têm parâmetro de notificação. Por que: ao ser solicitado a "melhorar o texto", um modelo cria um segundo objeto a menos que seja impedido. Teste: crie duas vezes com a mesma chave; uma linha, um erro nomeando-a. Fonte: reproduzível com o teste acima.
  • [invariante] Atualizações carregam a versão que o chamador leu: objetos e mensagens nos resultados têm uma version (hash de conteúdo), ferramentas de atualização e edição a exigem, uma desatualizada retorna conflict com o estado atual. Por que: um agente trabalhando com uma leitura antiga sobrescreve a edição de um colega. Teste: leia, altere a linha em outro lugar, atualize com a versão antiga; conflict, linha inalterada. Fonte: reproduzível com o teste acima.
  • [invariante] Ferramentas em lote usam identificadores explícitos, ou um filtro mais um expected_count obrigatório; quando a contagem de correspondências difere, retorna as correspondências e não executa nada. Por que: um filtro mais amplo do que o modelo esperava multiplica um erro. Teste: um filtro correspondendo a 12 reservas com expected_count: 3; erro lista 12, nada mudou. Fonte: reproduzível com o teste acima.
  • [invariante] Valide cada argumento no servidor com as próprias regras da ferramenta e rejeite campos desconhecidos com a lista de permitidos. Por que: SDKs nem sempre verificam argumentos contra inputSchema, e um campo ignorado faz o modelo acreditar que definiu algo. Teste: um campo extra retorna a lista permitida e não escreve nada. Fonte: especificação MCP tools, servidores DEVEM "Validar todas as entradas da ferramenta" (verif. em 2026-10-31).
  • [invariante] Texto de terceiros em resultados não é confiável: texto que um cliente, usuário final, sistema externo ou upload pode escrever (notas, corpos de e-mail, payloads de webhook, mensagens de erro remotas) é truncado, removido de caracteres de controle e retornado sob untrusted_text com uma nota para não seguir instruções nele; corpos brutos ficam de fora. Descrições descrevem a ferramenta e nunca dizem ao modelo como se comportar. Por que: texto injetado que direciona uma ferramenta com efeito externo é o principal risco; a etapa de pré-visualização é a segunda linha. Teste: um canário de injeção em cada campo de terceiros aparece apenas dentro do wrapper. Fonte: especificação MCP tools, servidores DEVEM "Sanitizar saídas da ferramenta"; critérios de revisão de conectores rejeitam padrões de injeção de prompt em descrições; ambos verif. em 2026-10-31.
  • [invariante] Resultados não carregam segredos e apenas os dados pessoais necessários para a tarefa: apresentadores com listas explícitas de campos, nunca um serializador de registro inteiro; logs contêm nome da ferramenta, resultado e IDs públicos, nunca argumentos. Por que: cada resultado vai para o provedor de modelo do usuário. Teste: preencha cada campo secreto de um fixture com um valor de isca, chame cada ferramenta de leitura, grep resultados e logs; nenhuma isca. Fonte: reproduzível com o teste acima; manutenção de registros em gdpr-engineering.
  • [invariante] Falhas de negócio, validação e permissão são erros de execução da ferramenta (isError: true) cujo texto começa com Error:, nomeia causa, correção e a ferramenta correta com identificadores reais, e termina com uma linha de detalhes JSON. "Não encontrado" aponta para uma ferramenta find_, nunca para criar. Uma ferramenta oculta por direitos, conjunto de ferramentas ou plano responde com esse motivo. Por que: o modelo se autocorrige apenas em erros que vê e entende. Teste: cada caminho de erro no conjunto de contratos começa com Error: e tem uma linha JSON analisável. Fonte: MCP schema, CallToolResult.isError: erros de ferramenta "DEVEM ser reportados dentro do objeto de resultado ... Caso contrário, o LLM não seria capaz de ver que um erro ocorreu e autocorrigir-se"; critérios de revisão de conectores falham em respostas genéricas "Internal Server Error"; ambos verif. em 2026-10-31.
  • [invariante] O bloco de texto e structuredContent carregam o mesmo JSON, e um outputSchema declarado cobre cada resultado estruturado, incluindo erros. Por que: clientes diferem em qual canal atinge o modelo, e eles DEVEM validar contra um esquema declarado. Teste: para cada resultado no conjunto, o texto analisado é igual a structuredContent. Fonte: especificação MCP tools, uma ferramenta com conteúdo estruturado "DEVE também retornar o JSON serializado em um bloco TextContent" (verif. em 2026-10-31).
  • [invariante] Hora e dinheiro são trabalho do servidor: horas chegam como hora local mais fuso IANA ou ISO 8601 com deslocamento, nunca sem; horas locais inexistentes e ambíguas são rejeitadas com as opções; cada hora em um resultado mostra dia da semana, hora local com fuso, UTC e distância de agora. Totais, impostos e arredondamentos são computados no servidor a partir de strings decimais ou unidades menores inteiras. Por que: erros de um dia a mais e horário de verão são invisíveis sem o dia da semana. Teste: 2026-03-29 02:30 em Europe/Berlin é rejeitado; 2026-10-25 02:30 retorna ambos os deslocamentos. Fonte: reproduzível com o teste acima.
  • [invariante] Um kill switch em um lugar: um sinalizador global, definido por um comando CLI e uma alternância de administrador que ambos auditam, faz cada chamada MCP retornar 503 com Retry-After enquanto as conexões permanecem; um interruptor por tenant com seu padrão definido uma vez permite que um administrador de tenant desligue o acesso do agente. Por que: um incidente precisa de um movimento que pare todas as gravações do agente. Teste: sinalizador ativado, chame uma ferramenta de gravação; 503, nenhuma linha, nenhum trabalho. Fonte: reproduzível com o teste acima.
  • [invariante] Cada gravação MCP é auditada com canal mcp, nome da conexão e do cliente, definido no ponto de entrada como colunas, e list_recent_changes mostra o que esta conexão mudou. Por que: os tenants veem o que um agente fez, e um agente que perdeu o contexto encontra seu rascunho em vez de criar outro. Teste: cada ferramenta de gravação produz exatamente uma linha de auditoria com canal mcp. Fonte: reproduzível com o teste acima.
  • [invariante] Credenciais MCP e API não se cruzam: tokens MCP têm seu próprio tipo e prefixo, são armazenados com hash, mostrados uma vez e são rejeitados por toda rota de API; tokens de API e cookies de sessão são rejeitados pelo endpoint MCP. Com OAuth, aceite apenas tokens emitidos para este servidor e nunca passe um adiante. Valide Origin. Por que: tokens MCP ficam em texto simples nos arquivos de configuração do cliente. Teste: cada emparelhamento retorna 401; um Origin ruim retorna 403. Fonte: especificação de autorização MCP, servidores "NÃO DEVEM aceitar ou transitar nenhum outro token" (https://modelcontextprotocol.io/specification/2026-07-28/server/authorization, verif. em 2026-10-31).
  • [invariante] Depreciação, ferramentas de namespace e conjuntos: ferramentas não são removidas adicionando .deprecated ou uma descrição que diz "não use"; existe um plano por escrito com datas, substitutos, logs e validação do modelo antes de remover. Os prefixos de namespace (bookings_, customers_) são um diretório, não autorização. Conjuntos de ferramentas para modelos pequenos são definidos com ferramentas menores, combinadas, com identificadores e resultados que cabem em uma única resposta de modelo. Por que: modelos são treinados em documentos de especificação e podem continuar chamando ferramentas com nomes antigos. Fonte: reproduzível com o teste acima.
  • [invariante] Erros de tempo limite são tratados com transações demarcadas ou usando a menor granularidade atômica; ferramentas longas implementam progresso (progressToken, totalProgress na notificação). Resultados consistentemente lentos são sinalizados ao cliente marcando o método como slowTool. Por que: clientes como Claude Code têm um tempo limite para cada chamada de ferramenta. Teste: atrase uma ferramenta além do tempo limite do cliente; o cliente vê o progresso ou um erro. Fonte: especificação MCP, Progress_Notification, ToolAnnotations.slowTool.

Habilidades Relacionadas