Principal Configurações avançadas Como criar um servidor MCP compatível com a ClaudIA

Como criar um servidor MCP compatível com a ClaudIA

Última atualização em Sep 02, 2026

A tela ClaudIA > Servidores MCP permite conectar ferramentas externas aos seus agentes usando o Model Context Protocol (MCP). Este artigo descreve exatamente o que a plataforma exige de um servidor para que ele passe no teste de conexão e funcione em produção.

A ClaudIA usa um subconjunto pequeno e bem definido do protocolo. Se o seu servidor cumprir os pontos abaixo, ele vai funcionar.

1. Transporte: Streamable HTTP

A ClaudIA fala apenas o transporte Streamable HTTP da especificação MCP (revisão 2025-03-26 ou mais recente).

Na prática, isso significa:

  • Um único endpoint HTTP (por exemplo, https://seu-host/mcp) que aceita POST com um corpo JSON-RPC 2.0.
  • A resposta pode ser Content-Type: application/json (um único objeto JSON) ou Content-Type: text/event-stream (SSE). Os dois formatos são aceitos.
  • O servidor pode ser stateless ou stateful (devolvendo o header Mcp-Session-Id no initialize). Ambos funcionam.

O que não funciona:

  • Servidores stdio (o formato dos tutoriais para Claude Desktop). Eles não têm URL HTTP.
  • O transporte HTTP+SSE antigo (protocolo 2024-11-05), com endpoints separados /sse e /messages. A ClaudIA não faz fallback para esse formato.

A maioria dos quickstarts públicos ensina stdio ou SSE. Confira qual transporte o seu framework está usando antes de testar.

2. Handshake e métodos usados

A cada uso, a ClaudIA abre uma sessão nova e executa, nesta ordem:

  1. initialize: o servidor precisa responder com capabilities.tools declarado.
  2. notifications/initialized
  3. tools/list: para descobrir as ferramentas.
  4. tools/call: quando o agente decide usar uma ferramenta.

Nenhum outro recurso do protocolo é consumido: resources, prompts, sampling, elicitation, roots e a notificação tools/list_changed são ignorados. O servidor não precisa implementá-los.

Como cada chamada abre uma sessão nova, o servidor precisa aceitar muitas sessões curtas sem problema.

3. URL

  • Cole a URL completa do endpoint MCP, com o path (ex.: https://seu-host/mcp ou https://seu-host/v1/minha-api/mcp).
  • A URL é usada exatamente como colada. A plataforma não adiciona /mcp automaticamente.
  • Apenas http e https são aceitos.

4. Autenticação

Tipo escolhido na tela O que o servidor recebe
Nenhum Nenhum header de autenticação
Bearer Token Authorization: Bearer <token>
API Key X-Api-Key: <token>

Você também pode adicionar cabeçalhos personalizados. Os nomes Authorization, X-Api-Key e X-Authorization são reservados e não podem ser usados como cabeçalho personalizado.

Se o servidor responder 401 ou 403, o teste de conexão mostra "Falha na autenticação".

5. Formato das ferramentas

Cada item retornado em tools/list precisa ter:

  • name: identificador único. Use apenas letras minúsculas, números, _ e -. A ClaudIA prefixa o nome com o identificador do servidor, então nomes curtos e descritivos funcionam melhor.
  • description: texto claro do que a ferramenta faz e quando usar. É isso que o modelo lê para decidir chamar a ferramenta.
  • inputSchema: JSON Schema do tipo object descrevendo os parâmetros.

Exemplo mínimo:

{
  "name": "consultar_pedido",
  "description": "Retorna o status de um pedido a partir do número informado pelo cliente.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "numero_pedido": { "type": "string", "description": "Número do pedido" }
    },
    "required": ["numero_pedido"]
  }
}

6. Formato do resultado de tools/call

  • Retorne o resultado em content como blocos {"type": "text", "text": "..."}. É esse texto que o agente lê.
  • structuredContent é aceito, mas o agente usa apenas o bloco de texto. Se usar structuredContent, mantenha também o JSON serializado em um bloco text, como a especificação recomenda.
  • Para erros de negócio (pedido não encontrado, API externa indisponível), retorne isError: true com a explicação em content. O agente recebe a mensagem e consegue reagir.

7. Tempo limite

Etapa Limite
Conexão TCP/TLS 5 segundos
initialize e tools/list 30 segundos
tools/call em produção 180 segundos

Um servidor que demora mais que isso aparece como "Servidor inacessível" no teste ou como falha de ferramenta na conversa.

8. O que o botão "Testar conexão" faz

O teste executa exatamente o mesmo initialize + tools/list que o agente executa em produção, com a URL, o tipo de autenticação e os cabeçalhos informados na tela. Se passar, o servidor será chamado dessa mesma forma. Nada é salvo durante o teste.

Mensagem na tela Causa provável
Servidor inacessível DNS, porta fechada, TLS inválido, timeout, ou o servidor respondeu 404/405 ao POST (sintoma típico de servidor SSE antigo ou stdio)
A resposta do servidor não é uma resposta MCP válida O corpo não é JSON-RPC 2.0, ou o initialize não declarou capabilities.tools
O servidor retornou um erro O servidor respondeu com um error JSON-RPC ao initialize ou ao tools/list
Falha na autenticação 401 ou 403

9. Exemplos mínimos

Python (FastMCP, SDK oficial)

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("meu-servidor", stateless_http=True)

@mcp.tool()
def consultar_pedido(numero_pedido: str) -> str:
    """Retorna o status de um pedido a partir do número informado pelo cliente."""
    return f"Pedido {numero_pedido}: em transporte"

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

O endpoint fica em http://host:8000/mcp. Publique atrás de HTTPS e cole essa URL na ClaudIA.

TypeScript (SDK oficial)

import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";

const app = express();
app.use(express.json());

app.post("/mcp", async (req, res) => {
  const server = new McpServer({ name: "meu-servidor", version: "1.0.0" });
  server.registerTool(
    "consultar_pedido",
    {
      description: "Retorna o status de um pedido a partir do número informado pelo cliente.",
      inputSchema: { numero_pedido: z.string() },
    },
    async ({ numero_pedido }) => ({
      content: [{ type: "text", text: `Pedido ${numero_pedido}: em transporte` }],
    }),
  );
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
  res.on("close", () => { transport.close(); server.close(); });
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

app.listen(3000);

Checklist rápido

  • [ ] Endpoint único aceitando POST JSON-RPC (Streamable HTTP)
  • [ ] initialize responde com capabilities.tools
  • [ ] tools/list retorna name, description e inputSchema
  • [ ] tools/call retorna content com blocos text
  • [ ] Autenticação via Authorization: Bearer ou X-Api-Key, conforme escolhido na tela
  • [ ] Responde em menos de 30 segundos ao initialize e ao tools/list
  • [ ] URL completa, com path, em HTTPS

Referências