Цей розділ містить детальний посібник з реалізації безпечного, масштабованого та реального часу стрімінгу за допомогою Model Context Protocol (MCP) через HTTPS. Тут розглядаються мотивація для стрімінгу, доступні транспортні механізми, як реалізувати стрімінг HTTP у MCP, найкращі практики безпеки, міграція з SSE та практичні поради для створення власних стрімінгових MCP-додатків.
У цьому розділі розглядаються різні транспортні механізми, доступні в MCP, та їх роль у забезпеченні можливостей стрімінгу для реального часу комунікації між клієнтами та серверами.
Транспортний механізм визначає, як дані обмінюються між клієнтом і сервером. MCP підтримує кілька типів транспорту, щоб відповідати різним середовищам і вимогам:
- stdio: Стандартний ввід/вивід, підходить для локальних інструментів та CLI. Простий, але не підходить для вебу чи хмари.
- SSE (Server-Sent Events): Дозволяє серверам надсилати оновлення в реальному часі клієнтам через HTTP. Добре для веб-інтерфейсів, але обмежений у масштабованості та гнучкості.
- Streamable HTTP: Сучасний HTTP-стрімінг, що підтримує сповіщення та кращу масштабованість. Рекомендується для більшості виробничих та хмарних сценаріїв.
Ознайомтеся з таблицею порівняння нижче, щоб зрозуміти відмінності між цими транспортними механізмами:
| Транспорт | Оновлення в реальному часі | Стрімінг | Масштабованість | Сценарій використання |
|---|---|---|---|---|
| stdio | Ні | Ні | Низька | Локальні CLI-інструменти |
| SSE | Так | Так | Середня | Веб, оновлення в реальному часі |
| Streamable HTTP | Так | Так | Висока | Хмара, мультиклієнтські додатки |
Tip: Вибір правильного транспорту впливає на продуктивність, масштабованість і користувацький досвід. 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 стрімінг (сповіщення) |
|---|---|---|
| Основна відповідь | Частинами (chunked) | Одна, в кінці |
| Оновлення прогресу | Надсилаються як частини даних | Надсилаються як сповіщення |
| Вимоги до клієнта | Має обробляти стрім | Має реалізувати обробник повідомлень |
| Сценарій використання | Великі файли, потоки токенів AI | Прогрес, логи, зворотній зв’язок у реальному часі |
Також ось кілька ключових відмінностей:
-
Патерн комунікації:
- Класичний HTTP стрімінг: Використовує просте кодування chunked для передачі даних частинами
- MCP стрімінг: Використовує структуровану систему сповіщень з протоколом JSON-RPC
-
Формат повідомлень:
- Класичний HTTP: Простий текст з розділенням новими рядками
- MCP: Структуровані об’єкти LoggingMessageNotification з метаданими
-
Реалізація клієнта:
- Класичний HTTP: Простий клієнт, що обробляє стрімінгові відповіді
- MCP: Більш складний клієнт з обробником повідомлень для різних типів повідомлень
-
Оновлення прогресу:
- Класичний HTTP: Прогрес є частиною основного потоку відповіді
- MCP: Прогрес надсилається окремими сповіщеннями, а основна відповідь приходить в кінці
Ось дещо, що ми рекомендуємо при виборі між класичним стрімінгом (як показано вище через /stream) і стрімінгом через MCP.
-
Для простих потреб стрімінгу: Класичний HTTP стрімінг простіший у реалізації і достатній для базових випадків.
-
Для складних, інтерактивних додатків: MCP стрімінг забезпечує більш структурований підхід з багатшими метаданими та розділенням між сповіщеннями і кінцевими результатами.
-
Для AI-додатків: Система сповіщень MCP особливо корисна для довготривалих AI-завдань, де потрібно тримати користувачів у курсі прогресу.
Отже, ви вже бачили деякі рекомендації та порівняння між класичним стрімінгом і стрімінгом у MCP. Тепер розглянемо детально, як саме можна використовувати стрімінг у MCP.
Розуміння того, як працює стрімінг у рамках MCP, є ключовим для створення чуйних додатків, які надають зворотній зв’язок у реальному часі під час довготривалих операцій.
У MCP стрімінг — це не про надсилання основної відповіді частинами, а про надсилання сповіщень клієнту під час обробки запиту інструментом. Ці сповіщення можуть містити оновлення прогресу, логи або інші події.
Основний результат все ще надсилається як одна відповідь. Однак сповіщення можуть надсилатися окремими повідомленнями під час обробки, оновлюючи клієнта в реальному часі. Клієнт повинен вміти обробляти і відображати ці сповіщення.
Ми згадали "сповіщення", що це означає в контексті MCP?
Сповіщення — це повідомлення, яке сервер надсилає клієнту, щоб інформувати про прогрес, стан або інші події під час довготривалої операції. Сповіщення підвищують прозорість і покращують користувацький досвід.
Наприклад, клієнт має надіслати сповіщення після встановлення початкового з’єднання з сервером.
Сповіщення виглядає як 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() використовується для надсилання інформаційних повідомлень.
Щоб увімкнути сповіщення у вашому MCP сервері на .NET, переконайтеся, що ви використовуєте стрімінговий транспорт:
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()для надсилання сповіщень під час обробки кожного елемента. Це надсилає повідомлення клієнту до того, як буде готовий основний результат. - На клієнті: Реалізуйте обробник повідомлень, який слухає
Існує дві вагомі причини перейти з SSE на Streamable HTTP:
- Streamable HTTP забезпечує кращу масштабованість, сумісність та ширші можливості сповіщень у порівнянні з SSE.
- Це рекомендований транспорт для нових MCP-застосунків.
Ось як ви можете перейти з SSE на Streamable HTTP у своїх MCP-застосунках:
- Оновіть серверний код, використовуючи
transport="streamable-http"уmcp.run(). - Оновіть клієнтський код, замінивши SSE клієнт на
streamablehttp_client. - Реалізуйте обробник повідомлень на клієнті для обробки сповіщень.
- Перевірте сумісність з існуючими інструментами та робочими процесами.
Рекомендується підтримувати сумісність з існуючими SSE клієнтами під час міграції. Ось кілька стратегій:
- Ви можете підтримувати одночасно SSE і Streamable HTTP, запустивши обидва транспорти на різних кінцевих точках.
- Поступово мігруйте клієнтів на новий транспорт.
Переконайтеся, що ви врахували наступні виклики під час міграції:
- Оновлення всіх клієнтів
- Обробка відмінностей у доставці сповіщень
Безпека має бути пріоритетом при впровадженні будь-якого сервера, особливо при використанні HTTP-транспортів, таких як Streamable HTTP у MCP.
При реалізації MCP серверів з HTTP-транспортами безпека стає ключовим питанням, що вимагає уважного ставлення до різних векторів атак та механізмів захисту.
Безпека критично важлива при відкритті MCP серверів через HTTP. Streamable HTTP створює нові вразливі місця, тому потрібна ретельна конфігурація.
Ось основні аспекти безпеки:
- Перевірка заголовка Origin: Завжди перевіряйте заголовок
Origin, щоб запобігти атакам DNS rebinding. - Прив’язка до localhost: Для локальної розробки прив’язуйте сервер до
localhost, щоб уникнути відкриття доступу в інтернет. - Аутентифікація: Впроваджуйте аутентифікацію (наприклад, API ключі, OAuth) для продакшн-розгортань.
- CORS: Налаштовуйте політики Cross-Origin Resource Sharing (CORS) для обмеження доступу.
- HTTPS: Використовуйте HTTPS у продакшн-середовищі для шифрування трафіку.
Також дотримуйтесь цих рекомендацій при забезпеченні безпеки вашого MCP стрімінгового сервера:
- Ніколи не довіряйте вхідним запитам без перевірки.
- Логування та моніторинг усіх доступів і помилок.
- Регулярно оновлюйте залежності для усунення вразливостей.
Під час впровадження безпеки у MCP стрімінгових серверах ви зіткнетесь з такими викликами:
- Балансування між безпекою та зручністю розробки
- Забезпечення сумісності з різними клієнтськими середовищами
Сценарій: Створіть MCP сервер і клієнт, де сервер обробляє список елементів (наприклад, файли або документи) і надсилає сповіщення для кожного обробленого елемента. Клієнт має відображати кожне сповіщення у міру його надходження.
Кроки:
- Реалізуйте серверний інструмент, який обробляє список і надсилає сповіщення для кожного елемента.
- Реалізуйте клієнта з обробником повідомлень для відображення сповіщень у реальному часі.
- Протестуйте реалізацію, запустивши сервер і клієнта, та спостерігайте за сповіщеннями.
Щоб продовжити вивчення MCP стрімінгу та розширити свої знання, цей розділ пропонує додаткові ресурси та рекомендації для створення більш складних застосунків.
- Microsoft: Вступ до HTTP стрімінгу
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS в ASP.NET Core
- Python requests: Streaming Requests
- Спробуйте створити більш складні MCP інструменти, які використовують стрімінг для аналітики в реальному часі, чатів або спільного редагування.
- Дослідіть інтеграцію MCP стрімінгу з фронтенд-фреймворками (React, Vue тощо) для живих оновлень інтерфейсу.
- Далі: Utilising AI Toolkit for VSCode
Відмова від відповідальності:
Цей документ було перекладено за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ рідною мовою слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується звертатися до професійного людського перекладу. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.