26 KiB
Streaming HTTPS com Model Context Protocol (MCP)
Este capítulo fornece um guia abrangente para implementar streaming seguro, escalável e em tempo real com o Model Context Protocol (MCP) usando HTTPS. Ele cobre a motivação para streaming, os mecanismos de transporte disponíveis, como implementar HTTP transmissível no MCP, melhores práticas de segurança, migração de SSE e orientações práticas para construir suas próprias aplicações de streaming MCP.
Mecanismos de Transporte e Streaming no MCP
Esta seção explora os diferentes mecanismos de transporte disponíveis no MCP e seu papel em possibilitar capacidades de streaming para comunicação em tempo real entre clientes e servidores.
O que é um Mecanismo de Transporte?
Um mecanismo de transporte define como os dados são trocados entre o cliente e o servidor. O MCP suporta múltiplos tipos de transporte para atender diferentes ambientes e requisitos:
- stdio: Entrada/saída padrão, adequado para ferramentas locais e baseadas em CLI. Simples, mas não adequado para web ou nuvem.
- SSE (Server-Sent Events): Permite que servidores enviem atualizações em tempo real para clientes via HTTP. Bom para interfaces web, mas limitado em escalabilidade e flexibilidade. A partir da Especificação MCP 2025-06-18, o transporte SSE autônomo (Server-Sent Events) foi descontinuado e substituído pelo transporte "Streamable HTTP".
- Streamable HTTP: Transporte de streaming moderno baseado em HTTP, suportando notificações e melhor escalabilidade. Recomendado para a maioria dos cenários em produção e na nuvem.
Tabela de Comparação
Confira a tabela de comparação abaixo para entender as diferenças entre esses mecanismos de transporte:
| Transporte | Atualizações em Tempo Real | Streaming | Escalabilidade | Caso de Uso |
|---|---|---|---|---|
| stdio | Não | Não | Baixa | Ferramentas CLI locais |
| SSE | Sim | Sim | Média | Web, atualizações em tempo real |
| Streamable HTTP | Sim | Sim | Alta | Nuvem, múltiplos clientes |
Dica: Escolher o transporte correto impacta performance, escalabilidade e experiência do usuário. Streamable HTTP é recomendado para aplicações modernas, escaláveis e preparadas para nuvem.
Observe os transportes stdio e SSE que foram apresentados nos capítulos anteriores e como o streamable HTTP é o transporte abordado neste capítulo.
Streaming: Conceitos e Motivação
Entender os conceitos fundamentais e a motivação por trás do streaming é essencial para implementar sistemas de comunicação em tempo real eficazes.
Streaming é uma técnica em programação de rede que permite que dados sejam enviados e recebidos em pequenos pedaços gerenciáveis ou como uma sequência de eventos, ao invés de esperar que toda uma resposta esteja pronta. Isso é especialmente útil para:
- Arquivos ou conjuntos de dados grandes.
- Atualizações em tempo real (ex: chat, barras de progresso).
- Computações de longa duração onde você quer manter o usuário informado.
Aqui está o que você precisa saber sobre streaming em alto nível:
- Os dados são entregues progressivamente, não de uma só vez.
- O cliente pode processar os dados conforme eles chegam.
- Reduz a latência percebida e melhora a experiência do usuário.
Por que usar streaming?
As razões para usar streaming são as seguintes:
- Os usuários recebem feedback imediatamente, não só ao final.
- Habilita aplicações em tempo real e interfaces responsivas.
- Uso mais eficiente dos recursos de rede e computação.
Exemplo Simples: Servidor & Cliente de Streaming HTTP
Aqui está um exemplo simples de como o streaming pode ser implementado:
Python
Servidor (Python, usando FastAPI e StreamingResponse):
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import time
app = FastAPI()
async def event_stream():
for i in range(1, 6):
yield f"data: Message {i}\n\n"
time.sleep(1)
@app.get("/stream")
def stream():
return StreamingResponse(event_stream(), media_type="text/event-stream")
Cliente (Python, usando requests):
import requests
with requests.get("http://localhost:8000/stream", stream=True) as r:
for line in r.iter_lines():
if line:
print(line.decode())
Este exemplo demonstra um servidor enviando uma série de mensagens ao cliente conforme elas ficam disponíveis, ao invés de esperar que todas as mensagens estejam prontas.
Como funciona:
- O servidor produz cada mensagem assim que ela está pronta.
- O cliente recebe e imprime cada pedaço conforme chega.
Requisitos:
- O servidor deve usar uma resposta de streaming (ex:
StreamingResponseno FastAPI). - O cliente deve processar a resposta como um stream (
stream=Trueno requests). - O Content-Type é geralmente
text/event-streamouapplication/octet-stream.
Java
Servidor (Java, usando Spring Boot e Server-Sent Events):
@RestController
public class CalculatorController {
@GetMapping(value = "/calculate", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> calculate(@RequestParam double a,
@RequestParam double b,
@RequestParam String op) {
double result;
switch (op) {
case "add": result = a + b; break;
case "sub": result = a - b; break;
case "mul": result = a * b; break;
case "div": result = b != 0 ? a / b : Double.NaN; break;
default: result = Double.NaN;
}
return Flux.<ServerSentEvent<String>>just(
ServerSentEvent.<String>builder()
.event("info")
.data("Calculating: " + a + " " + op + " " + b)
.build(),
ServerSentEvent.<String>builder()
.event("result")
.data(String.valueOf(result))
.build()
)
.delayElements(Duration.ofSeconds(1));
}
}
Cliente (Java, usando Spring WebFlux WebClient):
@SpringBootApplication
public class CalculatorClientApplication implements CommandLineRunner {
private final WebClient client = WebClient.builder()
.baseUrl("http://localhost:8080")
.build();
@Override
public void run(String... args) {
client.get()
.uri(uriBuilder -> uriBuilder
.path("/calculate")
.queryParam("a", 7)
.queryParam("b", 5)
.queryParam("op", "mul")
.build())
.accept(MediaType.TEXT_EVENT_STREAM)
.retrieve()
.bodyToFlux(String.class)
.doOnNext(System.out::println)
.blockLast();
}
}
Notas de Implementação Java:
- Usa a stack reativa do Spring Boot com
Fluxpara streaming. ServerSentEventfornece streaming de eventos estruturados com tipos de evento.WebClientcombodyToFlux()permite consumo reativo do streaming.delayElements()simula tempo de processamento entre eventos.- Eventos podem ter tipos (
info,result) para melhor tratamento no cliente.
Comparação: Streaming Clássico vs Streaming MCP
As diferenças entre como o streaming funciona de maneira "clássica" versus como funciona no MCP podem ser ilustradas assim:
| Característica | Streaming HTTP Clássico | Streaming MCP (Notificações) |
|---|---|---|
| Resposta principal | Em pedaços (chunked) | Única, ao final |
| Atualizações de progresso | Enviadas como pedaços de dados | Enviadas como notificações |
| Requisitos do cliente | Deve processar o stream | Deve implementar um handler de mensagens |
| Caso de uso | Arquivos grandes, streams de tokens AI | Progresso, logs, feedback em tempo real |
Diferenças Chave Observadas
Além disso, aqui estão algumas diferenças chaves:
-
Padrão de Comunicação:
- Streaming HTTP clássico: usa codificação de transferência chunked simples para enviar dados em pedaços.
- Streaming MCP: usa um sistema estruturado de notificações com protocolo JSON-RPC.
-
Formato da Mensagem:
- HTTP clássico: pedaços de texto simples com quebras de linha.
- MCP: objetos estruturados LoggingMessageNotification com metadados.
-
Implementação do Cliente:
- HTTP clássico: cliente simples que processa respostas de streaming.
- MCP: cliente mais sofisticado com handler de mensagens para processar diferentes tipos.
-
Atualizações de Progresso:
- HTTP clássico: o progresso é parte do fluxo principal de resposta.
- MCP: progresso é enviado via mensagens de notificação separadas enquanto a resposta principal vem ao final.
Recomendações
Algumas recomendações quanto à escolha entre implementar streaming clássico (como o endpoint que mostramos acima usando /stream) versus escolher streaming via MCP:
-
Para necessidades simples de streaming: Streaming HTTP clássico é mais simples de implementar e suficiente para necessidades básicas.
-
Para aplicações complexas e interativas: Streaming MCP oferece uma abordagem mais estruturada com metadados mais ricos e separação entre notificações e resultados finais.
-
Para aplicações AI: O sistema de notificações do MCP é particularmente útil para tarefas AI de longa duração onde você quer manter usuários informados sobre o progresso.
Streaming no MCP
Ok, você já viu algumas recomendações e comparações até aqui sobre a diferença entre streaming clássico e streaming no MCP. Vamos agora detalhar exatamente como você pode aproveitar o streaming no MCP.
Entender como o streaming funciona dentro do framework MCP é essencial para construir aplicações responsivas que forneçam feedback em tempo real para os usuários durante operações longas.
No MCP, streaming não é sobre enviar a resposta principal em pedaços, mas enviar notificações para o cliente enquanto uma ferramenta processa uma requisição. Essas notificações podem incluir atualizações de progresso, logs ou outros eventos.
Como funciona
O resultado principal ainda é enviado como uma única resposta. Entretanto, notificações podem ser enviadas como mensagens separadas durante o processamento e assim atualizar o cliente em tempo real. O cliente deve ser capaz de manipular e exibir essas notificações.
O que é uma Notificação?
Dissemos "Notificação", o que isso significa no contexto do MCP?
Uma notificação é uma mensagem enviada do servidor para o cliente para informar sobre progresso, status ou outros eventos durante uma operação longa. Notificações melhoram transparência e experiência do usuário.
Por exemplo, espera-se que o cliente envie uma notificação assim que o handshake inicial com o servidor for concluído.
Uma notificação tem a seguinte aparência em JSON:
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}
Notificações pertencem a um tópico no MCP referido como "Logging".
Para que o logging funcione, o servidor precisa habilitá-lo como uma funcionalidade/capacidade assim:
{
"capabilities": {
"logging": {}
}
}
Note
Dependendo do SDK usado, o logging pode estar habilitado por padrão, ou você pode precisar ativá-lo explicitamente na configuração do seu servidor.
Existem diferentes tipos de notificações:
| Nível | Descrição | Exemplo de Caso de Uso |
|---|---|---|
| debug | Informações detalhadas de depuração | Pontos de entrada/saída de funções |
| info | Mensagens informativas gerais | Atualizações de progresso de operação |
| notice | Eventos normais mas significativos | Mudanças de configuração |
| warning | Condições de aviso | Uso de funcionalidade obsoleta |
| error | Condições de erro | Falhas em operações |
| critical | Condições críticas | Falhas de componentes do sistema |
| alert | Ação deve ser tomada imediatamente | Detecção de corrupção de dados |
| emergency | Sistema está inutilizável | Falha completa do sistema |
Implementando Notificações no MCP
Para implementar notificações no MCP, você precisa configurar tanto o lado do servidor quanto o do cliente para manipular atualizações em tempo real. Isso permite que sua aplicação forneça feedback imediato aos usuários durante operações longas.
Lado Servidor: Enviando Notificações
Vamos começar com o lado servidor. No MCP, você define ferramentas que podem enviar notificações enquanto processam requisições. O servidor usa o objeto de contexto (geralmente ctx) para enviar mensagens para o cliente.
Python
@mcp.tool(description="A tool that sends progress notifications")
async def process_files(message: str, ctx: Context) -> TextContent:
await ctx.info("Processing file 1/3...")
await ctx.info("Processing file 2/3...")
await ctx.info("Processing file 3/3...")
return TextContent(type="text", text=f"Done: {message}")
No exemplo acima, a ferramenta process_files envia três notificações para o cliente conforme processa cada arquivo. O método ctx.info() é usado para enviar mensagens informativas.
Além disso, para habilitar notificações, certifique-se que seu servidor está usando um transporte de streaming (como streamable-http) e que seu cliente implementa um handler de mensagens para processar notificações. Veja como configurar o servidor para usar o transporte streamable-http:
mcp.run(transport="streamable-http")
.NET
[Tool("A tool that sends progress notifications")]
public async Task<TextContent> ProcessFiles(string message, ToolContext ctx)
{
await ctx.Info("Processing file 1/3...");
await ctx.Info("Processing file 2/3...");
await ctx.Info("Processing file 3/3...");
return new TextContent
{
Type = "text",
Text = $"Done: {message}"
};
}
Neste exemplo .NET, a ferramenta ProcessFiles está decorada com o atributo Tool e envia três notificações para o cliente enquanto processa cada arquivo. O método ctx.Info() é usado para enviar mensagens informativas.
Para habilitar notificações no seu servidor MCP .NET, assegure-se de usar um transporte de streaming:
var builder = McpBuilder.Create();
await builder
.UseStreamableHttp() // Enable streamable HTTP transport
.Build()
.RunAsync();
Lado Cliente: Recebendo Notificações
O cliente deve implementar um handler de mensagens para processar e exibir notificações à medida que chegam.
Python
async def message_handler(message):
if isinstance(message, types.ServerNotification):
print("NOTIFICATION:", message)
else:
print("SERVER MESSAGE:", message)
async with ClientSession(
read_stream,
write_stream,
logging_callback=logging_collector,
message_handler=message_handler,
) as session:
No código acima, a função message_handler verifica se a mensagem entrante é uma notificação. Se for, ela imprime a notificação; caso contrário, processa como uma mensagem regular do servidor. Note também como o ClientSession é inicializado com o message_handler para lidar com notificações recebidas.
.NET
// Define a message handler
void MessageHandler(IJsonRpcMessage message)
{
if (message is ServerNotification notification)
{
Console.WriteLine($"NOTIFICATION: {notification}");
}
else
{
Console.WriteLine($"SERVER MESSAGE: {message}");
}
}
// Create and use a client session with the message handler
var clientOptions = new ClientSessionOptions
{
MessageHandler = MessageHandler,
LoggingCallback = (level, message) => Console.WriteLine($"[{level}] {message}")
};
using var client = new ClientSession(readStream, writeStream, clientOptions);
await client.InitializeAsync();
// Now the client will process notifications through the MessageHandler
Neste exemplo .NET, a função MessageHandler verifica se a mensagem entrante é uma notificação. Se for, ela imprime a notificação; caso contrário, processa como mensagem regular do servidor. O ClientSession é inicializado com o handler de mensagens via ClientSessionOptions.
Para habilitar notificações, assegure que seu servidor usa um transporte de streaming (como streamable-http) e seu cliente implementa um handler de mensagens para processar notificações.
Notificações de Progresso & Cenários
Esta seção explica o conceito de notificações de progresso no MCP, por que são importantes e como implementá-las usando Streamable HTTP. Você também encontrará um exercício prático para reforçar seu entendimento.
Notificações de progresso são mensagens em tempo real enviadas do servidor para o cliente durante operações longas. Ao invés de esperar o processo completo terminar, o servidor mantém o cliente atualizado sobre o status atual. Isso melhora transparência, experiência do usuário e facilita a depuração.
Exemplo:
"Processing document 1/10"
"Processing document 2/10"
...
"Processing complete!"
Por que usar notificações de progresso?
Notificações de progresso são essenciais por vários motivos:
- Melhor experiência do usuário: Usuários veem atualizações conforme o trabalho progride, e não somente ao final.
- Feedback em tempo real: Clientes podem mostrar barras de progresso ou logs, deixando o app mais responsivo.
- Depuração e monitoramento mais fáceis: Desenvolvedores e usuários podem ver onde um processo está lento ou travado.
Como implementar notificações de progresso
Veja como implementar notificações de progresso no MCP:
- No servidor: Use
ctx.info()ouctx.log()para enviar notificações à medida que cada item é processado. Isso envia uma mensagem ao cliente antes do resultado principal estar pronto. - No cliente: Implemente um handler de mensagens que escute e exiba notificações conforme elas chegam. Esse handler distingue entre notificações e resultado final.
Exemplo Servidor:
Python
@mcp.tool(description="A tool that sends progress notifications")
async def process_files(message: str, ctx: Context) -> TextContent:
for i in range(1, 11):
await ctx.info(f"Processing document {i}/10")
await ctx.info("Processing complete!")
return TextContent(type="text", text=f"Done: {message}")
Exemplo Cliente:
Python
async def message_handler(message):
if isinstance(message, types.ServerNotification):
print("NOTIFICATION:", message)
else:
print("SERVER MESSAGE:", message)
Considerações de Segurança
Ao implementar servidores MCP com transportes baseados em HTTP, a segurança torna-se uma preocupação primordial que requer atenção cuidadosa a múltiplos vetores de ataque e mecanismos de proteção.
Visão Geral
A segurança é crítica ao expor servidores MCP via HTTP. Streamable HTTP introduz novas superfícies de ataque e requer configuração cuidadosa.
Pontos-Chave
- Validação do Cabeçalho Origin: Sempre valide o cabeçalho
Originpara prevenir ataques de DNS rebinding. - Vinculação a Localhost: Para desenvolvimento local, vincule servidores a
localhostpara evitar exposição à internet pública. - Autenticação: Implemente autenticação (ex: chaves API, OAuth) para ambientes de produção.
- CORS: Configure políticas de Cross-Origin Resource Sharing para restringir acesso.
- HTTPS: Utilize HTTPS em produção para criptografar o tráfego.
Melhores Práticas
- Nunca confie em requisições recebidas sem validação.
- Registre e monitore todos acessos e erros.
- Atualize dependências regularmente para corrigir vulnerabilidades de segurança.
Desafios
- Equilibrando segurança com facilidade de desenvolvimento
- Garantindo compatibilidade com vários ambientes de cliente
Atualizando de SSE para Streamable HTTP
Para aplicações que atualmente usam Server-Sent Events (SSE), migrar para Streamable HTTP oferece capacidades aprimoradas e melhor sustentabilidade a longo prazo para suas implementações MCP.
Por que atualizar?
Há duas razões convincentes para atualizar de SSE para Streamable HTTP:
- Streamable HTTP oferece melhor escalabilidade, compatibilidade e suporte a notificações mais ricos do que SSE.
- É o transporte recomendado para novas aplicações MCP.
Passos para migração
Aqui está como você pode migrar de SSE para Streamable HTTP em suas aplicações MCP:
- Atualize o código do servidor para usar
transport="streamable-http"emmcp.run(). - Atualize o código do cliente para usar
streamablehttp_clientem vez do cliente SSE. - Implemente um handler de mensagens no cliente para processar notificações.
- Teste a compatibilidade com ferramentas e fluxos de trabalho existentes.
Mantendo compatibilidade
É recomendado manter compatibilidade com clientes SSE existentes durante o processo de migração. Aqui estão algumas estratégias:
- Você pode suportar ambos SSE e Streamable HTTP executando ambos os transportes em endpoints diferentes.
- Migre os clientes gradualmente para o novo transporte.
Desafios
Certifique-se de tratar os seguintes desafios durante a migração:
- Garantir que todos os clientes sejam atualizados
- Lidar com diferenças na entrega das notificações
Considerações de segurança
A segurança deve ser prioridade máxima ao implementar qualquer servidor, especialmente ao usar transportes baseados em HTTP como Streamable HTTP no MCP.
Ao implementar servidores MCP com transportes baseados em HTTP, a segurança torna-se uma preocupação primordial que exige atenção cuidadosa a múltiplos vetores de ataque e mecanismos de proteção.
Visão geral
A segurança é crítica quando expõe servidores MCP via HTTP. Streamable HTTP introduz novas superfícies de ataque e requer configuração cuidadosa.
Aqui estão algumas considerações-chave de segurança:
- Validação do cabeçalho Origin: Sempre valide o cabeçalho
Originpara evitar ataques de DNS rebinding. - Binding localhost: Para desenvolvimento local, faça o binding dos servidores ao
localhostpara evitar exposição à internet pública. - Autenticação: Implemente autenticação (ex.: chaves API, OAuth) para implantações em produção.
- CORS: Configure políticas de Cross-Origin Resource Sharing (CORS) para restringir acesso.
- HTTPS: Use HTTPS em produção para criptografar o tráfego.
Melhores práticas
Além disso, aqui estão algumas melhores práticas para seguir ao implementar segurança no seu servidor de streaming MCP:
- Nunca confie em requisições recebidas sem validação.
- Registre e monitore todos os acessos e erros.
- Atualize as dependências regularmente para corrigir vulnerabilidades de segurança.
Desafios
Você enfrentará alguns desafios ao implementar segurança em servidores de streaming MCP:
- Equilibrar segurança com facilidade de desenvolvimento
- Garantir compatibilidade com vários ambientes de cliente
Exercício: Crie sua própria aplicação MCP de streaming
Cenário: Construa um servidor e cliente MCP onde o servidor processa uma lista de itens (ex.: arquivos ou documentos) e envia uma notificação para cada item processado. O cliente deve exibir cada notificação assim que ela chegar.
Passos:
- Implemente uma ferramenta de servidor que processe uma lista e envie notificações para cada item.
- Implemente um cliente com um handler de mensagens para exibir notificações em tempo real.
- Teste sua implementação executando ambos servidor e cliente, e observe as notificações.
Leitura adicional e próximos passos
Para continuar sua jornada com streaming MCP e expandir seu conhecimento, esta seção fornece recursos adicionais e passos sugeridos para construir aplicações mais avançadas.
Leitura adicional
- Microsoft: Introduction to HTTP Streaming
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS in ASP.NET Core
- Python requests: Streaming Requests
Próximos passos
- Experimente construir ferramentas MCP mais avançadas que usem streaming para análises em tempo real, chat ou edição colaborativa.
- Explore integrar streaming MCP com frameworks frontend (React, Vue, etc.) para atualizações ao vivo da UI.
- Próximo: Utilising AI Toolkit for VSCode
Aviso Legal: Este documento foi traduzido usando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos pela precisão, por favor, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.