Alternar tema

Introdução ao desenvolvimento de MCP Server: crie seu primeiro serviço MCP do zero

Easton editorial illustration: trace beacon network

Introdução: Ao programar no Cursor, você já quis que a IA consultasse diretamente a versão mais recente de uma dependência do projeto? Ou, ao analisar dados no Claude, desejou que ele pudesse ler informações do seu banco de dados? Sem um padrão comum, seria preciso criar uma integração para cada ferramenta de IA. Com um MCP Server, você implementa uma vez e qualquer cliente compatível com MCP pode usar o serviço. Neste artigo, você vai criar do zero um MCP Server completo em TypeScript.

30 minutos
Tempo para começar
Do zero à execução
3 tipos
Recursos principais
Tools/Resources/Prompts
Mais de 1.000
Servidores MCP
Comunidade open source no GitHub
Source: Dados oficiais do MCP (2025)

O que é MCP? Entenda o conceito principal em 3 minutos

A história de uma porta USB

Quem usava eletrônicos há alguns anos provavelmente se lembra de uma época pouco prática: o mouse tinha um conector redondo, o teclado outro formato e a impressora usava uma porta paralela. Cada dispositivo exigia uma entrada específica. Então surgiu o USB, padronizando tudo em uma única interface.

O MCP (Model Context Protocol) está se tornando o “padrão USB” do universo das ferramentas de IA.

Sem MCP, para permitir que uma IA acesse uma fonte de dados, você precisa criar uma camada de integração para cada ferramenta: um plugin para Claude, uma extensão para Cursor, outra para Windsurf e assim por diante. A complexidade é N x M (N fontes de dados x M ferramentas de IA).

Com MCP, basta criar um MCP Server para que todos os clientes compatíveis possam usá-lo diretamente. A complexidade cai para N+M.

A arquitetura de três camadas é simples:

+-------------+     +-------------+     +-------------+
|    Host     | ->  |   Client    | ->  |   Server    |
|  (Claude)   |     | (cliente MCP)|    | (seu serviço)|
+-------------+     +-------------+     +-------------+
  • Host: o próprio aplicativo de IA, como Claude Desktop ou Cursor
  • Client: o cliente MCP responsável pela comunicação com o Host
  • Server: o serviço que você desenvolve para oferecer funcionalidades específicas

Os três tipos de recurso oferecidos por um MCP Server

Um MCP Server pode disponibilizar três tipos diferentes de funcionalidade:

RecursoFinalidadeExemplo
Tools (ferramentas)Executar açõesConsultar o tempo, enviar mensagens, ler um banco de dados
Resources (recursos)Fornecer dadosConteúdo de arquivos, respostas de API, configurações
PromptsOferecer modelos predefinidosModelo de revisão de código, modelo de relatório diário

Pense em Tools como “funções”: a IA pode chamá-las para executar uma ação. Resources são “fontes de dados” cujo conteúdo pode ser lido pela IA. Prompts são “modelos” que ajudam a IA a entender uma tarefa mais rapidamente.

Diferença em relação a outros artigos: se você já leu outros tutoriais sobre MCP, talvez tenha visto implementações em Python com FastMCP. Este artigo usa o SDK oficial para TypeScript, mais adequado para desenvolvedores frontend e full stack. As duas opções oferecem recursos equivalentes; escolha a linguagem com a qual você tem mais familiaridade.

"https://modelcontextprotocol.io"


Preparação do ambiente de desenvolvimento

Pré-requisitos

Este artigo pressupõe que você:

  • tenha instalado Node.js 18+ ou Bun 1.0+
  • já tenha usado TypeScript e saiba o que são interface e async/await
  • tenha o Claude Desktop ou outro cliente compatível com MCP, como Cursor ou Windsurf

Se você nunca usou Bun, vale a pena experimentar. Ele é muito mais rápido que npm e oferece suporte integrado a TypeScript, sem exigir configuração adicional de ts-node.

Inicialização do projeto

# Criar o diretório do projeto
mkdir mcp-weather-server && cd mcp-weather-server

# Inicializar (com Bun ou npm)
bun init -y
# ou npm init -y

# Instalar o MCP TypeScript SDK
bun add @modelcontextprotocol/sdk zod
# ou npm install @modelcontextprotocol/sdk zod

