Converter API em servidor MCP: REST e OpenAPI passo a passo
Encapsule uma API REST existente como um servidor MCP que agentes possam chamar sem adivinhar. Gere ferramentas a partir de um arquivo OpenAPI com FastMCP, construa-as à mão em TypeScript, trate autenticação e tarefas lentas de imagem ou vídeo e depois teste com o Inspector e publique via stdio ou HTTP.
Sua API REST já funciona, mas os agentes ainda se atrapalham com ela. Eles chutam nomes de parâmetros, travam diante de respostas JSON de 40 KB e chamam DELETE quando queriam chamar GET. A solução não é um modelo mais inteligente. É uma camada fina no meio: um servidor MCP que informa ao agente exatamente quais ações existem, como é a entrada de cada uma e o que volta. Este tutorial mostra como converter uma API em servidor MCP a partir da especificação OpenAPI, primeiro com código gerado e depois à mão, incluindo autenticação, tarefas lentas, testes e deploy.
Você precisa de três coisas antes de começar: uma API que você já consiga chamar com curl, o arquivo OpenAPI 3.x dela (ou paciência para escrever um) e um cliente MCP como Claude Desktop, Cursor ou VS Code para testar o resultado. Uma primeira versão funcional leva uma tarde. O acabamento é onde vai o tempo de verdade, e é também dele que vem a qualidade.
💡 Versão curta: o MCP empacota sua API em ferramentas. Cada ferramenta tem um nome, uma descrição e um JSON Schema para sua entrada. O agente escolhe as ferramentas lendo essas descrições, então as descrições importam mais do que a parte técnica do HTTP.
Por que empacotar uma API como MCP
A REST foi pensada para desenvolvedores que leem a documentação uma vez e escrevem código em cima dela. Um agente funciona de outro jeito. Ele lê o que o servidor lista no início da sessão e decide a chamada só com base nessa lista. Se a lista é vaga, ele chuta. Se a lista é enorme, ele consome a janela de contexto antes de o usuário digitar qualquer coisa.
Um servidor MCP resolve os dois problemas da mesma forma que uma telefonista: recebe um pedido claro, encaminha para a linha certa e devolve uma resposta limpa.
O que o agente realmente vê
Quando um cliente se conecta, ele pede ao servidor a lista de ferramentas. Cada item traz um name, um description, um inputSchema escrito em JSON Schema e, opcionalmente, um outputSchema e um conjunto de annotations. Essa é a superfície inteira. O agente nunca vê suas rotas, seus verbos HTTP nem seus códigos de status. Ele vê nomes, frases e schemas.
REST para MCP, de relance
Cada parte de uma operação OpenAPI tem um lugar no lado MCP:
REST / OpenAPI
Ferramenta MCP
operationId
Ferramenta name
summary e description
Ferramenta description
Parâmetros de path, query e body
inputSchema, um único objeto JSON Schema plano
Schema da resposta 200
outputSchema e conteúdo estruturado
Respostas 4xx e 5xx
Resultado com isError: true e uma mensagem legível
Esquema de segurança
Configuração do servidor: token em variável de ambiente, ou OAuth para servidores remotos
Links de paginação
Entradas explícitas cursor e limit
A saída estruturada e os output schemas chegaram com a revisão 2025-06-18 da especificação, então confirme que a versão do seu SDK os suporta antes de depender de outputSchema.
Mapear operações OpenAPI para ferramentas
Abra a especificação e resista à vontade de expor tudo. Uma API de 120 endpoints vira um servidor de 120 ferramentas, e só a lista de ferramentas pode consumir milhares de tokens em cada conversa. Comece pequeno, dê bons nomes e descreva as coisas como um colega descreveria.
Escolha operações, não endpoints
Faça quatro perguntas sobre cada endpoint antes de ele virar uma ferramenta:
Uma pessoa pediria a um assistente para fazer isso em linguagem simples?
É seguro chamar duas vezes caso o agente tente de novo?
A resposta cabe em alguns kilobytes, ou dá para cortá-la até caber?
Ele pertence a outro público, como administração, cobrança ou ferramentas internas?
Quem falha na primeira ou na última pergunta fica de fora. Cinco a dez ferramentas bem escolhidas superam cem ferramentas cruas. Fluxos de várias etapas merecem uma ferramenta: se "criar carrinho, adicionar itens, finalizar compra" sempre acontece em sequência, o agente deve ver uma única ação place_order.
Nomeie e descreva cada ferramenta
Parta de operationId e depois reescreva como verbo e substantivo. Uma boa descrição responde a três perguntas: o que a ferramenta faz, quando usá-la em vez das vizinhas e o que ela devolve.
Gerado
Reescrito
Nome
OrdersController_findAll
search_orders
Descrição
"Find all"
"Pesquise pedidos pelo e-mail do cliente, status ou intervalo de datas. Devolve até 20 pedidos com id, status e total. Use get_order para os itens do pedido."
Achate os parâmetros de path, query e body em um único objeto. Mantenha os enums, marque os campos obrigatórios, dê a cada propriedade uma descrição curta com um valor de exemplo e defina limites como maximum e maxLength para que o modelo não peça 10.000 linhas. Uma operação OpenAPI como esta:
{
"name": "get_order",
"description": "Fetch one order by id. Returns status, total and line items. Use search_orders when you only have an email.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "Order id, for example ord_8f2c1" }
},
"required": ["order_id"]
}
}
Duas formas de construir o servidor
Você pode gerar um servidor direto da especificação em minutos, ou escrever cada ferramenta à mão. A maioria das equipes faz as duas coisas: gera primeiro para ver a forma, depois ajusta à mão as cinco ferramentas que importam.
Gerar com FastMCP
A biblioteca Python FastMCP pode construir um servidor diretamente de um documento OpenAPI:
O servidor lê a especificação, cria as ferramentas e encaminha cada chamada pelo cliente httpx que você passa, que também é onde fica o cabeçalho de autenticação. Os mapas de rotas removem as rotas de administração e as internas antes que o agente as veja.
⚠️ Verificação de versão: o mapeamento padrão muda entre as versões principais do FastMCP. As versões recentes transformam cada operação em ferramenta, enquanto versões 2.x mais antigas mapeavam algumas rotas GET para resources. Fixe sua versão, defina os mapas de rotas explicitamente e confirme o caminho de importação na documentação da versão que você instalou.
Quando a geração não basta
A própria documentação do FastMCP avisa que servidores curados dão resultados visivelmente melhores para os modelos do que servidores convertidos automaticamente, especialmente em APIs com muitos endpoints e parâmetros. Você vai ver o motivo na primeira rodada de testes:
Nomes como get_orders_by_id_using_get que nenhuma pessoa escreveria
Descrições copiadas da documentação para desenvolvedores, escritas para leitores que já conhecem o sistema
Respostas que devolvem todos os campos, inclusive flags internas
Quatro ferramentas que deveriam ser uma só
Corrija nesta ordem: remova, renomeie, reescreva as descrições, enxugue as respostas, una os fluxos.
Construa à mão em TypeScript
Para as ferramentas que importam, o SDK oficial de TypeScript dá controle total. Instale @modelcontextprotocol/sdk e zod e depois registre cada ferramenta com um schema e um handler:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const API = "https://api.example.com";
const TOKEN = process.env.ORDERS_API_TOKEN;
const server = new McpServer({ name: "orders", version: "1.0.0" });
server.registerTool(
"get_order",
{
title: "Get order",
description:
"Fetch one order by id. Returns status, total and line items. Use search_orders when you only have an email.",
inputSchema: { order_id: z.string().describe("Order id, for example ord_8f2c1") },
annotations: { readOnlyHint: true },
},
async ({ order_id }) => {
const res = await fetch(`${API}/orders/${encodeURIComponent(order_id)}`, {
headers: { Authorization: `Bearer ${TOKEN}` },
});
if (!res.ok) {
return {
isError: true,
content: [{ type: "text", text: `Orders API returned ${res.status}. Check the id and try again.` }],
};
}
const order = await res.json();
return { content: [{ type: "text", text: JSON.stringify(order) }] };
}
);
await server.connect(new StdioServerTransport());
Dois detalhes fazem o trabalho pesado. A anotação readOnlyHint informa ao cliente que essa chamada pode rodar sem um prompt de confirmação, e o ramo de erro devolve isError: true com uma mensagem legível, para que o agente tente de novo em vez de travar.
Autenticação, segredos e salvaguardas
O servidor guarda as credenciais. O modelo nunca guarda.
Mantenha tokens fora dos prompts
Leia o token da API de uma variável de ambiente ou de um gerenciador de segredos quando o processo iniciar. Nunca aceite o token como argumento de ferramenta, nunca o repita em uma mensagem de erro e nunca registre headers de requisição em log. Crie o token mais restrito que a API permitir: um token somente leitura para um servidor somente leitura. Para servidores remotos, o fluxo de autorização do MCP é construído sobre OAuth 2.1, então cada usuário entra com a própria conta e cada chamada carrega as próprias permissões, em vez de um superusuário compartilhado.
Anote as ferramentas arriscadas
As anotações são dicas que ajudam os clientes a decidir quando pedir confirmação ao usuário:
Anotação
Defina quando
readOnlyHint: true
A ferramenta só lê, como um GET ou uma busca
destructiveHint: true
A ferramenta apaga ou sobrescreve dados
idempotentHint: true
Repetir a chamada com a mesma entrada não muda mais nada
openWorldHint: true
A ferramenta acessa sistemas fora do seu, como a web aberta
Trate-as como dicas, não como imposição, porque um cliente não deve confiar em anotações de um servidor que não conhece. A proteção real está do seu lado: publique a primeira versão somente leitura, adicione ferramentas de escrita uma por vez e dê às destrutivas uma entrada dry_run ou confirm para que o agente precise ser explícito.
Tarefas lentas, polling e mídia
Geração de imagens, renderização de vídeos e exportação de relatórios seguem o mesmo padrão: a API responde na hora com um id de tarefa, e o resultado chega em segundos ou minutos. Uma ferramenta que trava por três minutos vai estourar o tempo limite na maioria dos clientes. Um trilho de comandas resolve o mesmo problema em um restaurante: anota o pedido, entrega a comanda e chama pelo número quando o prato estiver pronto.
Criar, consultar, buscar
Divida a tarefa em três ferramentas: uma inicia, uma consulta e uma cancela. A ferramenta de início devolve um id e uma indicação de quando voltar para consultar. A ferramenta de consulta devolve um pequeno objeto de status, queued, running, succeeded ou failed, mais uma URL assim que houver algo para buscar. Devolva links, não bytes de arquivo: uma imagem de 5 MB colada no contexto não ajuda ninguém.
server.registerTool(
"get_render",
{
description:
"Check a render started with start_render. Call again after next_poll_in_seconds until status is succeeded or failed.",
inputSchema: { render_id: z.string() },
annotations: { readOnlyHint: true },
},
async ({ render_id }) => {
const job = await api(`/renders/${render_id}`); // api() is your fetch helper
const done = job.status === "succeeded" || job.status === "failed";
const body = {
status: job.status,
url: job.output?.[0] ?? null,
next_poll_in_seconds: done ? null : 5,
};
return { content: [{ type: "text", text: JSON.stringify(body) }] };
}
);
Um exemplo real de imagem e vídeo
O conector próprio da PicassoIA segue esse desenho. Suas ferramentas generate_image, edit_image, generate_video_picassoia e generate_video_seedance devolvem um predict_id assim que uma GPU aceita a tarefa, junto com um tempo estimado. Depois, o agente chama get_generation com o next_poll_in_seconds devolvido e repete até que o status seja succeeded ou failed. Uma ferramenta cancel_generation interrompe uma tarefa em andamento, com uma ressalva honesta nas instruções: um vídeo que a GPU já está renderizando não pode mais ser cancelado.
Por baixo disso existe uma API REST no estilo Replicate em https://api.picassoia.com/v1, com autenticação por bearer token. POST /v1/models/{owner}/{name}/predictions cria uma tarefa, GET /v1/predictions/{id} lê a tarefa e POST /v1/predictions/{id}/cancel a interrompe. Isso a torna um alvo de conversão clássico, e os quatro modelos por trás do conector correspondem às suas quatro ferramentas de geração:
Os limites também pertencem às descrições das ferramentas. A API permite 5 predições simultâneas por conta, compartilhadas entre tokens e conexões MCP, com prompts de até 4.000 caracteres, então uma boa descrição diz ao agente para esperar uma tarefa em andamento antes de iniciar uma sexta. Confira os termos atuais do plano no site da PicassoIA antes de construir um produto sobre a API.
Teste e depois publique
Um agente é um testador implacável: ele usa suas ferramentas de formas que você não planejou. Teste com ferramentas adequadas antes de entregá-lo.
Rode o MCP Inspector
O MCP Inspector é a interface oficial de depuração. Aponte-o para o seu servidor, por exemplo npx @modelcontextprotocol/inspector node dist/server.js, e ele lista todas as ferramentas, permite chamar cada uma com JSON bruto e mostra o resultado exato que um cliente receberia. Depois conecte um cliente real e rode dez prompts realistas. Para cada um, verifique três coisas: o agente escolheu a ferramenta certa, preencheu os argumentos corretamente e a resposta deu a ele o necessário para responder?
Escolha stdio ou HTTP
stdio
HTTP em streaming
Executa como
Processo local iniciado pelo cliente
Serviço remoto atrás de uma URL
Autenticação
Variáveis de ambiente na máquina do usuário
OAuth ou bearer tokens
Ideal para
Ferramentas pessoais e desenvolvimento
Equipes e APIs compartilhadas
Cuidado com
Nunca imprima logs no stdout
TLS, limites de taxa, escala horizontal
O HTTP em streaming substituiu o antigo transporte HTTP mais SSE na revisão 2025-03-26 da especificação, e o protocolo continua evoluindo, então fixe a versão do seu SDK e leia o changelog antes de atualizar.
Cinco erros comuns
Expor todos os endpoints. As listas de ferramentas custam tokens em cada turno.
Registrar logs no stdout em um servidor stdio. O stdout carrega o próprio protocolo. Envie os logs para o stderr.
Devolver o payload upstream inteiro. Corte para os campos que o agente precisa e pagine o resto.
Lançar exceções. Devolva um resultado isError com uma mensagem que diga o que tentar em seguida.
Descrições sobrepostas. Se duas ferramentas soam parecidas, o agente escolhe no cara ou coroa. Diga quando preferir cada uma.
Escrever vinte descrições de ferramentas à mão é cansativo, e um LLM faz bem esse trabalho quando você dá regras. Na PicassoIA, o Claude Sonnet 5 é uma boa escolha: a página do modelo lista tarefas de programação em várias etapas e uso de ferramentas entre seus pontos fortes, ele aceita um prompt de sistema e permite escolher quanto raciocínio ele faz.
Abra o modelo. Acesse a página do Claude Sonnet 5 na PicassoIA.
Defina o prompt de sistema uma vez. Por exemplo: You write MCP tool definitions. For each OpenAPI operation return a verb_noun name, a description that says what the tool does, when to use it and what it returns, and a flat JSON Schema with example values. Never copy internal parameter names.
Cole uma operação por vez no campo de prompt, ou um pequeno grupo de operações relacionadas. Uma especificação inteira de 5 MB produz uma saída confusa.
Escolha o nível de esforço.low é o mais rápido e desliga o raciocínio, medium serve para um lote de operações simples, e high compensa para corpos de requisição aninhados.
Deixe o máximo de tokens em 8192, o padrão, para lotes de cinco a oito operações.
Anexe uma captura de tela se tudo o que você tem são documentos renderizados. O campo de imagem aceita uma.
Revise antes de publicar. Passe cada rascunho pelo Inspector e corrija os nomes que se sobrepõem.
💡 Precisa de uma saída que sempre seja um JSON válido? O GPT 5 Structured foi feito para devolver JSON limpo, o que combina com rascunhos de schema que você pretende carregar direto no código.
Monte seu próprio kit de ferramentas para agentes
Escolha uma API, cinco ferramentas e uma tarde livre. Publique primeiro a versão somente leitura, teste com dez prompts reais e só depois adicione as ferramentas que escrevem ou apagam.
Agentes precisam de coisas para mostrar, não apenas de dados para ler. Experimente você mesmo na Picasso IA: escreva um prompt no PicassoIA Image, escolha 16:9 e depois refine o resultado com o PicassoIA Image Editor Pro, que aceita até três imagens de referência. Quando a imagem parada estiver boa, anime-a com o Picasso IA Video ou prolongue a cena para dez segundos com o Seedance 2.5 Lite. Teste suas próprias cenas e, quando estiver pronto, crie a ferramenta MCP que permite ao seu agente fazer o mesmo.