Se você leu o nosso Guia sobre Model Context Protocol (MCP) e o nosso Tutorial de MCP Server com TypeScript, você já sabe como esse protocolo está revolucionando a integração de Inteligência Artificial localmente nas nossas IDEs favoritas, como o Cursor e o Claude Desktop.
Mas e se você quisesse conectar o seu agente de IA a um servidor remoto na nuvem? E se você quisesse criar uma aplicação baseada em navegador (Web App) que interage com agentes inteligentes usando o MCP, sem depender do sistema de arquivos local do usuário ou do terminal dele? É aqui que o WebMCP brilha.
Neste artigo, vamos explorar o conceito de WebMCP, compreender como funciona o transporte baseado em SSE (Server-Sent Events) e implementar passo a passo um servidor WebMCP remoto utilizando Node.js e TypeScript.
A Limitação do Standard I/O (stdio)
Por padrão, a maioria dos servidores MCP que configuramos localmente se comunica através do fluxo padrão de entrada e saída do sistema operacional (stdio). A IDE inicia o processo do servidor em background e se comunica com ele por meio de streams de texto.
Embora essa abordagem seja extremamente rápida, performática e segura para execuções locais, ela impõe barreiras físicas:
- Isolamento de Máquina: A IA e o servidor MCP precisam estar no mesmo computador.
- Incompatibilidade Web: Navegadores não possuem acesso direto para spawnar processos de sistema ou ler/escrever fluxos de
stdioarbitrários por razões óbvias de sandbox e segurança. - Dificuldade de Compartilhamento: Se uma equipe deseja usar uma ferramenta customizada e centralizada (como um catálogo corporativo de microsserviços), cada desenvolvedor precisaria instalar e configurar o servidor MCP localmente em sua própria máquina.
A Magia do Server-Sent Events (SSE)
Para o transporte na Web, a especificação oficial do MCP adota a arquitetura de SSE (Server-Sent Events) associada a requisições HTTP POST tradicionais. Mas por que o SSE foi escolhido em vez de WebSockets ou polling simples?
O SSE é uma tecnologia nativa que permite ao servidor enviar notificações de mão única em tempo real para o cliente sobre uma conexão HTTP de longa duração. No fluxo de mensagens do WebMCP, o tráfego JSON-RPC 2.0 funciona da seguinte forma:
- Conexão Inicial: O cliente web (MCP Client) inicia uma conexão HTTP GET em um endpoint específico do servidor (por exemplo,
/sse). O servidor responde mantendo a conexão aberta com o headerContent-Type: text/event-stream. - Event Stream (Servidor ➔ Cliente): Através dessa conexão aberta, o servidor pode enviar mensagens e respostas assíncronas para o cliente de forma contínua e em tempo real.
- Requisições HTTP POST (Cliente ➔ Servidor): Quando o cliente precisa enviar uma requisição ou comando para o servidor (como chamar uma ferramenta), ele faz uma requisição HTTP POST comum para um endpoint separado (geralmente chamado de
/messages), passando a payload no corpo.
Essa arquitetura assíncrona desacoplada simplifica drasticamente o roteamento em firewalls e proxies reversos corporativos se comparado ao protocolo WebSockets, operando totalmente sob HTTPS padrão.
Tutorial Prático: Construindo um Servidor WebMCP com SSE
Vamos colocar a mão na massa e criar um servidor WebMCP funcional utilizando o SDK oficial da Anthropic (@modelcontextprotocol/sdk) e o Express no Node.js.
1. Inicialização do Projeto
Crie um diretório para o projeto e instale as dependências necessárias. Utilizaremos o SDK oficial e o Express, juntamente com o Zod para validação e suporte a TypeScript:
npm init -y
npm install @modelcontextprotocol/sdk express cors zod
npm install --save-dev typescript @types/express @types/node @types/cors ts-node
2. Escrevendo o Servidor Express com SSE
Crie um arquivo chamado server.ts. Neste arquivo, configuramos a instância clássica de Server do MCP e mapeamos os endpoints HTTP necessários para configurar o SSEServerTransport:
import express from "express";
import cors from "cors";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
const app = express();
app.use(cors());
app.use(express.json());
// 1. Instanciando o Servidor MCP
const mcpServer = new Server(
{
name: "webmcp-demo-server",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // Habilitando suporte a ferramentas dinâmicas
},
}
);
// 2. Definindo uma ferramenta para consultar informações
const CONSULTAR_DOC_TOOL = {
name: "consultar_documentacao",
description: "Busca informações técnicas na base interna corporativa.",
inputSchema: {
type: "object",
properties: {
termo: {
type: "string",
description: "Termo de busca (ex: 'deploy', 'auth', 'database')",
},
},
required: ["termo"],
},
};
// 3. Registrando handlers do MCP
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [CONSULTAR_DOC_TOOL],
};
});
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "consultar_documentacao") {
const termo = z.string().parse(args?.termo);
let resposta = `Nenhuma documentação encontrada para: ${termo}`;
if (termo.toLowerCase().includes("deploy")) {
resposta = "Procedimento de Deploy: Execute 'npm run build' e depois faça o push na branch developer.";
} else if (termo.toLowerCase().includes("auth")) {
resposta = "Autenticação: Utilize os tokens JWT gerados via cabeçalho Authorization: Bearer.";
}
return {
content: [{ type: "text", text: resposta }],
};
}
throw new Error("Ferramenta não encontrada");
});
// 4. Mapeando sessões ativas do SSE
const activeTransports = new Map<string, SSEServerTransport>();
app.get("/sse", async (req, res) => {
console.log("🔌 Novo cliente iniciando conexão SSE");
// Criamos o transporte SSE apontando para a rota de mensagens HTTP POST
const transport = new SSEServerTransport("/messages", res);
// Salvamos o transporte associado ao ID da conexão
const sessionId = transport.sessionId;
activeTransports.set(sessionId, transport);
// Conectamos o transporte ao nosso servidor MCP
await mcpServer.connect(transport);
// Removemos o transporte do cache quando a conexão é encerrada
req.on("close", () => {
console.log(`❌ Conexão SSE encerrada para a sessão ${sessionId}`);
activeTransports.delete(sessionId);
});
});
app.post("/messages", async (req, res) => {
const sessionId = req.query.sessionId as string;
const transport = activeTransports.get(sessionId);
if (!transport) {
res.status(404).send("Sessão ativa não encontrada.");
return;
}
// Delega a leitura e parse do payload JSON-RPC para o SDK do MCP resolver
await transport.handleMessage(req, res);
});
const PORT = 3002;
app.listen(PORT, () => {
console.log(`🚀 Servidor WebMCP rodando em http://localhost:${PORT}`);
console.log(` -> Conexão SSE: http://localhost:${PORT}/sse`);
});
SSEServerTransport gera dinamicamente um identificador único de sessão (sessionId). O cliente web precisará passar este ID como query string ao fazer requisições POST para a rota de mensagens (ex: /messages?sessionId=xpto), permitindo que o servidor direcione a resposta para o túnel SSE correto.
Consumindo o Servidor WebMCP
Agora que você tem um servidor WebMCP expondo endpoints HTTP, você pode conectá-lo a clientes. No ecossistema moderno, existem duas formas principais:
1. Configurando em Ferramentas Locais
O próprio Claude Desktop e IDEs como o Cursor aceitam conexões SSE nativamente em seus arquivos de configuração. Veja um exemplo de configuração no claude_desktop_config.json:
{
"mcpServers": {
"meu-servidor-web-mcp": {
"url": "http://localhost:3002/sse"
}
}
}
2. Integrando diretamente em Web Apps
Se você estiver desenvolvendo o seu próprio chatbot ou painel web, você pode utilizar o SDK de cliente no navegador. Veja como se conectar usando Vanilla JavaScript/TypeScript no client-side:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const client = new Client({
name: "meu-web-app-client",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new SSEClientTransport(new URL("http://localhost:3002/sse"));
await client.connect(transport);
// A partir daqui, o cliente web está conectado de forma bidirecional!
const tools = await client.listTools();
console.log("Ferramentas disponíveis remotamente:", tools);
Conclusão
O WebMCP desamarra o Model Context Protocol do ambiente do computador local e o escala para toda a Web. Seja centralizando ferramentas e utilitários da sua equipe de engenharia em um único servidor remoto ou criando aplicações e assistentes de IA interativos que rodam inteiramente no navegador, o uso de SSE no MCP abre portas gigantescas para a computação e automação por agentes em 2026.
Que tal testar a criação de ferramentas no seu próprio servidor WebMCP para formatar dados em tempo real ou analisar payloads corporativos?
🛠️ Experimente na prática
Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.