O projeto usa duas dependências:

  • @modelcontextprotocol/sdk: SDK oficial do MCP para TypeScript
  • zod: validação de tipos em tempo de execução para TypeScript, usada para definir o schema dos parâmetros das ferramentas

Pontos importantes da configuração do TypeScript

Se você usar bun init, o arquivo tsconfig.json já estará configurado. Em uma configuração manual, preste atenção às opções abaixo:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "strict": true
  }
}

moduleResolution: "bundler" é importante para módulos ESM. Sem essa opção, você pode encontrar erros como “xxx is not defined”.


Na prática: criando um MCP Server de consulta do tempo

Neste tutorial, você vai desenvolver um MCP Server completo capaz de:

  1. Receber solicitações de uma IA
  2. Consultar a API do OpenWeatherMap para obter o tempo em tempo real
  3. Retornar o resultado formatado

Estrutura do projeto

mcp-weather-server/
+-- src/
|   +-- index.ts      # Arquivo de entrada
|   +-- weather.ts    # Implementação da ferramenta de clima
|   +-- resources.ts  # Definição dos recursos
+-- package.json
+-- tsconfig.json

Na prática, todo o código pode ficar em index.ts, como faremos neste artigo. Mesmo assim, separar a implementação em módulos facilita a manutenção.

Etapa 1: crie a estrutura básica do MCP Server

Comece pelo mais simples: um MCP Server que consegue iniciar.

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Criar a instância do servidor
const server = new McpServer({
  name: "weather-service",
  version: "1.0.0",
});

// Registrar uma ferramenta (Tools)
server.tool(
  "get_weather",
  "获取指定城市的当前天气信息",
  {
    city: z.string().describe("城市名称,如:北京、上海"),
  },
  async ({ city }) => {
    // A implementação será detalhada na próxima seção
    return { content: [{ type: "text", text: `查询 ${city} 的天气...` }] };
  }
);

// Iniciar o servidor
const transport = new StdioServerTransport();
await server.connect(transport);

McpServer é a classe principal fornecida pelo SDK; você precisa informar name e version. O método tool() registra uma ferramenta: o primeiro argumento é o nome, o segundo é a descrição, o terceiro é o schema dos parâmetros e o último é a função de execução.

Etapa 2: implemente a ferramenta de consulta do tempo (código principal)

Agora vamos fazer a ferramenta funcionar de verdade usando a API gratuita do OpenWeatherMap:

// src/weather.ts
import { z } from "zod";

// Definir o tipo da resposta da API do OpenWeatherMap
interface WeatherResponse {
  name: string;
  main: { temp: number; feels_like: number; humidity: number };
  weather: [{ description: string }];
  wind: { speed: number };
}

