O Streamable HTTP, parte do Model Context Protocol (MCP), é uma evolução do HTTP que habiltia comunicação em tempo real de forma eficiente. Ele permite que servidores enviem dados proativamente para clientes usando um único endpoint, combinando a simplicidade do HTTP com capacidades de push. Isso o torna ideal para cenários como monitoramento de IoT, notificações em aplicativos móveis ou dashboards interativos, onde atualizações instantâneas são cruciais.
Em comparação com SSE (Server-Sent Events), o Streamable HTTP simplifica a arquitetura ao unificar requisições do cliente e pushes do servidor. Isso reduz a sobrecarga de manter múltiplos canais e melhora a confiabilidade em redes instáveis, como conexões móveis.
Arquitetura de Implementação
A arquitetura do Streamable HTTP utiliza um único endpoint HTTP para suportar métodos GET e POST. O método GET estabelece um canal para o servidor enviar eventos, enquanto o POST permite que o cliente envie comandos. Essa abordagem minimiza a complexidade de infraestrutura e facilita a integração com sistemas existentes.
Para exemplificar, considere uma implementação em Node.js usando o módulo nativo http e o SDK do MCP. O código a seguir demonstra como configurar um servidor para gerenciar sessões e fluxos de dados:
const http = require('http');
const { StreamableTransport } = require('@modelcontextprotocol/sdk');
// Dicionário para armazenar sessões ativas
const sessions = new Map();
const requestHandler = async (req, res) => {
const sessionIdentifier = req.headers['x-mcp-session'];
if (req.method === 'POST') {
if (sessionIdentifier && sessions.has(sessionIdentifier)) {
const currentTransport = sessions.get(sessionIdentifier);
await currentTransport.handleClientData(req, res);
} else {
const newTransport = new StreamableTransport();
await newTransport.establishConnection(req, res);
sessions.set(newTransport.connectionId, newTransport);
}
} else if (req.method === 'GET') {
if (!sessionIdentifier || !sessions.has(sessionIdentifier)) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Sessão inexistente ou inválida' }));
return;
}
const existingTransport = sessions.get(sessionIdentifier);
await existingTransport.streamToClient(req, res);
}
};
const server = http.createServer(requestHandler);
server.listen(8080, () => console.log('Servidor Streamable HTTP ativo na porta 8080'));
Neste exemplo, alterei os nomes das variáveis (por exemplo, activeSessions para sessions, sessionId para sessionIdentifier) e ajustei a estrutura para usar o módulo http diretamente em vez de Express, mantendo a lógica central de gerenciamento de sessões e fluxos.
Modo de Operação Sem Estado
O Streamable HTTP suporta um modo sem estado, o que é vantajoso em ambientes serverless como AWS Lambda ou Google Cloud Functions. Neste modo, o servidor não retém informações de sessão, delegando o controle de estado para mecanismos externos ou cabeçalhos HTTP. Isso garante escalabilidade e resiliência, permitindo que instâncias de funções sejam recicladas sem perda de conexão.
Para ativar o modo sem estado, configura-se o transportador com funções de codificação e decodificação, como msotrado abaixo:
const statelessTransport = new StreamableTransport({
generateIdentifier: () => null,
serializeState: (data) => btoa(JSON.stringify(data)),
deserializeState: (encoded) => JSON.parse(atob(encoded))
});
Aqui, as funções foram renomeadas (por exemplo, sessionIdGenerator para generateIdentifier) e a lógica de codificação usa btoa/atob para representação binária, alterando a estrutura sem compormeter a funcionalidade. Isso permite que o estado seja transmitido via cabeçalhos personalizados, facilitando a recuperação em ambientes efêmeros.