Dit hoofdstuk biedt een uitgebreide gids voor het implementeren van veilige, schaalbare en realtime streaming met het Model Context Protocol (MCP) via HTTPS. Het behandelt de motivatie achter streaming, de beschikbare transportmechanismen, hoe je streamable HTTP in MCP implementeert, beveiligingsrichtlijnen, migratie van SSE en praktische tips voor het bouwen van je eigen streaming MCP-applicaties.
Deze sectie onderzoekt de verschillende transportmechanismen die beschikbaar zijn in MCP en hun rol bij het mogelijk maken van streamingfunctionaliteiten voor realtime communicatie tussen clients en servers.
Een transportmechanisme bepaalt hoe data wordt uitgewisseld tussen client en server. MCP ondersteunt meerdere transporttypes die passen bij verschillende omgevingen en eisen:
- stdio: Standaard input/output, geschikt voor lokale en CLI-gebaseerde tools. Simpel maar niet geschikt voor web of cloud.
- SSE (Server-Sent Events): Hiermee kunnen servers realtime updates naar clients pushen via HTTP. Goed voor web-UI’s, maar beperkt in schaalbaarheid en flexibiliteit.
- Streamable HTTP: Modern, HTTP-gebaseerd streamingtransport, ondersteunt notificaties en betere schaalbaarheid. Aanbevolen voor de meeste productie- en cloudscenario’s.
Bekijk de onderstaande vergelijkingstabel om de verschillen tussen deze transportmechanismen te begrijpen:
| Transport | Realtime Updates | Streaming | Schaalbaarheid | Gebruikssituatie |
|---|---|---|---|---|
| stdio | Nee | Nee | Laag | Lokale CLI-tools |
| SSE | Ja | Ja | Gemiddeld | Web, realtime updates |
| Streamable HTTP | Ja | Ja | Hoog | Cloud, multi-client |
Tip: De keuze van het juiste transport beïnvloedt prestaties, schaalbaarheid en gebruikerservaring. Streamable HTTP wordt aanbevolen voor moderne, schaalbare en cloudklare applicaties.
Let op de transports stdio en SSE die in eerdere hoofdstukken zijn besproken en dat streamable HTTP het transport is dat in dit hoofdstuk wordt behandeld.
Het begrijpen van de basisconcepten en motivaties achter streaming is essentieel voor het implementeren van effectieve realtime communicatiesystemen.
Streaming is een techniek in netwerkprogrammering waarbij data in kleine, beheersbare stukken of als een reeks gebeurtenissen wordt verzonden en ontvangen, in plaats van te wachten tot een volledige respons klaar is. Dit is vooral nuttig voor:
- Grote bestanden of datasets.
- Realtime updates (bijv. chat, voortgangsbalken).
- Langdurige berekeningen waarbij je de gebruiker op de hoogte wilt houden.
Dit is wat je op hoofdlijnen moet weten over streaming:
- Data wordt geleidelijk geleverd, niet in één keer.
- De client kan data verwerken zodra deze binnenkomt.
- Vermindert de waargenomen latency en verbetert de gebruikerservaring.
De redenen om streaming te gebruiken zijn:
- Gebruikers krijgen direct feedback, niet alleen aan het einde.
- Maakt realtime applicaties en responsieve UI’s mogelijk.
- Efficiënter gebruik van netwerk- en rekencapaciteit.
Hier is een eenvoudig voorbeeld van hoe streaming geïmplementeerd kan worden:
Python
Server (Python, met FastAPI en StreamingResponse):
Python
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")Client (Python, met requests):
Python
import requests
with requests.get("http://localhost:8000/stream", stream=True) as r:
for line in r.iter_lines():
if line:
print(line.decode())Dit voorbeeld laat zien hoe een server een reeks berichten naar de client stuurt zodra ze beschikbaar zijn, in plaats van te wachten tot alle berichten klaar zijn.
Hoe werkt het:
- De server levert elk bericht zodra het gereed is.
- De client ontvangt en print elk deel zodra het binnenkomt.
Vereisten:
- De server moet een streaming response gebruiken (bijv.
StreamingResponsein FastAPI). - The client must process the response as a stream (
stream=Truein requests). - Content-Type is usually
text/event-streamorapplication/octet-stream.
Java
Server (Java, met Spring Boot en 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));
}
}Client (Java, met 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();
}
}Notities bij Java-implementatie:
- Maakt gebruik van Spring Boot’s reactieve stack met
Fluxfor streaming ServerSentEventprovides structured event streaming with event typesWebClientwithbodyToFlux()enables reactive streaming consumptiondelayElements()simulates processing time between events- Events can have types (
info,result) for better client handling
The differences between how streaming works in a "classical" manner versus how it works in MCP can be depicted like so:
| Feature | Classic HTTP Streaming | MCP Streaming (Notifications) |
|---|---|---|
| Main response | Chunked | Single, at end |
| Progress updates | Sent as data chunks | Sent as notifications |
| Client requirements | Must process stream | Must implement message handler |
| Use case | Large files, AI token streams | Progress, logs, real-time feedback |
Additionally, here are some key differences:
-
Communication Pattern:
- Classic HTTP streaming: Uses simple chunked transfer encoding to send data in chunks
- MCP streaming: Uses a structured notification system with JSON-RPC protocol
-
Message Format:
- Classic HTTP: Plain text chunks with newlines
- MCP: Structured LoggingMessageNotification objects with metadata
-
Client Implementation:
- Classic HTTP: Simple client that processes streaming responses
- MCP: More sophisticated client with a message handler to process different types of messages
-
Progress Updates:
- Classic HTTP: The progress is part of the main response stream
- MCP: Progress is sent via separate notification messages while the main response comes at the end
There are some things we recommend when it comes to choosing between implementing classical streaming (as an endpoint we showed you above using /stream) versus streaming via MCP.
-
Voor eenvoudige streamingbehoeften: Klassieke HTTP streaming is eenvoudiger te implementeren en voldoende voor basis streaming.
-
Voor complexe, interactieve applicaties: MCP streaming biedt een meer gestructureerde aanpak met rijkere metadata en scheiding tussen notificaties en eindresultaten.
-
Voor AI-toepassingen: Het notificatiesysteem van MCP is vooral handig voor langdurige AI-taken waarbij je gebruikers op de hoogte wilt houden van de voortgang.
Je hebt nu enkele aanbevelingen en vergelijkingen gezien over het verschil tussen klassieke streaming en streaming in MCP. Laten we nu in detail bekijken hoe je streaming in MCP kunt gebruiken.
Begrijpen hoe streaming binnen het MCP-framework werkt is essentieel voor het bouwen van responsieve applicaties die realtime feedback geven aan gebruikers tijdens langdurige bewerkingen.
In MCP gaat streaming niet om het verzenden van de hoofdrespons in stukken, maar om het sturen van notificaties naar de client terwijl een tool een verzoek verwerkt. Deze notificaties kunnen voortgangsupdates, logs of andere gebeurtenissen bevatten.
Het hoofdresultaat wordt nog steeds als één enkele respons gestuurd. Notificaties kunnen echter als aparte berichten worden verzonden tijdens de verwerking, waardoor de client realtime wordt bijgewerkt. De client moet in staat zijn deze notificaties te verwerken en weer te geven.
We zeiden “Notificatie”, wat betekent dat precies binnen MCP?
Een notificatie is een bericht dat de server naar de client stuurt om te informeren over voortgang, status of andere gebeurtenissen tijdens een langdurige operatie. Notificaties verhogen de transparantie en verbeteren de gebruikerservaring.
Bijvoorbeeld, een client moet een notificatie sturen zodra de eerste handshake met de server is gemaakt.
Een notificatie ziet er als volgt uit als JSON-bericht:
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}Notificaties behoren tot een topic in MCP dat "Logging" wordt genoemd.
Om logging te laten werken, moet de server het inschakelen als feature/capability zoals hieronder:
{
"capabilities": {
"logging": {}
}
}Note
Afhankelijk van de gebruikte SDK kan logging standaard ingeschakeld zijn, of moet je het expliciet aanzetten in je serverconfiguratie.
Er zijn verschillende soorten notificaties:
| Niveau | Beschrijving | Voorbeeld Gebruikssituatie |
|---|---|---|
| debug | Gedetailleerde debug-informatie | Functie-in- en uitgangspunten |
| info | Algemene informatieve berichten | Voortgangsupdates |
| notice | Normale maar belangrijke gebeurtenissen | Configuratiewijzigingen |
| warning | Waarschuwingen | Gebruik van verouderde functies |
| error | Foutcondities | Foutmeldingen bij bewerkingen |
| critical | Kritieke condities | Fouten in systeemcomponenten |
| alert | Directe actie vereist | Geconstateerde datacorruptie |
| emergency | Systeem onbruikbaar | Volledige systeemuitval |
Om notificaties in MCP te implementeren, moet je zowel de server- als clientzijde instellen om realtime updates te verwerken. Zo kan je applicatie directe feedback geven aan gebruikers tijdens langdurige bewerkingen.
Laten we beginnen bij de serverkant. In MCP definieer je tools die notificaties kunnen versturen tijdens het verwerken van verzoeken. De server gebruikt het contextobject (meestal ctx) om berichten naar de client te sturen.
Python
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}")In het voorgaande voorbeeld wordt process_files tool sends three notifications to the client as it processes each file. The ctx.info() method is used to send informational messages.
Additionally, to enable notifications, ensure your server uses a streaming transport (like streamable-http) and your client implements a message handler to process notifications. Here's how you can set up the server to use the streamable-http transport gebruikt:
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}"
};
}In dit .NET-voorbeeld wordt de ProcessFiles tool is decorated with the Tool attribute and sends three notifications to the client as it processes each file. The ctx.Info() methode gebruikt om informatieve berichten te verzenden.
Zorg ervoor dat je voor notificaties in je .NET MCP-server een streaming transport gebruikt:
var builder = McpBuilder.Create();
await builder
.UseStreamableHttp() // Enable streamable HTTP transport
.Build()
.RunAsync();De client moet een message handler implementeren om notificaties te verwerken en weer te geven zodra ze binnenkomen.
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:In bovenstaande code wordt message_handler function checks if the incoming message is a notification. If it is, it prints the notification; otherwise, it processes it as a regular server message. Also note how the ClientSession is initialized with the message_handler gebruikt om binnenkomende notificaties af te handelen.
.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 MessageHandlerIn dit .NET-voorbeeld wordt MessageHandler function checks if the incoming message is a notification. If it is, it prints the notification; otherwise, it processes it as a regular server message. The ClientSession is initialized with the message handler via the ClientSessionOptions.
To enable notifications, ensure your server uses a streaming transport (like streamable-http gebruikt en implementeert de client een message handler om notificaties te verwerken.
Deze sectie legt het concept voortgangsnotificaties in MCP uit, waarom ze belangrijk zijn en hoe je ze implementeert met Streamable HTTP. Ook vind je een praktische opdracht om je begrip te versterken.
Voortgangsnotificaties zijn realtime berichten die de server naar de client stuurt tijdens langdurige bewerkingen. In plaats van te wachten tot het hele proces klaar is, houdt de server de client op de hoogte van de huidige status. Dit verhoogt transparantie, verbetert de gebruikerservaring en maakt debugging makkelijker.
Voorbeeld:
"Processing document 1/10"
"Processing document 2/10"
...
"Processing complete!"
Voortgangsnotificaties zijn om meerdere redenen belangrijk:
- Betere gebruikerservaring: Gebruikers zien updates tijdens het werk, niet alleen aan het einde.
- Realtime feedback: Clients kunnen voortgangsbalken of logs tonen, waardoor de app responsief aanvoelt.
- Makkelijker debuggen en monitoren: Ontwikkelaars en gebruikers zien waar een proces traag is of vastloopt.
Zo implementeer je voortgangsnotificaties in MCP:
- Aan de serverkant: Gebruik
ctx.info()orctx.log()om notificaties te sturen zodra een item verwerkt is. Dit verstuurt een bericht naar de client vóór het hoofdresultaat klaar is. - Aan de clientkant: Implementeer een message handler die luistert naar en notificaties toont zodra ze binnenkomen. Deze handler maakt onderscheid tussen notificaties en het eindresultaat.
Servervoorbeeld:
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}")Clientvoorbeeld:
Python
async def message_handler(message):
if isinstance(message, types.ServerNotification):
print("NOTIFICATION:", message)
else:
print("SERVER MESSAGE:", message)Bij het implementeren van MCP-servers met HTTP-gebaseerde transports is beveiliging een topprioriteit die aandacht vereist voor verschillende aanvalsvectoren en beschermingsmechanismen.
Beveiliging is cruciaal bij het blootstellen van MCP-servers via HTTP. Streamable HTTP introduceert nieuwe aanvalsvlakken en vereist zorgvuldige configuratie.
- Validatie van de Origin Header: Valideer altijd de
Originheader om te voorkomen dat ongeautoriseerde bronnen verbinding maken. - Gebruik HTTPS: Zorg dat alle communicatie via HTTPS verloopt om afluisteren en manipulatie te voorkomen.
- Authenticatie en Autorisatie: Implementeer geschikte authenticatie- en autorisatiemechanismen om toegang te beperken.
- Rate Limiting: Beperk het aantal verzoeken om misbruik en DoS-aanvallen te voorkomen.
- Inputvalidatie: Controleer en valideer alle binnenkomende data om injectie-aanvallen te vermijden.
Het is aan te raden om tijdens de migratie compatibiliteit met bestaande SSE-clients te behouden. Enkele strategieën:
- Ondersteun zowel SSE als Streamable HTTP door beide transports op verschillende endpoints te draaien.
- Migreer clients geleidelijk naar het nieuwe transport.
Houd rekening met de volgende uitdagingen tijdens migratie:
- Zorgen dat alle clients worden bijgewerkt.
- Omgaan met verschillen in notificatieaflevering.
Scenario: Bouw een MCP-server en client waarbij de server een lijst met items (bijv. bestanden of documenten) verwerkt en voor elk verwerkt item een notificatie stuurt. De client toont elke notificatie zodra deze binnenkomt.
Stappen:
- Implementeer een servertool die een lijst verwerkt en notificaties verstuurt voor elk item.
- Implementeer een client met een message handler die notificaties realtime toont.
- Test je implementatie door zowel server als client te draaien en observeer de notificaties.
Om je reis met MCP-streaming voort te zetten en je kennis uit te breiden, biedt deze sectie extra bronnen en suggesties voor de volgende stappen bij het bouwen van meer geavanceerde applicaties.
- Microsoft: Introduction to HTTP Streaming
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS in ASP.NET Core
- Python requests: Streaming Requests
- Probeer meer geavanceerde MCP-tools te bouwen die streaming gebruiken voor realtime analytics, chat of collaboratieve bewerking.
- Verken het integreren van MCP-streaming met frontend-frameworks (React, Vue, etc.) voor live UI-updates.
- Volgende: Utilising AI Toolkit for VSCode
Disclaimer:
Dit document is vertaald met behulp van de AI-vertalingsservice Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u er rekening mee te houden dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het oorspronkelijke document in de oorspronkelijke taal moet als de gezaghebbende bron worden beschouwd. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor eventuele misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.