Streamable HTTP com MCP: Guia Técnico para Sistemas de Comunicação em Tempo Real

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.

Tags: MCP Streamable HTTP javascript Node.js Serverless

Publicado em 6-25 22:08