Skip to content

Latest commit

 

History

History
528 lines (370 loc) · 34.1 KB

File metadata and controls

528 lines (370 loc) · 34.1 KB

HTTPS Streaming з Model Context Protocol (MCP)

Цей розділ містить детальний посібник з реалізації безпечного, масштабованого та реального часу стрімінгу за допомогою Model Context Protocol (MCP) через HTTPS. Тут розглядаються мотивація для стрімінгу, доступні транспортні механізми, як реалізувати стрімінг HTTP у MCP, найкращі практики безпеки, міграція з SSE та практичні поради для створення власних стрімінгових MCP-додатків.

Транспортні механізми та стрімінг у 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 є транспортом, розглянутим у цьому розділі.

Стрімінг: концепції та мотивація

Розуміння основних концепцій і мотивації стрімінгу є важливим для реалізації ефективних систем комунікації в реальному часі.

Стрімінг — це техніка в мережевому програмуванні, яка дозволяє надсилати та отримувати дані невеликими, керованими частинами або як послідовність подій, замість того, щоб чекати на повну відповідь. Це особливо корисно для:

  • Великих файлів або наборів даних.
  • Оновлень у реальному часі (наприклад, чат, індикатори прогресу).
  • Довготривалих обчислень, коли потрібно тримати користувача в курсі.

Ось що варто знати про стрімінг на високому рівні:

  • Дані доставляються поступово, а не всі одразу.
  • Клієнт може обробляти дані по мірі їх надходження.
  • Зменшує відчутну затримку і покращує користувацький досвід.

Чому варто використовувати стрімінг?

Причини для використання стрімінгу такі:

  • Користувачі отримують зворотний зв’язок негайно, а не лише в кінці.
  • Дозволяє створювати додатки в реальному часі та чуйні інтерфейси.
  • Ефективніше використовує мережеві та обчислювальні ресурси.

Простий приклад: HTTP стрімінг сервер і клієнт

Ось простий приклад, як можна реалізувати стрімінг:

Python

Сервер (Python, з FastAPI та 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")

Клієнт (Python, з 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())

Цей приклад демонструє сервер, який надсилає серію повідомлень клієнту по мірі їх готовності, замість того, щоб чекати на всі повідомлення одразу.

Як це працює:

  • Сервер віддає кожне повідомлення, щойно воно готове.
  • Клієнт отримує і виводить кожен фрагмент по мірі надходження.

Вимоги:

  • Сервер має використовувати стрімінгову відповідь (наприклад, StreamingResponse у FastAPI).
  • Клієнт має обробляти відповідь як потік (stream=True у requests).
  • Content-Type зазвичай text/event-stream або application/octet-stream.

Java

Сервер (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) для кращої обробки на клієнті

Порівняння: класичний стрімінг vs MCP стрімінг

Відмінності між класичним стрімінгом і тим, як це працює в 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 стрімінг — це не про надсилання основної відповіді частинами, а про надсилання сповіщень клієнту під час обробки запиту інструментом. Ці сповіщення можуть містити оновлення прогресу, логи або інші події.

Як це працює

Основний результат все ще надсилається як одна відповідь. Однак сповіщення можуть надсилатися окремими повідомленнями під час обробки, оновлюючи клієнта в реальному часі. Клієнт повинен вміти обробляти і відображати ці сповіщення.

Що таке сповіщення?

Ми згадали "сповіщення", що це означає в контексті 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, потрібно налаштувати як серверну, так і клієнтську частини для обробки оновлень у реальному часі. Це дозволяє вашому додатку надавати миттєвий зворотній зв’язок користувачам під час довготривалих операцій.

Серверна частина: надсилання сповіщень

Почнемо з серверної частини. У MCP ви визначаєте інструменти, які можуть надсилати сповіщення під час обробки запитів. Сервер використовує об’єкт контексту (зазвичай ctx) для надсилання повідомлень клієнту.

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}")

У наведеному прикладі інструмент process_files надсилає три сповіщення клієнту під час обробки кожного файлу. Метод ctx.info() використовується для надсилання інформаційних повідомлень.

Крім того, щоб увімкнути сповіщення, переконайтеся, що сервер використовує стрімінговий транспорт (наприклад, streamable-http), а клієнт реалізує обробник повідомлень для обробки сповіщень. Ось як можна налаштувати сервер для використання транспорту 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}"
    };
}

У цьому прикладі на .NET інструмент ProcessFiles позначений атрибутом Tool і надсилає три сповіщення клієнту під час обробки кожного файлу. Метод ctx.Info() використовується для надсилання інформаційних повідомлень.

Щоб увімкнути сповіщення у вашому MCP сервері на .NET, переконайтеся, що ви використовуєте стрімінговий транспорт:

var builder = McpBuilder.Create();
await builder
    .UseStreamableHttp() // Enable streamable HTTP transport
    .Build()
    .RunAsync();

Клієнтська частина: отримання сповіщень

Клієнт повинен реалізувати обробник повідомлень, щоб обробляти і відображати сповіщення по мірі їх надходження.

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:

У наведеному коді функція message_handler перевіряє, чи є вхідне повідомлення сповіщенням. Якщо так, воно виводиться; інакше обробляється як звичайне серверне повідомлення. Також зверніть увагу, що ClientSession ініціалізується з message_handler для обробки вхідних сповіщень.

.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

У цьому прикладі на .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 сервер і клієнт, де сервер обробляє список елементів (наприклад, файли або документи) і надсилає сповіщення для кожного обробленого елемента. Клієнт має відображати кожне сповіщення у міру його надходження.

Кроки:

  1. Реалізуйте серверний інструмент, який обробляє список і надсилає сповіщення для кожного елемента.
  2. Реалізуйте клієнта з обробником повідомлень для відображення сповіщень у реальному часі.
  3. Протестуйте реалізацію, запустивши сервер і клієнта, та спостерігайте за сповіщеннями.

Solution

Подальше читання та що далі?

Щоб продовжити вивчення MCP стрімінгу та розширити свої знання, цей розділ пропонує додаткові ресурси та рекомендації для створення більш складних застосунків.

Подальше читання

Що далі?

  • Спробуйте створити більш складні MCP інструменти, які використовують стрімінг для аналітики в реальному часі, чатів або спільного редагування.
  • Дослідіть інтеграцію MCP стрімінгу з фронтенд-фреймворками (React, Vue тощо) для живих оновлень інтерфейсу.
  • Далі: Utilising AI Toolkit for VSCode

Відмова від відповідальності:
Цей документ було перекладено за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ рідною мовою слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується звертатися до професійного людського перекладу. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.