Ten rozdział oferuje kompleksowy przewodnik po implementacji bezpiecznego, skalowalnego i w czasie rzeczywistym przesyłania strumieniowego z użyciem protokołu Model Context Protocol (MCP) za pomocą HTTPS. Omawia motywację do przesyłania strumieniowego, dostępne mechanizmy transportowe, sposób implementacji przesyłania strumieniowego HTTP w MCP, najlepsze praktyki dotyczące bezpieczeństwa, migrację z SSE oraz praktyczne wskazówki dotyczące budowy własnych aplikacji MCP do przesyłania strumieniowego.
Ta sekcja bada różne mechanizmy transportowe dostępne w MCP oraz ich rolę w umożliwianiu przesyłania strumieniowego dla komunikacji w czasie rzeczywistym między klientami a serwerami.
Mechanizm transportowy definiuje sposób wymiany danych między klientem a serwerem. MCP obsługuje wiele typów transportu, aby dostosować się do różnych środowisk i wymagań:
- stdio: Standardowe wejście/wyjście, odpowiednie dla lokalnych narzędzi CLI. Proste, ale nieodpowiednie dla aplikacji webowych czy chmurowych.
- SSE (Server-Sent Events): Pozwala serwerom na przesyłanie aktualizacji w czasie rzeczywistym do klientów za pomocą HTTP. Dobre dla interfejsów webowych, ale ograniczone pod względem skalowalności i elastyczności.
- Streamable HTTP: Nowoczesny transport oparty na HTTP, obsługujący powiadomienia i lepszą skalowalność. Zalecany dla większości scenariuszy produkcyjnych i chmurowych.
Zapoznaj się z poniższą tabelą porównawczą, aby zrozumieć różnice między tymi mechanizmami transportowymi:
| Transport | Aktualizacje w czasie rzeczywistym | Przesyłanie strumieniowe | Skalowalność | Zastosowanie |
|---|---|---|---|---|
| stdio | Nie | Nie | Niska | Lokalnie, narzędzia CLI |
| SSE | Tak | Tak | Średnia | Web, aktualizacje w czasie rzeczywistym |
| Streamable HTTP | Tak | Tak | Wysoka | Chmura, wieloklientowe |
Tip: Wybór odpowiedniego transportu wpływa na wydajność, skalowalność i doświadczenie użytkownika. Streamable HTTP jest zalecany dla nowoczesnych, skalowalnych aplikacji gotowych na chmurę.
Zwróć uwagę na transporty stdio i SSE, które zostały omówione w poprzednich rozdziałach, oraz na to, że streamable HTTP jest transportem omawianym w tym rozdziale.
Zrozumienie podstawowych koncepcji i motywacji stojących za przesyłaniem strumieniowym jest kluczowe dla implementacji skutecznych systemów komunikacji w czasie rzeczywistym.
Przesyłanie strumieniowe to technika w programowaniu sieciowym, która pozwala na przesyłanie i odbieranie danych w małych, łatwych do zarządzania fragmentach lub jako sekwencja zdarzeń, zamiast czekać na pełną odpowiedź. Jest to szczególnie przydatne w przypadku:
- Dużych plików lub zestawów danych.
- Aktualizacji w czasie rzeczywistym (np. czat, paski postępu).
- Długotrwałych obliczeń, gdzie chcesz informować użytkownika na bieżąco.
Oto, co warto wiedzieć o przesyłaniu strumieniowym na wysokim poziomie:
- Dane są dostarczane stopniowo, a nie wszystkie naraz.
- Klient może przetwarzać dane w miarę ich przybywania.
- Zmniejsza postrzeganą latencję i poprawia doświadczenie użytkownika.
Powody, dla których warto korzystać z przesyłania strumieniowego, są następujące:
- Użytkownicy otrzymują informacje zwrotne natychmiast, a nie dopiero na końcu.
- Umożliwia aplikacje w czasie rzeczywistym i responsywne interfejsy użytkownika.
- Bardziej efektywne wykorzystanie zasobów sieciowych i obliczeniowych.
Oto prosty przykład, jak można zaimplementować przesyłanie strumieniowe:
Serwer (Python, używając FastAPI i 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")Klient (Python, używając 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())Ten przykład pokazuje serwer wysyłający serię wiadomości do klienta w miarę ich dostępności, zamiast czekać na gotowość wszystkich wiadomości.
Jak to działa:
- Serwer generuje każdą wiadomość w miarę jej gotowości.
- Klient odbiera i drukuje każdy fragment w miarę jego przybywania.
Wymagania:
- Serwer musi używać odpowiedzi strumieniowej (np.
StreamingResponsew FastAPI). - Klient musi przetwarzać odpowiedź jako strumień (
stream=Truew requests). - Content-Type zazwyczaj to
text/event-streamlubapplication/octet-stream.
Serwer (Java, używając Spring Boot i 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));
}
}Klient (Java, używając 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();
}
}Uwagi dotyczące implementacji w Javie:
- Używa reaktywnego stosu Spring Boot z
Fluxdo przesyłania strumieniowego. ServerSentEventzapewnia strukturalne przesyłanie zdarzeń z typami zdarzeń.WebClientzbodyToFlux()umożliwia reaktywne odbieranie strumieniowe.delayElements()symuluje czas przetwarzania między zdarzeniami.- Zdarzenia mogą mieć typy (
info,result) dla lepszej obsługi po stronie klienta.
Różnice między klasycznym przesyłaniem strumieniowym a przesyłaniem strumieniowym w MCP można przedstawić w następujący sposób:
| Funkcja | Klasyczne przesyłanie HTTP | MCP Streaming (Powiadomienia) |
|---|---|---|
| Główna odpowiedź | Fragmentowana | Jedna, na końcu |
| Aktualizacje postępu | Wysyłane jako fragmenty danych | Wysyłane jako powiadomienia |
| Wymagania klienta | Musi przetwarzać strumień | Musi implementować obsługę wiadomości |
| Zastosowanie | Duże pliki, strumienie tokenów AI | Postęp, logi, informacje zwrotne w czasie rzeczywistym |
Dodatkowo, oto kilka kluczowych różnic:
-
Wzorzec komunikacji:
- Klasyczne przesyłanie HTTP: Używa prostego kodowania transferu fragmentowanego do wysyłania danych w fragmentach.
- MCP Streaming: Używa strukturalnego systemu powiadomień z protokołem JSON-RPC.
-
Format wiadomości:
- Klasyczne HTTP: Fragmenty tekstu z nowymi liniami.
- MCP: Strukturalne obiekty LoggingMessageNotification z metadanymi.
-
Implementacja klienta:
- Klasyczne HTTP: Prosty klient przetwarzający odpowiedzi strumieniowe.
- MCP: Bardziej zaawansowany klient z obsługą wiadomości do przetwarzania różnych typów wiadomości.
-
Aktualizacje postępu:
- Klasyczne HTTP: Postęp jest częścią głównego strumienia odpowiedzi.
- MCP: Postęp jest wysyłany za pomocą oddzielnych wiadomości powiadomień, podczas gdy główna odpowiedź przychodzi na końcu.
Oto kilka zaleceń dotyczących wyboru między implementacją klasycznego przesyłania strumieniowego (jako punkt końcowy pokazany powyżej używający /stream) a wyborem przesyłania strumieniowego za pomocą MCP.
-
Dla prostych potrzeb przesyłania strumieniowego: Klasyczne przesyłanie HTTP jest prostsze w implementacji i wystarczające dla podstawowych potrzeb przesyłania strumieniowego.
-
Dla złożonych, interaktywnych aplikacji: MCP Streaming oferuje bardziej strukturalne podejście z bogatszymi metadanymi i rozdzieleniem między powiadomieniami a wynikami końcowymi.
-
Dla aplikacji AI: System powiadomień MCP jest szczególnie przydatny w przypadku długotrwałych zadań AI, gdzie chcesz informować użytkowników o postępie.
Ok, widziałeś już kilka zaleceń i porównań dotyczących różnic między klasycznym przesyłaniem strumieniowym a przesyłaniem strumieniowym w MCP. Przejdźmy do szczegółów, jak dokładnie możesz wykorzystać przesyłanie strumieniowe w MCP.
Zrozumienie, jak działa przesyłanie strumieniowe w ramach MCP, jest kluczowe dla budowy responsywnych aplikacji, które zapewniają użytkownikom informacje zwrotne w czasie rzeczywistym podczas długotrwałych operacji.
W MCP przesyłanie strumieniowe nie polega na wysyłaniu głównej odpowiedzi w fragmentach, ale na wysyłaniu powiadomień do klienta podczas przetwarzania żądania przez narzędzie. Te powiadomienia mogą zawierać aktualizacje postępu, logi lub inne zdarzenia.
Główny wynik nadal jest wysyłany jako pojedyncza odpowiedź. Jednak powiadomienia mogą być wysyłane jako oddzielne wiadomości podczas przetwarzania, aktualizując klienta w czasie rzeczywistym. Klient musi być w stanie obsługiwać i wyświetlać te powiadomienia.
Powiedzieliśmy "Powiadomienie", co to oznacza w kontekście MCP?
Powiadomienie to wiadomość wysyłana z serwera do klienta, informująca o postępie, statusie lub innych zdarzeniach podczas długotrwałej operacji. Powiadomienia poprawiają przejrzystość i doświadczenie użytkownika.
Na przykład klient powinien wysłać powiadomienie po nawiązaniu początkowego połączenia z serwerem.
Powiadomienie wygląda tak jako wiadomość JSON:
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}Powiadomienia należą do tematu w MCP określanego jako "Logging".
Aby logowanie działało, serwer musi włączyć je jako funkcję/możliwość w następujący sposób:
{
"capabilities": {
"logging": {}
}
}Note
W zależności od używanego SDK logowanie może być domyślnie włączone lub może być konieczne jego wyraźne włączenie w konfiguracji serwera.
Istnieją różne typy powiadomień:
| Poziom | Opis | Przykład zastosowania |
|---|---|---|
| debug | Szczegółowe informacje debugowania | Punkty wejścia/wyjścia funkcji |
| info | Ogólne wiadomości informacyjne | Aktualizacje postępu operacji |
| notice | Zwykłe, ale istotne zdarzenia | Zmiany konfiguracji |
| warning | Warunki ostrzegawcze | Użycie przestarzałej funkcji |
| error | Warunki błędów | Niepowodzenia operacji |
| critical | Krytyczne warunki | Awaria komponentu systemu |
| alert | Natychmiastowa akcja wymagana | Wykrycie uszkodzenia danych |
| emergency | System nie działa | Całkowita awaria systemu |
Aby zaimplementować powiadomienia w MCP, musisz skonfigurować zarówno stronę serwera, jak i klienta, aby obsługiwały aktualizacje w czasie rzeczywistym. Dzięki temu Twoja aplikacja będzie mogła zapewniać użytkownikom natychmiastowe informacje zwrotne podczas długotrwałych operacji.
Zacznijmy od strony serwera. W MCP definiujesz narzędzia, które mogą wysyłać powiadomienia podczas przetwarzania żądań. Serwer używa obiektu kontekstu (zwykle ctx) do wysyłania wiadomości do klienta.
@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}")W powyższym przykładzie narzędzie process_files wysyła trzy powiadomienia do klienta podczas przetwarzania każdego pliku. Metoda ctx.info() jest używana do wysyłania wiadomości informacyjnych.
Dodatkowo, aby włączyć powiadomienia, upewnij się, że Twój serwer używa transportu strumieniowego (takiego jak streamable-http), a Twój klient implementuje obsługę wiadomości do przetwarzania powiadomień. Oto jak możesz skonfigurować serwer do używania transportu streamable-http:
mcp.run(transport="streamable-http")[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}"
};
}W tym przykładzie .NET narzędzie ProcessFiles jest oznaczone atrybutem Tool i wysyła trzy powiadomienia do klienta podczas przetwarzania każdego pliku. Metoda ctx.Info() jest używana do wysyłania wiadomości informacyjnych.
Aby włączyć powiadomienia w serwerze MCP .NET, upewnij się, że używasz transportu strumieniowego:
var builder = McpBuilder.Create();
await builder
.UseStreamableHttp() // Enable streamable HTTP transport
.Build()
.RunAsync();Klient musi zaimplementować obsługę wiadomości, aby przetwarzać i wyświetlać powiadomienia w miarę ich przybywania.
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:W powyższym kodzie funkcja message_handler sprawdza, czy przychodząca wiadomość jest powiadomieniem. Jeśli tak, drukuje powiadomienie; w przeciwnym razie przetwarza je jako zwykłą wiadomość serwera. Zwróć uwagę, jak ClientSession jest inicjalizowany z message_handler, aby obsługiwać przychodzące powiadomienia.
// 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 MessageHandlerW tym przykładzie .NET funkcja MessageHandler sprawdza, czy przychodząca wiadomość jest powiadomieniem. Jeśli tak, drukuje powiadomienie; w przeciwnym razie przetwarza je jako zwykłą wiadomość serwera. ClientSession jest inicjalizowany z obsługą wiadomości za pomocą ClientSessionOptions.
Aby włączyć powiadomienia, upewnij się, że Twój serwer używa transportu strumieniowego (takiego jak streamable-http), a Twój klient implementuje obsługę wiadomości do przetwarzania powiadomień.
Ta sekcja wyjaśnia koncepcję powiadomień o postępie w MCP, dlaczego są ważne i jak je zaimplementować za pomocą Streamable HTTP. Znajdziesz tu również praktyczne zadanie, które pomoże Ci utrwalić wiedzę.
Powiadomienia o postępie to wiadomości w czasie rzeczywistym wysyłane z serwera do klienta podczas długotrwałych operacji. Zamiast czekać na zakończenie całego procesu, serwer informuje klienta o bieżącym statusie. Poprawia to przejrzystość, doświadczenie użytkownika i ułatwia debugowanie.
Przykład:
"Processing document 1/10"
"Processing document 2/10"
...
"Processing complete!"
Powiadomienia o postępie są niezbędne z kilku powodów:
- Lepsze doświadczenie użytkownika: Użytkownicy widzą aktualizacje w miarę postępu pracy, a nie dopiero na końcu.
- Informacje zwrotne w czasie rzeczywistym: Klienci mogą wyświetlać paski postępu lub logi, co sprawia, że aplikacja wydaje się responsywna.
- Łatwiejsze debugowanie i monitorowanie: Programiści i użytkownicy mogą zobaczyć, gdzie proces może być wolny lub zablokowany.
Oto jak możesz zaimplementować powiadomienia o postępie w MCP:
-
Po stronie serwera: Użyj
ctx.info()lubctx.log(), aby wysyłać powiadomienia w miarę przetwarzania każdego elementu. To wysyła wiadomość do klienta przed przygotowaniem głównego wyniku. -
Po stronie klienta: Zaimplementuj obsługę wiadomo Istnieją dwa przekonujące powody, aby przejść z SSE na Streamable HTTP:
-
Streamable HTTP oferuje lepszą skalowalność, kompatybilność i bogatsze wsparcie dla powiadomień niż SSE.
-
Jest to zalecany transport dla nowych aplikacji MCP.
Oto jak można przejść z SSE na Streamable HTTP w swoich aplikacjach MCP:
- Zaktualizuj kod serwera, aby używać
transport="streamable-http"wmcp.run(). - Zaktualizuj kod klienta, aby korzystać z
streamablehttp_clientzamiast klienta SSE. - Zaimplementuj obsługę wiadomości w kliencie, aby przetwarzać powiadomienia.
- Przetestuj kompatybilność z istniejącymi narzędziami i przepływami pracy.
Zaleca się utrzymanie kompatybilności z istniejącymi klientami SSE podczas procesu migracji. Oto kilka strategii:
- Możesz obsługiwać zarówno SSE, jak i Streamable HTTP, uruchamiając oba transporty na różnych punktach końcowych.
- Stopniowo migruj klientów na nowy transport.
Upewnij się, że rozwiązujesz następujące wyzwania podczas migracji:
- Aktualizacja wszystkich klientów
- Radzenie sobie z różnicami w dostarczaniu powiadomień
Bezpieczeństwo powinno być najwyższym priorytetem podczas implementacji dowolnego serwera, szczególnie przy użyciu transportów opartych na HTTP, takich jak Streamable HTTP w MCP.
Podczas implementacji serwerów MCP z transportami opartymi na HTTP, bezpieczeństwo staje się kluczowym zagadnieniem, które wymaga starannego uwzględnienia wielu wektorów ataku i mechanizmów ochrony.
Bezpieczeństwo jest kluczowe podczas udostępniania serwerów MCP przez HTTP. Streamable HTTP wprowadza nowe powierzchnie ataku i wymaga starannej konfiguracji.
Oto kluczowe kwestie dotyczące bezpieczeństwa:
- Walidacja nagłówka Origin: Zawsze weryfikuj nagłówek
Origin, aby zapobiec atakom typu DNS rebinding. - Powiązanie z localhost: Na potrzeby lokalnego rozwoju, powiąż serwery z
localhost, aby uniknąć ich wystawienia na publiczny internet. - Uwierzytelnianie: Wdroż uwierzytelnianie (np. klucze API, OAuth) w środowiskach produkcyjnych.
- CORS: Skonfiguruj zasady Cross-Origin Resource Sharing (CORS), aby ograniczyć dostęp.
- HTTPS: Używaj HTTPS w środowiskach produkcyjnych, aby szyfrować ruch.
Dodatkowo, oto kilka najlepszych praktyk dotyczących bezpieczeństwa w serwerach strumieniowych MCP:
- Nigdy nie ufaj przychodzącym żądaniom bez ich weryfikacji.
- Loguj i monitoruj wszystkie dostępy i błędy.
- Regularnie aktualizuj zależności, aby załatać luki w zabezpieczeniach.
Podczas wdrażania zabezpieczeń w serwerach strumieniowych MCP możesz napotkać następujące wyzwania:
- Równoważenie bezpieczeństwa z łatwością rozwoju
- Zapewnienie kompatybilności z różnymi środowiskami klientów
Scenariusz: Zbuduj serwer i klienta MCP, gdzie serwer przetwarza listę elementów (np. plików lub dokumentów) i wysyła powiadomienie dla każdego przetworzonego elementu. Klient powinien wyświetlać każde powiadomienie w czasie rzeczywistym.
Kroki:
- Zaimplementuj narzędzie serwera, które przetwarza listę i wysyła powiadomienia dla każdego elementu.
- Zaimplementuj klienta z obsługą wiadomości, aby wyświetlać powiadomienia w czasie rzeczywistym.
- Przetestuj swoją implementację, uruchamiając zarówno serwer, jak i klienta, i obserwuj powiadomienia.
Aby kontynuować swoją przygodę z MCP streamingiem i poszerzyć wiedzę, ta sekcja zawiera dodatkowe zasoby i sugerowane kolejne kroki w budowaniu bardziej zaawansowanych aplikacji.
- Microsoft: Wprowadzenie do HTTP Streaming
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS w ASP.NET Core
- Python requests: Streaming Requests
- Spróbuj zbudować bardziej zaawansowane narzędzia MCP, które wykorzystują streaming do analityki w czasie rzeczywistym, czatu lub wspólnej edycji.
- Zbadaj integrację MCP streaming z frameworkami frontendowymi (React, Vue itp.) dla aktualizacji interfejsu użytkownika na żywo.
- Następny krok: Wykorzystanie AI Toolkit dla VSCode
Zastrzeżenie:
Ten dokument został przetłumaczony za pomocą usługi tłumaczenia AI Co-op Translator. Chociaż dokładamy wszelkich starań, aby tłumaczenie było precyzyjne, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za autorytatywne źródło. W przypadku informacji o kluczowym znaczeniu zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.