Como Construir um Servidor MCP para Seu Produto SaaS em 2025
Protocolo de Contexto de Modelo: O Guia de Produção que Você Realmente Precisa
Se você esteve acompanhando o espaço de ferramentas de IA em 2025, provavelmente notou que o Model Context Protocol (MCP) evoluiu de "especificação interessante da Anthropic" para "coisa que todo produto SaaS sério precisa suportar." E com razão. O MCP oferece aos agentes de IA -- Claude, assistentes baseados em GPT, agentes customizados -- uma maneira padronizada de descobrir e chamar sua API. Pense nisso como OpenAPI para a era de agentes, mas com comunicação bidirecional em tempo real integrada.
Passei os últimos meses construindo servidores MCP para vários produtos SaaS, e quero compartilhar o que realmente funciona, o que a documentação não te diz, e as decisões arquiteturais que importam. Isso não é uma reiteração da especificação. Este é o guia que eu gostaria de ter tido quando comecei.
Índice
- O que é o Protocolo de Contexto de Modelo (MCP)?
- Por que seu Produto SaaS Precisa de um Servidor MCP
- Arquitetura MCP: Como Realmente Funciona
- Configurando seu Projeto de Servidor MCP
- Definindo Ferramentas, Recursos e Prompts
- Conectando à sua API SaaS
- Autenticação e Multi-Tenância
- Tratamento de Erros e Validação
- Testando seu Servidor MCP
- Deployment e Considerações de Produção
- Exemplo do Mundo Real: Construindo um Servidor MCP para um SaaS de Gerenciamento de Projetos
- Perguntas Frequentes
O que é o Protocolo de Contexto de Modelo (MCP)?
MCP é um protocolo aberto originalmente criado pela Anthropic que define como modelos de IA se comunicam com ferramentas externas e fontes de dados. Lançado no final de 2024 e atingindo estabilidade v1.0 no início de 2025, agora é suportado pelo Claude Desktop, Cursor, Windsurf, OpenAI Agents SDK, e dezenas de outros clientes de IA.
A ideia central: em vez de cada integração de IA ser um plugin customizado com um formato proprietário, MCP fornece um único protocolo que qualquer cliente compatível pode usar para descobrir o que seu serviço oferece e interagir com ele.
Aqui está o que MCP define:
- Ferramentas -- Funções que a IA pode chamar (como
create_ticket,search_users,generate_report) - Recursos -- Dados que a IA pode ler (como documentação, registros de banco de dados, arquivos de configuração)
- Prompts -- Modelos de prompt reutilizáveis que seu servidor pode expor
- Sampling -- A capacidade do seu servidor solicitar conclusões de LLM do cliente
A camada de transporte usa JSON-RPC 2.0 via stdio (para servidores locais) ou HTTP com Server-Sent Events (SSE) para servidores remotos. O transporte HTTP Streamable mais recente, introduzido na revisão da especificação 2025-03, é o que você desejará para qualquer deployment de SaaS em produção.
Por que seu Produto SaaS Precisa de um Servidor MCP
Deixe-me ser direto: se seu produto SaaS tem uma API, você deveria estar construindo um servidor MCP agora mesmo. Eis o porquê.
Agentes de IA estão se tornando os consumidores primários de API. No Q1 de 2025, a Anthropic relatou que usuários do Claude Desktop invocam ferramentas MCP mais de 2 milhões de vezes por dia. Esse número está crescendo rapidamente. Seus clientes já estão tentando usar agentes de IA para interagir com seu produto -- a questão é se você torna isso fácil ou frustrante.
É um canal de distribuição. Quando alguém instala Claude Desktop e digita "ajude-me a gerenciar meus projetos", a IA pode descobrir e usar servidores MCP que o usuário configurou. Seu produto fica acessível através de linguagem natural. Isso não é uma gimmick -- é uma verdadeira nova superfície para seu produto.
Seus concorrentes estão fazendo isso. Stripe, Linear, Notion, GitHub, Sentry, e Supabase todos lançaram servidores MCP na primeira metade de 2025. Se você está em SaaS B2B e não tem um, está ficando para trás.
| Fator | Apenas API REST | API REST + Servidor MCP |
|---|---|---|
| Acessibilidade de agente de IA | Requer integração customizada por agente | Qualquer cliente MCP funciona automaticamente |
| Descoberta | Desenvolvedores leem documentação | IA descobre capacidades em tempo real |
| Tempo para primeira integração | Horas até dias | Minutos |
| Interação em linguagem natural | Não é possível sem wrapper | Integrada |
| Carga de manutenção | Uma base de código | Duas bases de código (mas MCP envolve REST) |
Arquitetura MCP: Como Realmente Funciona
Antes de escrevermos código, vamos deixar a arquitetura clara. Um deployment MCP tem três partes:
- Cliente MCP -- A aplicação de IA (Claude Desktop, Cursor, seu agente customizado). Descobre as capacidades do seu servidor e as chama.
- Servidor MCP -- Seu código. Expõe ferramentas, recursos e prompts via protocolo MCP. Isso é o que estamos construindo.
- Sua API SaaS -- O backend real que seu servidor MCP chama para fazer as coisas acontecerem.
O fluxo se parece com isto:
Usuário → Cliente de IA → Cliente MCP → Servidor MCP → Sua API SaaS
↓
Resposta flui de volta
Seu servidor MCP é essencialmente um adaptador de protocolo. Traduz entre o protocolo MCP (que clientes de IA falam) e sua API REST/GraphQL existente. Isso significa que você não precisa modificar sua API existente. O servidor MCP fica ao lado dela.
Opções de Transporte
Para produtos SaaS, você tem duas opções realistas de transporte:
- HTTP Streamable (recomendado): Usa requisições HTTP padrão com SSE opcional para streaming. Funciona atrás de load balancers, CDNs e infraestrutura padrão. Isso é o que você quer para servidores MCP remotos/hospedados.
- SSE (legado): O transporte remoto original. Ainda funciona mas a especificação recomenda HTTP Streamable para novas implementações.
O transporte Stdio é ótimo para ferramentas locais mas não é aplicável para um servidor MCP de produto SaaS.
Configurando seu Projeto de Servidor MCP
Vamos construir isso com TypeScript. O pacote oficial @modelcontextprotocol/sdk é bem mantido e é a escolha certa para uso em produção. Python tem mcp (o SDK oficial do Python) se esse for seu stack, mas vou focar em TypeScript já que a maioria dos backends SaaS com os quais trabalho usam Node.js.
mkdir my-saas-mcp-server
cd my-saas-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod express
npm install -D typescript @types/node @types/express tsx
Configure seu tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
Agora vamos criar a estrutura básica do servidor:
// src/server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
const server = new McpServer({
name: "my-saas-mcp",
version: "1.0.0",
description: "MCP server for My SaaS Product",
});
// We'll add tools, resources, and prompts here
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
});
await server.connect(transport);
await transport.handleRequest(req, res);
});
app.get("/mcp", async (req, res) => {
// SSE endpoint for streaming responses
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
});
await server.connect(transport);
await transport.handleRequest(req, res);
});
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`MCP server running on port ${PORT}`);
});
Esse é seu esqueleto. Vamos preenchê-lo.
Definindo Ferramentas, Recursos e Prompts
Ferramentas
Ferramentas são a primitiva mais importante. Cada ferramenta é uma função que a IA pode chamar com parâmetros estruturados. Eis como definir uma:
import { z } from "zod";
server.tool(
"create_project",
"Create a new project in the workspace",
{
name: z.string().describe("The project name"),
description: z.string().optional().describe("Project description"),
team_id: z.string().describe("ID of the team that owns this project"),
},
async ({ name, description, team_id }) => {
// Call your SaaS API here
const project = await apiClient.createProject({ name, description, team_id });
return {
content: [
{
type: "text",
text: JSON.stringify(project, null, 2),
},
],
};
}
);
Algumas coisas que aprendi sobre design de ferramentas:
Seja específico com descrições. A IA usa sua descrição de ferramenta e descrições de parâmetros para decidir quando e como chamá-la. Descrições vagas levam à seleção errada de ferramentas. "Criar um novo projeto" é ok. "Criar um novo projeto no workspace do usuário. Requer um team_id que pode ser obtido da ferramenta list_teams" é muito melhor.
Mantenha a contagem de ferramentas gerenciável. Vi pessoas expondo 50+ ferramentas e se perguntando por que a IA fica confusa. Comece com 10-15 operações principais. Você sempre pode adicionar mais.
Retorne dados estruturados. Sempre retorne JSON no conteúdo do seu texto. A IA o analisa melhor que prosa.
Recursos
Recursos expõem dados legíveis. Pense neles como endpoints GET para consumo de IA:
server.resource(
"project-list",
"projects://list",
"List of all projects in the workspace",
async () => {
const projects = await apiClient.listProjects();
return {
contents: [
{
uri: "projects://list",
mimeType: "application/json",
text: JSON.stringify(projects, null, 2),
},
],
};
}
);
Prompts
Prompts são modelos reutilizáveis. Eles são subutilizados mas poderosos:
server.prompt(
"weekly-report",
"Generate a weekly status report for a project",
{
project_id: z.string().describe("The project ID to report on"),
},
async ({ project_id }) => {
const stats = await apiClient.getProjectStats(project_id);
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Generate a weekly status report based on this data: ${JSON.stringify(stats)}. Include completed tasks, blockers, and upcoming deadlines.`,
},
},
],
};
}
);
Conectando à sua API SaaS
Seu servidor MCP precisa conversar com sua API existente. Recomendo criar uma classe de cliente de API tipada:
// src/api-client.ts
class SaaSApiClient {
private baseUrl: string;
private apiKey: string;
constructor(baseUrl: string, apiKey: string) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}
private async request<T>(path: string, options?: RequestInit): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, {
...options,
headers: {
"Authorization": `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
...options?.headers,
},
});
if (!response.ok) {
const error = await response.text();
throw new Error(`API error ${response.status}: ${error}`);
}
return response.json() as T;
}
async createProject(data: CreateProjectInput): Promise<Project> {
return this.request<Project>("/api/v1/projects", {
method: "POST",
body: JSON.stringify(data),
});
}
async listProjects(): Promise<Project[]> {
return this.request<Project[]>("/api/v1/projects");
}
// ... more methods
}
Mantenha esse cliente fino. É um pass-through, não uma camada de lógica de negócios.
Autenticação e Multi-Tenância
É aqui que as coisas ficam interessantes -- e onde a maioria dos tutoriais passa por cima das partes difíceis.
Seu servidor MCP precisa autenticar requisições de duas maneiras:
- O cliente MCP autenticando para seu servidor MCP ("isso é um usuário válido?")
- Seu servidor MCP autenticando para sua API SaaS ("agir em nome desse usuário")
OAuth 2.0 (Recomendado para Produção)
A especificação MCP inclui um framework de autorização baseado em OAuth 2.1. Para um produto SaaS, esta é a abordagem correta:
// Middleware to extract and validate the OAuth token
app.use("/mcp", async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
return res.status(401).json({ error: "Missing authorization" });
}
const token = authHeader.slice(7);
try {
const user = await validateOAuthToken(token);
req.user = user;
next();
} catch {
return res.status(401).json({ error: "Invalid token" });
}
});
Depois passe o contexto do usuário para seus manipuladores de ferramentas. Isso é crítico para multi-tenância -- cada chamada de API deve ser escopo do workspace do usuário autenticado.
Abordagem de Chave de API (Mais Simples, para Interno/Estágio Inicial)
Se você está em estágio inicial ou isso é apenas interno, chaves de API funcionam bem:
const apiKey = req.headers["x-api-key"] as string;
const client = new SaaSApiClient(process.env.API_BASE_URL!, apiKey);
O usuário fornece sua chave de API ao configurar o servidor MCP no seu cliente, e ela é passada para sua API.
Tratamento de Erros e Validação
Agentes de IA precisam de mensagens de erro claras. Quando uma ferramenta falha, a IA precisa entender o porquê para poder corrigir a entrada ou explicar o problema ao usuário.
server.tool(
"get_project",
"Get project details by ID",
{ project_id: z.string().uuid().describe("The project's UUID") },
async ({ project_id }) => {
try {
const project = await apiClient.getProject(project_id);
return {
content: [{ type: "text", text: JSON.stringify(project, null, 2) }],
};
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
return {
isError: true,
content: [
{
type: "text",
text: `Failed to get project: ${message}. Make sure the project_id is a valid UUID and the project exists in your workspace.`,
},
],
};
}
}
);
Repare no sinalizador isError: true. Isso diz ao cliente MCP que a chamada da ferramenta falhou, para que possa lidar com isso apropriadamente. Sempre inclua orientação acionável em mensagens de erro.
Testando seu Servidor MCP
Testar servidores MCP ficou muito mais fácil em 2025. Aqui estão suas opções:
Inspetor MCP
O Inspetor MCP oficial é seu melhor amigo durante o desenvolvimento:
npx @modelcontextprotocol/inspector
Isso te dá uma UI web onde você pode se conectar ao seu servidor, navegar ferramentas/recursos, e invocá-los interativamente. Use constantemente.
Testes Automatizados
Para CI/CD, teste suas ferramentas como funções async regulares:
import { describe, it, expect } from "vitest";
describe("create_project tool", () => {
it("should create a project with valid input", async () => {
const result = await createProjectHandler({
name: "Test Project",
team_id: "team-123",
});
expect(result.isError).toBeUndefined();
const data = JSON.parse(result.content[0].text);
expect(data.name).toBe("Test Project");
});
it("should return error for missing team_id", async () => {
// Zod validation should catch this before the handler runs
// Test the validation layer
});
});
Testes de Integração com Claude Desktop
Uma vez que seu servidor estiver rodando, adicione-o à configuração do Claude Desktop:
{
"mcpServers": {
"my-saas": {
"url": "http://localhost:3001/mcp",
"headers": {
"Authorization": "Bearer your-test-token"
}
}
}
}
Então apenas converse com Claude e tente usar suas ferramentas naturalmente. Você encontrará rapidamente casos extremos que os testes automatizados perderam.
Deployment e Considerações de Produção
Onde Fazer Deploy
Seu servidor MCP é apenas um app Express. Faça deploy onde você faz deploy de serviços Node.js. Algumas boas opções:
| Plataforma | Cold Start | Custo (est.) | Melhor Para |
|---|---|---|---|
| Railway | Nenhum | ~$5-20/mês | SaaS pequeno-médio |
| Fly.io | <500ms | ~$5-15/mês | Distribuição global |
| AWS ECS/Fargate | Nenhum | ~$15-50/mês | Enterprise, AWS existente |
| Vercel (Edge) | <100ms | $0-20/mês | Se você já está na Vercel |
| Cloudflare Workers | <5ms | $0-5/mês | Performance-crítico |
Rate Limiting
Agentes de IA podem ser tagarelas. Uma única conversa de usuário pode disparar 20-30 chamadas de ferramenta. Implemente rate limiting que seja generoso o suficiente para uso normal de IA mas previna abuso:
import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 60, // 60 requests per minute per user
keyGenerator: (req) => req.user?.id || req.ip,
});
app.use("/mcp", limiter);
Monitoramento
Registre cada invocação de ferramenta com o ID do usuário, nome da ferramenta e latência. Você quer visibilidade sobre quais ferramentas são mais usadas, quais falham mais, e onde estão os gargalos de latência. Datadog, Axiom, ou até logs JSON estruturados para CloudWatch funcionam bem.
Versionamento
Seu servidor MCP evoluirá. Use o campo version nos metadados do seu servidor e considere executar múltiplas versões atrás de um prefixo de caminho (/mcp/v1, /mcp/v2) durante transições.
Exemplo do Mundo Real: Construindo um Servidor MCP para um SaaS de Gerenciamento de Projetos
Deixe-me percorrer um exemplo real. Digamos que você esteja construindo um servidor MCP para uma ferramenta de gerenciamento de projetos (pense em um Linear ou Asana simplificado).
Eis o conjunto de ferramentas que eu exporia:
// Core CRUD tools
server.tool("list_projects", ...);
server.tool("get_project", ...);
server.tool("create_project", ...);
server.tool("update_project", ...);
// Task management
server.tool("list_tasks", ...); // with filters for status, assignee, project
server.tool("create_task", ...);
server.tool("update_task", ...); // update status, assignee, priority
server.tool("add_comment", ...);
// Search and reporting
server.tool("search", ...); // full-text search across projects and tasks
server.tool("get_project_stats", ...); // summary stats for a project
// Resources
server.resource("workspace-info", ...); // workspace config, team members
// Prompts
server.prompt("standup-report", ...); // generate a standup from recent activity
server.prompt("sprint-planning", ...); // help plan a sprint
São 12 ferramentas, 1 recurso, e 2 prompts. O suficiente para ser genuinamente útil sem sobrecarregar a seleção de ferramenta da IA.
A experiência do usuário se parece com isto: alguém abre Claude Desktop e diz "Quais tarefas estão vencidas no projeto Backend Rewrite?" Claude chama list_tasks com um filtro de status e nome de projeto, obtém os resultados, e os apresenta em linguagem natural. O usuário diz "Atribua a tarefa de migração de auth à Sarah e aumente-a para alta prioridade." Claude chama update_task. Parece mágica, e é realmente apenas encanamento de protocolo.
Se você está construindo algo assim e quer ajuda com o frontend Next.js ou a camada headless CMS que frequentemente acompanha esses projetos, isso é algo que fazemos muito na Social Animal. Mas o servidor MCP em si? Isso é algo que você pode absolutamente construir internamente com este guia.
Perguntas Frequentes
Qual é a diferença entre MCP e function calling? Function calling (como function calling do OpenAI ou tool use do Claude) é como um modelo de IA decide invocar uma função dentro de uma única chamada de API. MCP é o protocolo que permite a um cliente de IA descobrir quais funções estão disponíveis de servidores externos. Eles trabalham juntos -- o cliente de IA usa function calling internamente para decidir quando invocar uma ferramenta MCP. Pense em MCP como o encanamento entre sistemas, e function calling como o processo de tomada de decisão do modelo.
Quanto custa construir e executar um servidor MCP? O servidor em si é leve. Para um produto SaaS típico com 10-20 ferramentas, você está olhando para algumas centenas de linhas de TypeScript. Custos de hospedagem $5-50/mês dependendo do seu tráfego e plataforma. O custo real é tempo de desenvolvedor -- orçamento 2-4 semanas para um servidor MCP de qualidade de produção com auth, tratamento de erros, monitoramento e testes. Se isso parece muito, ajudamos times a enviar estes mais rápido. Verifique nossa página de preços para detalhes.
Posso usar Python em vez de TypeScript?
Absolutamente. O SDK oficial do Python (pip install mcp) é excelente e possivelmente tem ergonomia melhor para definições de ferramentas. Use o que sua equipe conhece. O protocolo é agnóstico de linguagem. Se seu backend SaaS é Python (Django, FastAPI), construir o servidor MCP em Python faz ainda mais sentido já que você pode compartilhar modelos e lógica de validação.
Preciso modificar minha API existente? Não. Seu servidor MCP é um serviço separado que chama sua API existente. É uma camada adaptadora. Dito isto, você pode se ver querendo adicionar alguns endpoints de API especificamente para consumo de IA -- como um endpoint de busca que retorna mais contexto do que sua UI precisa. Isso é bom. Mas é aditivo, não uma modificação.
Como lidar com operações de longa duração?
Algumas ferramentas podem disparar operações que levam minutos (como gerar um relatório ou processar uma importação grande). Use o recurso de notificação de progresso do MCP para manter o cliente informado. Seu manipulador de ferramenta pode emitir atualizações de progresso enquanto espera a operação completar. Para operações muito longas (>30 segundos), considere retornar imediatamente com um ID de trabalho e fornecer uma ferramenta separada check_job_status.
MCP é estável o suficiente para produção? Sim, a partir de meados de 2025. A especificação atingiu v1.0 em março de 2025, e a revisão 2025-03-26 (que adicionou HTTP Streamable) é o que os clientes principais adotaram. Anthropic, Microsoft, Google, e OpenAI estão todos investindo no protocolo. Não vai desaparecer. Dito isto, fique atento a atualizações de especificação -- há propostas ativas sobre fluxos de auth melhores e comunicação servidor-para-servidor.
Qual é a melhor maneira de lidar com paginação em ferramentas MCP?
Retorne uma página razoável de resultados (20-50 itens) por padrão, e aceite parâmetros cursor ou page. Inclua metadados de paginação na sua resposta para que a IA saiba que há mais resultados. Algo como: { results: [...], next_cursor: "abc123", total_count: 342 }. A IA naturalmente pedirá a próxima página se o usuário precisar de mais dados.
Um servidor MCP pode suportar múltiplos clientes de IA simultaneamente? Sim, e deveria. Seu servidor MCP é apenas um servidor HTTP manipulando requisições concorrentes. Cada requisição inclui o token de auth do usuário, então você escopa tudo para o tenant correto. Não há estado específico do cliente para se preocupar se você estiver usando o transporte HTTP Streamable corretamente. Trate como qualquer outro servidor de API stateless.