// Implementação da ferramenta de consulta do tempo
server.tool(
  "get_weather",
  "获取指定城市的当前天气信息",
  {
    city: z.string().describe("城市名称,如:北京、上海"),
  },
  async ({ city }) => {
    const API_KEY = process.env.OPENWEATHER_API_KEY;
    const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`;

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`API 请求失败:${response.status}`);
      }

      const data: WeatherResponse = await response.json();

      // Retornar o resultado formatado
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({
              city: data.name,
              temperature: `${data.main.temp}°C`,
              feels_like: `${data.main.feels_like}°C`,
              description: data.weather[0].description,
              humidity: `${data.main.humidity}%`,
              wind_speed: `${data.wind.speed} m/s`,
            }, null, 2),
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `查询失败:${error instanceof Error ? error.message : '未知错误'}`,
          },
        ],
        isError: true,
      };
    }
  }
);

Observe três pontos:

  1. A API Key é lida de uma variável de ambiente: nunca deixe uma chave fixa no código
  2. Tratamento de erros: retornar isError: true informa ao cliente que a chamada falhou
  3. Definição de tipos: a interface WeatherResponse permite que o TypeScript verifique a estrutura dos dados

Crie uma conta gratuita no OpenWeatherMap. Depois de obter a API Key, defina a variável de ambiente:

export OPENWEATHER_API_KEY=your_api_key_here

Etapa 3: adicione Resources (opcional, mas recomendado)

Resources permite que seu Server forneça dados “somente leitura”. Por exemplo, você pode disponibilizar um recurso para a IA consultar o status do servidor:

// src/resources.ts

// Fornecer informações sobre o status do servidor
server.resource(
  "server-status",
  "status://server",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        text: JSON.stringify({
          name: "Weather Service",
          version: "1.0.0",
          status: "running",
          timestamp: new Date().toISOString(),
        }, null, 2),
      },
    ],
  })
);

// Fornecer a documentação da API
server.resource(
  "api-docs",
  "docs://api",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        text: `
# Weather MCP Server API

## Tools
- get_weather(city: string): 获取指定城市天气

## Resources
- status://server - 服务器状态
- docs://api - API 文档
        `.trim(),
      },
    ],
  })
);

Os dois primeiros argumentos de resource() são o nome e a URI do recurso; o terceiro é a função de leitura. A URI pode usar qualquer scheme, como status:// ou docs://, desde que permita distinguir os recursos.

Etapa 4: adicione Prompts (recurso avançado)

Prompts são modelos predefinidos de conversa. Você pode criar, por exemplo, um modelo de “relatório do tempo” que preenche automaticamente o nome da cidade:

// Modelo predefinido de relatório do tempo
server.prompt(
  "weather_report",
  "生成一份格式化的天气报告",
  {
    city: z.string().describe("城市名称"),
    include_tips: z.boolean().optional().describe("是否包含穿衣建议"),
  },
  ({ city, include_tips }) => ({
    messages: [
      {
        role: "user",
        content: {
          type: "text",
          text: `请为${city}生成一份天气报告。${include_tips ? "同时提供穿衣建议。" : ""}`,
        },
      },
    ],
  })
);

O retorno de prompt() é um array de mensagens, cada uma com role e content. Assim, ao usar o prompt, a IA recebe diretamente o contexto predefinido.

Etapa 5: finalize o arquivo de entrada

Reúna todo o código acima em src/index.ts e adicione o tratamento de erros:

// src/index.ts (versão completa)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "weather-service",
  version: "1.0.0",
});

// Registrar todas as ferramentas, recursos e prompts
// ... (código mostrado acima)

// Tratamento de erros
process.stdin.on("error", (err) => {
  console.error("标准输入错误:", err);
  process.exit(1);
});

process.stdout.on("error", (err) => {
  console.error("标准输出错误:", err);
  process.exit(1);
});

// Encerramento controlado
process.on("SIGINT", async () => {
  await server.close();
  process.exit(0);
});

// Iniciar o servidor
const transport = new StdioServerTransport();
await server.connect(transport);

console.error("MCP Weather Server 已启动,等待连接...");

StdioServerTransport usa a entrada e a saída padrão para comunicação; por isso, é importante tratar erros de stdin/stdout. O tratamento de SIGINT permite encerrar o serviço de forma controlada com Ctrl+C.

Execute bun run src/index.ts. Se a mensagem de inicialização aparecer, está tudo funcionando.


Configuração do cliente: conecte o Claude ao seu Server

Com o Server pronto, agora vamos permitir que Claude Desktop ou Cursor o chamem.

Configuração do Claude Desktop

Localize o arquivo de configuração:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Adicione a configuração do seu Server:

{
  "mcpServers": {
    "weather": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/mcp-weather-server/src/index.ts"],
      "env": {
        "OPENWEATHER_API_KEY": "你的 API Key"
      }
    }
  }
}

Atenção: o caminho em args deve ser absoluto. Um caminho relativo fará o Server falhar ao iniciar.

Configuração do Cursor e do Windsurf

A configuração no Cursor e no Windsurf é semelhante. Nas preferências da IDE, localize a configuração de MCP e adicione uma entrada para o servidor usando o mesmo formato acima.

O arquivo de configuração do Cursor costuma ficar em:

  • macOS: ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
  • ou, na IDE: Configurações -> AI -> MCP -> Adicionar servidor

Teste seu Server

  1. Reinicie o Claude Desktop ou o Cursor
  2. Digite na conversa: “Consulte o tempo em Pequim”
  3. O Claude deve chamar automaticamente seu MCP Server

Se você vir um resultado semelhante ao exemplo abaixo, deu certo:

{
  "city": "北京",
  "temperature": "18°C",
  "feels_like": "16°C",
  "description": "多云",
  "humidity": "65%",
  "wind_speed": "3.2 m/s"
}

Solução de problemas comuns

ProblemaPossível causaSolução
Server não conectadoCaminho incorretoVerifique o caminho absoluto em args
API Key inválidaVariável de ambiente não repassadaConfirme se a configuração de env está correta
Sem respostaErro de compilação do TypeScriptCompile primeiro com bun build ou tsc
Erro de permissãoPermissões do arquivo de configuraçãoVerifique se o arquivo pode ser lido

"https://github.com/modelcontextprotocol/typescript-sdk"


Sugestões para expansão e implantação

Adicione mais ferramentas

A consulta do tempo é apenas o começo. Você também pode criar:

  • Consulta do histórico meteorológico: chamar uma API de dados históricos para obter o tempo em uma data anterior
  • Comparação entre cidades: consultar várias cidades de uma só vez e retornar uma tabela comparativa
  • Alertas meteorológicos: verificar a existência de alertas de condições severas

O registro dessas ferramentas funciona exatamente como em get_weather; apenas a lógica de implementação muda.

Comparação das opções de implantação

Se você quiser compartilhar o Server com sua equipe, o transporte stdio local não será suficiente. Veja algumas opções:

Forma de implantaçãoCenário indicadoVantagensDesvantagens
stdio localUso pessoal e testes de desenvolvimentoSimples e seguroNão permite compartilhamento
HTTP/SSEEquipes e vários usuáriosAcesso remotoExige autenticação
ServerlessAmbiente de produçãoEscalabilidade automáticaLatência na inicialização a frio

Cuidados no ambiente de produção

Autenticação: em uma implantação HTTP, a autenticação é obrigatória. O MCP oferece suporte a OAuth 2.1, mas você também pode usar uma API Key simples:

// Verificar a API Key no cabeçalho da requisição
const apiKey = request.headers.get("Authorization");
if (apiKey !== `Bearer ${process.env.API_KEY}`) {
  return new Response("Unauthorized", { status: 401 });
}

Limitação de requisições: impeça que chamadas mal-intencionadas esgotem sua cota de API. Você pode usar express-rate-limit ou a limitação integrada do Cloudflare Workers.

Logs: use pino ou winston para registrar as chamadas das ferramentas e facilitar a investigação de problemas:

import pino from "pino";
const logger = pino();

server.tool("get_weather", /* ... */, async ({ city }) => {
  logger.info({ city }, "查询天气");
  // ...
});

Monitoramento: acompanhe a taxa de sucesso e o tempo de resposta das chamadas. Prometheus + Grafana é uma combinação comum.


Conclusão

Este artigo mostrou como criar um MCP Server do zero usando TypeScript. Você aprendeu a:

  • entender os conceitos principais e a arquitetura de três camadas do MCP
  • criar um servidor com o MCP TypeScript SDK
  • implementar uma ferramenta de consulta do tempo (Tools)
  • adicionar um recurso de status do servidor (Resources)
  • definir um modelo de relatório do tempo (Prompts)
  • configurar Claude Desktop e Cursor para chamar o Server

Agora você pode:

  1. Criar wrappers MCP para as APIs que usa com frequência, como GitHub, Slack e Notion
  2. Criar interfaces MCP para sistemas internos, como CRM e bancos de dados
  3. Explorar o que a comunidade MCP já desenvolveu

Recursos para continuar aprendendo:

Para entender melhor como o protocolo MCP funciona, leia também Entenda os fundamentos do protocolo MCP.

FAQ

Que conhecimentos são necessários para desenvolver um MCP Server?
Você precisa de conhecimentos básicos de JavaScript ou TypeScript. O artigo usa o MCP TypeScript SDK; familiaridade com async/await e definições de tipos já é suficiente para começar.
Qual é a diferença entre MCP Server e FastMCP?
FastMCP é um framework em Python, adequado para quem desenvolve nessa linguagem. Este artigo usa o SDK oficial para TypeScript, mais familiar para desenvolvedores frontend e full stack. Ambos oferecem recursos equivalentes; a escolha depende da sua stack.
Como testar se o MCP Server está funcionando?
Depois de configurar o Claude Desktop, digite uma solicitação em linguagem natural na conversa, como 'consulte o tempo em Pequim'. Se o Claude chamar a ferramenta automaticamente e retornar o resultado, o servidor está funcionando.
É possível implantar um MCP Server em um servidor remoto?
Sim. O transporte stdio usado neste artigo é adequado para desenvolvimento local. Em produção, você pode usar HTTP/SSE, com autenticação OAuth e limitação de requisições.

11 min de leitura · Publicado em: 19 mar 2026 · Atualizado em: 8 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog