Ово поглавље пружа свеобухватан водич за имплементацију безбедног, скалабилног и стриминга у реалном времену са Протоколом Контекста Модела (MCP) користећи HTTPS. Обухвата мотивацију за стриминг, доступне механизме транспорта, како имплементирати HTTP стриминг у MCP-у, најбоље праксе за безбедност, миграцију са SSE-а и практичне смернице за изградњу сопствених MCP апликација за стриминг.
Овај део истражује различите механизме транспорта доступне у MCP-у и њихову улогу у омогућавању стриминг могућности за комуникацију у реалном времену између клијената и сервера.
Механизам транспорта дефинише како се подаци размењују између клијента и сервера. MCP подржава више типова транспорта како би одговарао различитим окружењима и захтевима:
- stdio: Стандардни улаз/излаз, погодан за локалне и CLI алате. Једноставан, али није погодан за веб или облак.
- SSE (Server-Sent Events): Омогућава серверима да шаљу ажурирања у реалном времену клијентима преко HTTP-а. Добар за веб интерфејсе, али ограничен у скалабилности и флексибилности.
- Streamable HTTP: Модеран HTTP стриминг транспорт, који подржава обавештења и бољу скалабилност. Препоручује се за већину продукцијских и облачних сценарија.
Погледајте табелу поређења испод како бисте разумели разлике између ових механизама транспорта:
| Транспорт | Ажурирања у реалном времену | Стриминг | Скалабилност | Примена |
|---|---|---|---|---|
| stdio | Не | Не | Ниска | Локални CLI алати |
| SSE | Да | Да | Средња | Веб, ажурирања у реалном времену |
| Streamable HTTP | Да | Да | Висока | Облак, више клијената |
Савет: Избор правог транспорта утиче на перформансе, скалабилност и корисничко искуство. Streamable HTTP се препоручује за модерне, скалабилне и апликације спремне за облак.
Запамтите транспорте stdio и SSE који су вам представљени у претходним поглављима и како је Streamable HTTP транспорт који се обрађује у овом поглављу.
Разумевање основних концепата и мотивације иза стриминга је од суштинског значаја за имплементацију ефикасних система комуникације у реалном времену.
Стриминг је техника у мрежном програмирању која омогућава слање и примање података у малим, управљивим деловима или као низ догађаја, уместо чекања да цео одговор буде спреман. Ово је посебно корисно за:
- Велике датотеке или скупове података.
- Ажурирања у реалном времену (нпр. чет, траке напретка).
- Дуготрајне рачунске операције где желите да корисника држите информисаним.
Ево шта треба да знате о стримингу на високом нивоу:
- Подаци се испоручују постепено, а не одједном.
- Клијент може обрађивати податке како стижу.
- Смањује перципирану латенцију и побољшава корисничко искуство.
Разлози за коришћење стриминга су следећи:
- Корисници добијају повратне информације одмах, а не само на крају.
- Омогућава апликације у реалном времену и одзивне интерфејсе.
- Ефикасније коришћење мрежних и рачунских ресурса.
Ево једноставног примера како се стриминг може имплементирати:
Сервер (Python, користећи FastAPI и 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")Клијент (Python, користећи 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())Овај пример демонстрира сервер који шаље серију порука клијенту како постају доступне, уместо да чека да све поруке буду спремне.
Како функционише:
- Сервер шаље сваку поруку како је спремна.
- Клијент прима и штампа сваки део како стиже.
Захтеви:
- Сервер мора користити стриминг одговор (нпр.
StreamingResponseу FastAPI-ју). - Клијент мора обрађивати одговор као стрим (
stream=Trueу requests). - Content-Type је обично
text/event-streamилиapplication/octet-stream.
Сервер (Java, користећи Spring Boot и 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));
}
}Клијент (Java, користећи 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();
}
}Напомене о имплементацији у Java:
- Користи реактивни стек Spring Boot-а са
Fluxза стриминг. ServerSentEventпружа структуриран стриминг догађаја са типовима догађаја.WebClientсаbodyToFlux()омогућава реактивну потрошњу стриминга.delayElements()симулира време обраде између догађаја.- Догађаји могу имати типове (
info,result) за боље руковање на страни клијента.
Разлике између начина на који стриминг функционише на "класичан" начин у односу на MCP стриминг могу се приказати овако:
| Карактеристика | Класични HTTP стриминг | MCP стриминг (Обавештења) |
|---|---|---|
| Главни одговор | У деловима | Један, на крају |
| Ажурирања напретка | Шаљу се као делови података | Шаљу се као обавештења |
| Захтеви клијента | Мора обрађивати стрим | Мора имплементирати обрађивач порука |
| Примена | Велике датотеке, AI токени | Напредак, логови, повратне информације у реалном времену |
Постоје неке препоруке када је реч о избору између имплементације класичног стриминга (као што је крајња тачка коју смо вам показали горе користећи /stream) у односу на избор стриминга преко MCP-а.
-
За једноставне потребе стриминга: Класични HTTP стриминг је једноставнији за имплементацију и довољан за основне потребе стриминга.
-
За сложене, интерактивне апликације: MCP стриминг пружа структуриран приступ са богатијим метаподацима и одвајањем између обавештења и коначних резултата.
-
За AI апликације: MCP-ов систем обавештења је посебно користан за дуготрајне AI задатке где желите да кориснике држите информисаним о напретку.
У реду, видели сте неке препоруке и поређења до сада о разлици између класичног стриминга и стриминга у MCP-у. Хајде да детаљно објаснимо како можете искористити стриминг у MCP-у.
Разумевање како стриминг функционише у оквиру MCP оквира је од суштинског значаја за изградњу одзивних апликација које пружају повратне информације у реалном времену корисницима током дуготрајних операција.
У MCP-у, стриминг није о слању главног одговора у деловима, већ о слању обавештења клијенту док алат обрађује захтев. Ова обавештења могу укључивати ажурирања напретка, логове или друге догађаје.
Главни резултат се и даље шаље као један одговор. Међутим, обавештења се могу слати као посебне поруке током обраде и на тај начин ажурирати клијента у реалном времену. Клијент мора бити у стању да обрађује и приказује ова обавештења.
Рекли смо "обавештење", шта то значи у контексту MCP-а?
Обавештење је порука коју сервер шаље клијенту како би га обавестио о напретку, статусу или другим догађајима током дуготрајне операције. Обавештења побољшавају транспарентност и корисничко искуство.
На пример, клијент треба да пошаље обавештење након што је иницијални handshake са сервером направљен.
Обавештење изгледа овако као JSON порука:
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}Обавештења припадају теми у MCP-у која се назива "Logging".
Да би логовање функционисало, сервер мора да га омогући као функцију/способност овако:
{
"capabilities": {
"logging": {}
}
}Note
У зависности од коришћеног SDK-а, логовање може бити подразумевано омогућено или ћете га можда морати експлицитно омогућити у конфигурацији сервера.
Постоје различити типови обавештења:
| Ниво | Опис | Пример употребе |
|---|---|---|
| debug | Детаљне информације за дебаг | Улаз/излаз функције |
| info | Опште информационе поруке | Ажурирања напретка операције |
| notice | Нормални али значајни догађаји | Промене конфигурације |
| warning | Упозоравајући услови | Коришћење застареле функције |
| error | Услов грешке | Неуспех операције |
| critical | Критични услови | Неуспех компоненти система |
| alert | Потребна је хитна акција | Откривена корупција података |
| emergency | Систем је неупотребљив | Потпуни неуспех система |
Да бисте имплементирали обавештења у MCP-у, потребно је да подесите и серверску и клијентску страну за обраду ажурирања у реалном времену. Ово омогућава вашој апликацији да пружи тренутне повратне информације корисницима током дуготрајних операција.
Почнимо са серверском страном. У MCP-у, дефинишете алате који могу слати обавештења током обраде захтева. Сервер користи објекат контекста (обично ctx) за слање порука клијенту.
@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}")У претходном примеру, алат process_files шаље три обавештења клијенту док обрађује сваку датотеку. Метод ctx.info() се користи за слање информационих порука.
Додатно, да бисте омогућили обавештења, уверите се да ваш сервер користи стриминг транспорт (као што је streamable-http) и да ваш клијент имплементира обрађивач порука за обраду обавештења. Ево како можете подесити сервер да користи 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}"
};
}У овом .NET примеру, алат ProcessFiles је декорисан са атрибутом Tool и шаље три обавештења клијенту док обрађује сваку датотеку. Метод ctx.Info() се користи за слање информационих порука.
Да бисте омогућили обавештења у вашем .NET MCP серверу, уверите се да користите стриминг транспорт:
var builder = McpBuilder.Create();
await builder
.UseStreamableHttp() // Enable streamable HTTP transport
.Build()
.RunAsync();Клијент мора имплементирати обрађивач порука за обраду и приказивање обавештења како стижу.
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:У претходном коду, функција message_handler проверава да ли је долазна порука обавештење. Ако јесте, штампа обавештење; у супротном, обрађује је као редовну поруку сервера. Такође, обратите пажњу како је ClientSession иницијализован са message_handler за обраду долазних обавештења.
// 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У овом .NET примеру, функција MessageHandler проверава да ли је долазна порука обавештење. Ако јесте, штампа обавештење; у супротном, обрађује је као редовну поруку сервера. ClientSession је иницијализован са обрађивачем порука преко ClientSessionOptions.
Да бисте омогућили обавештења, уверите се да ваш сервер користи стриминг транспорт (као што је streamable-http) и да ваш клијент имплементира обрађивач порука за обраду обавештења.
Овај део објашњава концепт ажурирања напретка у MCP-у, зашто су важна и како их имплементирати користећи Streamable HTTP. Такође ћете пронаћи практичан задатак за јачање вашег разумевања.
Ажурирања напретка су поруке у реалном времену које сервер шаље клијенту током дуготрајних операција. Уместо да чека да цео процес заврши, сервер ажурира клијента о тренутном статусу. Ово побољшава транспарентност, корисничко искуство и олакшава дебаговање.
Пример:
"Processing document 1/10"
"Processing document 2/10"
...
"Processing complete!"
Ажурирања напретка су важна из неколико разлога:
- Боље корисничко искуство: Корисници виде ажурирања како рад напредује, а не само на крају.
- Повратне информације у реалном времену: Клијенти могу приказивати траке напретка или логове, чинећи апликацију одзивном.
- Лакше дебаговање и праћење: Програмери и корисници могу видети где процес може бити спор или заглављен.
Ево како можете имплементирати ажурирања напретка у MCP-у:
- На серверу: Користите
ctx.info()илиctx.log()за слање обавештења како се свака ставка обрађује. Ово шаље поруку клијенту пре него што је главни резултат спреман. - На клијенту: Имплементирајте обрађивач порука који слуша и приказује обавештења како стижу. Овај обрађивач разликује обавештења од коначног резултата.
Пример сервера:
@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}")Пример клијента:
async def message_handler(message):
if isinstance(message, types.ServerNotification):
print("NOTIFICATION:", message)
else:
print("SERVER MESSAGE:", message)Када имплементирате MCP сервере са HTTP-б Postoje dva ključna razloga za prelazak sa SSE na Streamable HTTP:
- Streamable HTTP nudi bolju skalabilnost, kompatibilnost i bogatiju podršku za obaveštenja u poređenju sa SSE.
- Preporučeni je transport za nove MCP aplikacije.
Evo kako možete migrirati sa SSE na Streamable HTTP u vašim MCP aplikacijama:
- Ažurirajte serverski kod tako da koristi
transport="streamable-http"umcp.run(). - Ažurirajte klijentski kod tako da koristi
streamablehttp_clientumesto SSE klijenta. - Implementirajte rukovalac porukama u klijentu za obradu obaveštenja.
- Testirajte kompatibilnost sa postojećim alatima i radnim tokovima.
Preporučuje se da održavate kompatibilnost sa postojećim SSE klijentima tokom procesa migracije. Evo nekoliko strategija:
- Možete podržavati i SSE i Streamable HTTP tako što ćete pokrenuti oba transporta na različitim krajnjim tačkama.
- Postepeno migrirajte klijente na novi transport.
Obratite pažnju na sledeće izazove tokom migracije:
- Ažuriranje svih klijenata
- Upravljanje razlikama u isporuci obaveštenja
Bezbednost treba da bude glavni prioritet prilikom implementacije bilo kog servera, posebno kada koristite HTTP-bazirane transporte poput Streamable HTTP u MCP.
Prilikom implementacije MCP servera sa HTTP-baziranim transportima, bezbednost postaje ključna tema koja zahteva pažljivo razmatranje različitih vektora napada i mehanizama zaštite.
Bezbednost je od suštinskog značaja kada izlažete MCP servere putem HTTP-a. Streamable HTTP uvodi nove površine za napade i zahteva pažljivu konfiguraciju.
Evo nekoliko ključnih bezbednosnih aspekata:
- Validacija Origin zaglavlja: Uvek validirajte
Originzaglavlje kako biste sprečili DNS rebinding napade. - Povezivanje na localhost: Za lokalni razvoj, povežite servere na
localhostkako biste izbegli izlaganje javnom internetu. - Autentifikacija: Implementirajte autentifikaciju (npr. API ključevi, OAuth) za produkcijska okruženja.
- CORS: Konfigurišite Cross-Origin Resource Sharing (CORS) politike kako biste ograničili pristup.
- HTTPS: Koristite HTTPS u produkciji za šifrovanje saobraćaja.
Pored toga, evo nekoliko najboljih praksi koje treba slediti prilikom implementacije bezbednosti u vašem MCP streaming serveru:
- Nikada ne verujte dolaznim zahtevima bez validacije.
- Beležite i pratite sav pristup i greške.
- Redovno ažurirajte zavisnosti kako biste zakrpili bezbednosne ranjivosti.
Suočićete se sa nekim izazovima prilikom implementacije bezbednosti u MCP streaming serverima:
- Balansiranje između bezbednosti i jednostavnosti razvoja
- Obezbeđivanje kompatibilnosti sa različitim klijentskim okruženjima
Scenario: Napravite MCP server i klijent gde server obrađuje listu stavki (npr. fajlova ili dokumenata) i šalje obaveštenje za svaku obrađenu stavku. Klijent treba da prikazuje svako obaveštenje čim stigne.
Koraci:
- Implementirajte serverski alat koji obrađuje listu i šalje obaveštenja za svaku stavku.
- Implementirajte klijent sa rukovaocem poruka za prikaz obaveštenja u realnom vremenu.
- Testirajte implementaciju pokretanjem i servera i klijenta, i posmatrajte obaveštenja.
Da biste nastavili svoje istraživanje MCP streaminga i proširili svoje znanje, ovaj odeljak pruža dodatne resurse i predložene sledeće korake za izgradnju naprednijih aplikacija.
- Microsoft: Uvod u HTTP Streaming
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS u ASP.NET Core
- Python requests: Streaming Requests
- Pokušajte da napravite naprednije MCP alate koji koriste streaming za analitiku u realnom vremenu, čet ili kolaborativno uređivanje.
- Istražite integraciju MCP streaminga sa frontend okvirima (React, Vue, itd.) za ažuriranja korisničkog interfejsa uživo.
- Sledeće: Korišćenje AI alata za VSCode
Одрицање од одговорности:
Овај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције Co-op Translator. Иако тежимо тачности, молимо вас да имате у виду да аутоматизовани преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква неспоразумевања или погрешна тумачења која могу произаћи из коришћења овог превода.