Até hoje você foi inquilino: instala MCPs que outros escreveram e sua IA os usa. Ótimo. Mas chega um momento em que isso fica curto — você tem uma API interna, um banco de dados, um script que só você entende, e quer que o Claude o toque diretamente, sem copiar e colar saídas no chat. É aí que você deixa de consumir e começa a publicar. Um servidor MCP é a tomada padrão: você descreve suas ferramentas uma vez, e qualquer IA que fale o protocolo as invoca como se fossem dela. O FastMCP é o framework de TypeScript que envolve o SDK oficial do MCP (o que a Anthropic abriu) e tira o boilerplate do seu caminho — o mesmo salto que o Express te deu sobre o módulo http do Node. Neste guia passamos de um tool 'add' sobre stdio em quinze minutos, a tools com esquemas Zod que se validam sozinhos, resources que expõem dados, prompts reutilizáveis, e por fim produção de verdade: autenticação, HTTP streaming, sessões e edge. No final você terá um MCP próprio que o Claude Code invoca pra valer — não uma demo, uma tubulação sua conectada ao seu mundo.
Faz semanas que você está com a IA conectada a ferramentas. Você pede que ela abra um navegador e ela abre. Pede que leia um repo e ela lê. Tudo isso são MCPs que outros escreveram — tomadas padrão que alguém publicou e você instalou. Funciona porque falam uma língua comum: o Model Context Protocol, o padrão aberto para que qualquer IA descubra e invoque ferramentas externas sem se acoplar a nenhuma.
O momento chega quando o que você precisa não existe como MCP. Você tem um endpoint interno que devolve o status dos seus pedidos. Uma planilha que só você sabe ler. Um script de 40 linhas que calcula algo específico do seu domínio. Hoje, cada vez que você quer que a IA use isso, faz a dança do entregador: você executa, copia a saída, cola no chat, espera. Funciona uma vez. Na décima, você se pergunta por que a IA não faz isso sozinha.
Este recurso fecha um arco. No agent-browser você aprendeu a dar à sua IA uma capacidade externa para consumir o mundo — ver páginas, clicar, extrair. Aqui você gira a câmera: aprende a publicar suas próprias capacidades para que outras IAs as consumam. De usuário a autor. É o mesmo protocolo, visto do outro lado do fio.
Quando você abre o SDK oficial do MCP pela primeira vez, a sensação é a de abrir o capô de um carro de corrida: tudo está ali, tudo é correto, e nada é óbvio. Você tem que registrar handlers na mão, mapear os requests do protocolo, serializar respostas no formato exato que o cliente espera, gerenciar o ciclo de conexão, fazer o parse dos parâmetros de entrada e validá-los por conta própria. Para expor um único tool que soma dois números, você escreve dezenas de linhas de encanamento antes de chegar à linha que faz a soma.
De onde vem essa dor? Do fato de o SDK oficial ser de baixo nível de propósito. É a base sobre a qual se constrói, não a ergonomia final — assim como o módulo http do Node é correto mas ninguém escreve um servidor web com ele diretamente, usa Express. O SDK te dá acesso total ao protocolo; o preço é que você carrega todo o boilerplate. É ótimo para quem constrói frameworks. É hostil para quem só quer plugar sua API.
O FastMCP existe para apagar exatamente esse boilerplate. É um framework de TypeScript que envolve o SDK oficial do MCP — não o substitui, fica em cima dele — e te dá uma API declarativa: você descreve o tool, seu esquema e sua função, e o FastMCP cuida do resto (registro, serialização, ciclo de conexão, validação). O tool de somar passa daquela confusão de encanamento para pouco mais de uma dúzia de linhas. E são as que importam: as que de verdade fazem a soma.
Framework de TypeScript para construir servidores MCP sem boilerplate. Fica em cima do SDK oficial do MCP (@modelcontextprotocol/sdk, o que a Anthropic abriu) e adiciona tools com validação por esquema (Zod e outros Standard Schema), resources, prompts, autenticação, HTTP streaming, sessões e um CLI de desenvolvimento. A forma mais rápida de passar de ideia a servidor MCP que o Claude invoca de verdade.
Publicar um servidor MCP não é algo que você faz uma vez e esquece. É um reflexo que se ativa em momentos concretos. Aprenda a reconhecê-los e você saberá sempre quando vale a pena o tempo de construí-lo.
O FastMCP se instala como qualquer pacote do npm. Roda sobre Node moderno com TypeScript. Um projeto novo mínimo cabe em uma pasta com três arquivos.
# En una carpeta nueva para tu servidor mkdir mi-mcp && cd mi-mcp npm init -y # FastMCP + Zod (para los esquemas de entrada) + tsx (para correr TS sin compilar) npm install fastmcp zod npm install -D tsx typescript
a é um número, email é uma string com formato de e-mail, edad é um inteiro opcional. O FastMCP pega esse esquema e faz duas coisas de graça: (1) diz ao cliente quais parâmetros seu tool espera, para que a IA os preencha bem; e (2) valida a entrada antes que ela chegue ao seu código. Se a IA mandar lixo, quem rejeita é o esquema, não sua função. É um guarda na porta que você não precisa escrever. (O FastMCP também aceita outros validadores do mesmo padrão — ArkType, Valibot — mas o Zod é o caminho mais batido.)Começamos pelo 'olá mundo' do MCP: um servidor com um único tool que soma dois números. É deliberadamente bobo — a graça não é a soma, é ver o fio completo: definir o servidor, registrar um tool com seu esquema, iniciá-lo, e o Claude invocá-lo. Assim que você tem esse esqueleto, todo o resto são variações.
// server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";
const server = new FastMCP({
name: "Mi Servidor",
version: "1.0.0",
});
server.addTool({
name: "add",
description: "Suma dos números",
parameters: z.object({
a: z.number(),
b: z.number(),
}),
execute: async (args) => {
return String(args.a + args.b);
},
});
server.start({
transportType: "stdio",
});Leia de cima a baixo, porque este padrão se repete em tudo o que você construir. new FastMCP cria o servidor com nome e versão — é isso que o Claude verá na lista de conexões. addTool registra uma ferramenta: um nome (com o qual a IA a invoca), uma descrição (que a IA lê para decidir quando usá-la — escreva-a bem, é marketing dirigido à máquina), os parameters como esquema Zod, e execute, a função que roda de verdade. Você devolve uma string e o FastMCP a envolve no formato do protocolo por você.
transportType: "stdio" significa que o servidor fala pela entrada e saída padrão — o mesmo canal pelo qual um programa de terminal recebe e emite texto. É o transporte mais simples: o cliente (Claude Code) lança seu servidor como um subprocesso e conversa com ele por esse cano. Zero rede, zero portas, zero configuração. Perfeito para ferramentas locais suas. Quando você quiser expô-lo pela internet, trocará este transporte por HTTP — mas para começar, stdio é tudo o que você precisa.Antes de plugá-lo ao Claude, teste-o isolado. O FastMCP traz um CLI que inicia seu servidor e te deixa falar com ele, mais o Inspector oficial do MCP para vê-lo em uma interface visual. É o seu loop de desenvolvimento: você muda o código, testa aqui, e só quando funciona conecta ao cliente real.
# Arranca tu servidor en modo desarrollo (interactúas con los tools) npx fastmcp dev server.ts # Ábrelo en el MCP Inspector (interfaz visual para inspeccionar tools/resources/prompts) npx fastmcp inspect server.ts
npx fastmcp dev como sua bancada de trabalho: ali você vê o erro cru, a saída exata, o esquema tal como seu servidor o publica. Só quando o tool faz o que você quer, você dá o passo de conectá-lo ao cliente. Assim como você não faz deploy para produção para testar um if — testa local primeiro.Aqui é onde deixa de ser um exercício e vira real. Um cliente MCP (Claude Desktop, Claude Code) lança seu servidor como subprocesso e fala com ele por stdio. Ele só precisa saber como iniciá-lo: qual comando e quais argumentos. Isso vive em um arquivo de configuração com a lista de servidores MCP.
{
"mcpServers": {
"mi-servidor": {
"command": "npx",
"args": ["tsx", "/ruta/absoluta/a/mi-mcp/server.ts"]
}
}
}command é o executável que lança seu servidor e args seus argumentos — aqui usamos npx tsx para rodar o TypeScript diretamente sem compilar. Use caminho absoluto: o cliente não sabe de qual pasta você o lança. Uma vez salvo e reiniciado o cliente, seu servidor aparece na lista, e quando você pedir ao Claude "soma 128 e 45", verá como ele invoca o seu tool add em vez de calcular de cabeça. Esse momento — o primeiro tool seu que a IA chama sozinha — é o que engancha.
./server.ts) em args. O cliente lança o subprocesso a partir do diretório de trabalho dele, não do seu, então ./server.ts aponta para o nada e o servidor não inicia — normalmente em silêncio. Se o seu MCP não aparece ou falha ao conectar, revise isso primeiro: caminho absoluto, sempre.O tool add usava Zod para o mínimo. Mas o verdadeiro poder aparece com tools reais, onde a entrada tem forma e regras. Imagine um tool que cria um usuário: o e-mail deve ter formato de e-mail, a idade deve ser um inteiro positivo, o papel só pode ser um de uma lista. Com Zod, você descreve tudo isso e o FastMCP rejeita a entrada inválida antes que ela toque no seu código. Você nunca escreve um if (!email.includes('@')). O esquema é o guarda.
server.addTool({
name: "crear_usuario",
description: "Crea un usuario en el sistema con validación completa",
parameters: z.object({
nombre: z.string().min(2),
email: z.string().email(),
edad: z.number().int().positive().optional(),
rol: z.enum(["admin", "editor", "lector"]),
}),
execute: async (args) => {
// Si llegaste aquí, args YA está validado: email es email, rol es válido.
const usuario = await miBaseDeDatos.insertar(args);
return `Usuario ${usuario.id} creado con rol ${args.rol}`;
},
});execute, args vem tipado em TypeScript, com autocompletar. Um único bloco de código que valida, documenta e tipa. Isto é o que o SDK oficial te obrigava a escrever três vezes na mão.Um tool é um verbo — a IA o executa para que algo aconteça. Mas às vezes você não quer uma ação, quer dar contexto: um arquivo de logs, um documento de configuração, o conteúdo de um README. Para isso existem os resources. São dados que seu servidor expõe e que a IA pode ler quando precisa, identificados por uma URI. Pense nos tools como os botões de um controle, e nos resources como as telas que mostram informação.
server.addResource({
uri: "file:///logs/app.log",
name: "Logs de la Aplicación",
mimeType: "text/plain",
async load() {
const contenido = await fs.readFile("/var/log/app.log", "utf-8");
return { text: contenido };
},
});A uri é o identificador único do resource — o cliente a usa para pedi-lo. mimeType diz à IA de que tipo é o conteúdo (texto simples, JSON, markdown), para que ela o interprete bem. E load é a função que traz o conteúdo quando alguém o pede — preguiçosa por design: você não lê o arquivo até que seja necessário. Para dados binários você devolve { blob } em base64 em vez de { text }. Um resource é a forma limpa de dizer "IA, aqui estão os dados frescos quando você precisar", sem gastá-los no prompt até o momento exato.
O terceiro ingrediente do protocolo são os prompts. Se você tem um template que usa o tempo todo — 'gera uma mensagem de commit a partir deste diff', 'resume esta reunião com este formato' — um prompt do MCP o empacota com um nome e uns argumentos, e qualquer cliente pode invocá-lo. Você deixa de copiar e colar a mesma instrução longa: você a oferece como mais uma capacidade do seu servidor.
server.addPrompt({
name: "git-commit",
description: "Genera un mensaje de commit a partir de un diff",
arguments: [
{
name: "changes",
description: "El diff de git o una descripción de los cambios",
required: true,
},
],
load: async (args) => {
return `Genera un mensaje de commit conciso para estos cambios:\n${args.changes}`;
},
});Tudo o que veio antes rodava por stdio: local, seu, um subprocesso na sua máquina. Perfeito para começar. Mas quando você quer que outros usem o seu MCP — seu time, um cliente, você mesmo de vários lugares — você precisa expô-lo pela internet. Aí entra o transporte HTTP streaming: em vez de um cano local, seu servidor escuta em uma porta e responde por HTTP com streaming de eventos. O código dos seus tools não muda uma linha; você só muda como ele inicia.
server.start({
transportType: "httpStream",
httpStream: {
port: 8080,
endpoint: "/mcp", // opcional, por defecto es /mcp
},
});Esse é o interruptor completo. Mesmos tools, mesmos resources, mesmos prompts — agora servidos por HTTP na porta 8080, endpoint /mcp. Um cliente remoto aponta para https://tu-dominio/mcp e pluga. Aqui é onde seu MCP deixa de ser uma ferramenta pessoal e vira um serviço. E onde surge a pergunta que separa um brinquedo de um produto: quem pode chamá-lo?
Um MCP por HTTP sem autenticação é uma porta aberta: qualquer um que saiba a URL invoca seus tools, toca seu banco de dados, gasta seus recursos. O FastMCP resolve isso com uma opção authenticate: uma função que roda em cada conexão, inspeciona a requisição (headers, API key, token), e decide se passa ou não. Se passa, devolve um objeto de sessão que estará disponível dentro de cada tool.
const server = new FastMCP({
name: "Mi Servidor",
version: "1.0.0",
authenticate: (request) => {
const apiKey = request.headers["x-api-key"];
if (apiKey !== process.env.MCP_API_KEY) {
throw new Response(null, { status: 401, statusText: "Unauthorized" });
}
return { id: 1, role: "user" }; // esto se vuelve la sesión
},
});
server.addTool({
name: "sayHello",
execute: async (args, { session }) => {
return `Hola, usuario ${session.id}!`; // session viene de authenticate
},
});authenticate valida. Não são rivais: um MCP de produção é tubulação com cadeado. Sem cadeado, sua tubulação é uma torneira pública que qualquer um abre.process.env.MCP_API_KEY. A chave jamais se escreve literal no código nem se sobe pro git — é a mesma regra de ouro do recurso de segredos: fora do repo, em uma variável de ambiente ou um gerenciador de segredos. Um MCP com a key hardcoded é um MCP com a porta pintada de 'fechado' mas sem fechadura de verdade. Qualquer um que veja o código, entra.Os tools reais não são instantâneos. Um tool que processa um arquivo grande, chama uma API lenta ou gera conteúdo demora segundos. O FastMCP te dá, dentro de execute, um contexto com ferramentas para que esse tool respire: reportar progresso, emitir conteúdo em streaming, logar, e acessar a sessão do usuário autenticado.
server.addTool({
name: "procesar_lote",
description: "Procesa un lote reportando progreso en vivo",
parameters: z.object({ total: z.number() }),
annotations: { streamingHint: true },
execute: async (args, { streamContent, reportProgress, log, session }) => {
log.info(`Iniciando lote para ${session.id}`);
await streamContent({ type: "text", text: "Empezando..." });
await reportProgress({ progress: 50, total: 100 });
// ... trabajo real ...
return "Completado";
},
});reportProgress({ progress, total }) diz ao cliente 'estou nos 50%', e a IA (e o humano) veem uma barra em vez de um silêncio angustiante. streamContent emite saída em pedaços conforme se gera, em vez de esperar o final — a diferença entre ver o texto aparecer e olhar um spinner. log deixa rastro estruturado para depurar. E session é o usuário que o authenticate validou, então cada tool sabe quem está chamando. Com estes, seus tools deixam de ser caixas-pretas que demoram e viram processos observáveis.
Aqui está o único prompt que você precisa guardar. Em vez de escrever o servidor na mão, você o descreve para sua IA — que já tem todo o contexto do FastMCP deste guia diante dela — e ela gera o esqueleto completo, testado, pronto para conectar. Preencha os colchetes com seu caso real e deixe ela construir. Um único prompt, não cinco: este arranca o projeto inteiro.
Aja como engenheiro sênior de MCP. Vamos construir um servidor MCP em TypeScript com FastMCP (o framework que envolve o SDK oficial do MCP, o que a Anthropic abriu; se instala com `npm install fastmcp zod`).
MEU SERVIDOR:
- Nome: [nome do seu servidor, ex. "CRM Interno"]
- O que expõe: [descreva em 2 linhas quais ferramentas/dados você quer que a IA toque]
OS TOOLS QUE PRECISO (ações que a IA executará):
1. [nome_tool] — [o que faz] — entradas: [campos e seus tipos/regras]
2. [nome_tool] — [o que faz] — entradas: [campos e seus tipos/regras]
RESOURCES (dados que a IA lerá, se aplicável):
- [nome] — [quais dados expõe, ex. logs, config]
MODO: [comece em "stdio local" para desenvolvimento | depois migro para "httpStream com autenticação por API key" para produção]
CONSTRUA:
1. server.ts completo: `new FastMCP` com nome e versão, cada tool com `addTool` (name, description clara orientada a que a IA saiba quando usá-lo, parameters como esquema Zod que VALIDE de verdade — .email(), .int().positive(), .enum() onde couber, e .optional() no opcional, execute tipado).
2. Os resources com `addResource` (uri, name, mimeType, load preguiçoso que devolva {text} ou {blob}) se eu pedi.
3. O `server.start` com o transporte que escolhi (stdio ou httpStream com port/endpoint).
4. Se pedi produção: a opção `authenticate` que lê a API key de `process.env` (NUNCA hardcoded), lança `new Response(null, {status: 401})` se não bater e devolve a sessão, mais um tool que use `session`.
5. O bloco JSON de `mcpServers` para conectá-lo ao Claude Code, com `npx tsx` e caminho ABSOLUTO.
6. Os comandos exatos: instalar, testar com `npx fastmcp dev server.ts`, e inspecionar com `npx fastmcp inspect server.ts`.
RESTRIÇÕES: zero segredos no código; descrições de tools escritas PARA que a IA decida bem quando invocá-las; valide toda entrada com Zod, não com ifs na mão. Explique-me cada tool em uma linha antes do código.npx fastmcp dev. Quando isso funcionar e o Claude o invocar de verdade, volte ao mesmo prompt trocando o MODO para produção com autenticação. Assim você constrói em camadas verificáveis em vez de cuspir um servidor gigante sem testar. E aplique o hábito de sempre: primeiro um commit do esqueleto que funciona, depois o resto.Publicar um MCP tem dois caminhos conforme onde você está parado, e convém saber quando tomar cada um.
server.ts completo com Zod, transporte e config.mcpServers com o caminho correto e os comandos de fastmcp dev para testar antes de plugar.npx fastmcp inspect server.ts abre o Inspector visual — ali você vê seus tools, resources e prompts como um cliente os vê.Recue e olhe o caminho. Você começou consumindo MCPs que outros escreveram — sua IA usava ferramentas alheias. Aprendeu com o agent-browser a dar a ela uma capacidade para ver e tocar o mundo. E aqui, com o FastMCP, você girou a câmera: agora você publica suas próprias capacidades para que qualquer IA as consuma. Um tool add em quinze minutos virou tools com Zod, resources, prompts, autenticação e HTTP. Você fechou o arco usuário→autor. Já não é inquilino do ecossistema MCP: é dono de uma tomada.
Join 4,200+ builders. No credit card. Build your first app with AI in minutes.