Files
2026-07-13 13:31:35 +08:00

37 KiB
Raw Permalink Blame History

HTTPS Streaming with Model Context Protocol (MCP)

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

Транспортні механізми та стрімінг у MCP

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

Що таке транспортний механізм?

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

  • stdio: стандартний ввід/вивід, підходить для локальних і CLI-інструментів. Простий, але не підходить для вебу або хмари.
  • SSE (Server-Sent Events): дозволяє серверам надсилати оновлення в реальному часі клієнтам через HTTP. Добре для веб-інтерфейсів, але обмежене масштабуванням і гнучкістю. З версії MCP Specification 2025-06-18 автономний транспорт SSE було застаріло і замінено на транспорт "Streamable HTTP".
  • Streamable HTTP: сучасний HTTP-базований стрімінговий транспорт, що підтримує сповіщення та краще масштабування. Рекомендується для більшості виробничих і хмарних сценаріїв.

Таблиця порівняння

Перегляньте таблицю нижче, щоб зрозуміти відмінності між цими транспортними механізмами:

Transport Оновлення в реальному часі Стрімінг Масштабованість Випадок використання
stdio Ні Ні Низька Локальні CLI-інструменти
SSE Так Так Середня Веб, оновлення в реальному часі
Streamable HTTP Так Так Висока Хмара, багато користувачів

Порада: Вибір правильного транспорту впливає на продуктивність, масштабованість і досвід користувача. Streamable HTTP рекомендується для сучасних, масштабованих та готових до хмари застосунків.

Зверніть увагу на транспорти stdio і SSE, які були показані у попередніх розділах, і на те, як Streamable HTTP є транспортом, описаним у цьому розділі.

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

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

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

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

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

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

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

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

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

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

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

Python

Сервер (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).
  • Тип вмісту зазвичай 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() використовується для надсилання інформаційних повідомлень.

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

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() для надсилання сповіщень під час обробки кожного елемента. Це надсилає повідомлення клієнту до готовності основного результату.
  • На клієнті: Реалізуйте обробник повідомлень, який слухає і відображає сповіщення по мірі їх надходження. Цей обробник розрізняє сповіщення і фінальний результат.

Приклад сервера:

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

Приклад клієнта:

Python

async def message_handler(message):
    if isinstance(message, types.ServerNotification):
        print("NOTIFICATION:", message)
    else:
        print("SERVER MESSAGE:", message)

Питання безпеки

При реалізації MCP серверів з HTTP-транспортом безпека стає першочерговим питанням, що потребує особливої уваги до різноманітних векторів атак і механізмів захисту.

Огляд

Безпека критична при публічному доступі MCP серверів через HTTP. Streamable HTTP відкриває нові можливості для атак, тож вимагає ретельного налаштування.

Ключові моменти

  • Перевірка заголовка Origin: Завжди валідуйте заголовок Origin, щоб запобігти атакам DNS rebinding.
  • Прив’язка до localhost: Для локальної розробки прив’язуйте сервер до localhost, щоб не відкривати до громадських мереж.
  • Аутентифікація: Впроваджуйте аутентифікацію (наприклад, API ключі, OAuth) для продакшен середовищ.
  • CORS: Налаштовуйте політики Cross-Origin Resource Sharing (CORS) для обмеження доступу.
  • HTTPS: Використовуйте HTTPS у продакшені для шифрування трафіку.

Найкращі практики

  • Ніколи не довіряйте вхідним запитам без перевірки.
  • Логгіруйте та моніторте всі доступи і помилки.
  • Регулярно оновлюйте залежності для патчу вразливостей.

Виклики

  • Балансування безпеки та простоти розробки
  • Забезпечення сумісності з різними клієнтськими середовищами

Оновлення з SSE до Streamable HTTP

Для застосунків, які наразі використовують Server-Sent Events (SSE), перехід на Streamable HTTP забезпечує розширені можливості та кращу довгострокову підтримку для реалізацій MCP.

Чому оновлювати?

Є дві переконливі причини оновитися з SSE до Streamable HTTP:

  • Streamable HTTP пропонує кращу масштабованість, сумісність і більш розвинену підтримку повідомлень, ніж SSE.
  • Це рекомендований транспорт для нових MCP-застосунків.

Кроки міграції

Ось як можна мігрувати з SSE до Streamable HTTP у ваших MCP-застосунках:

  • Оновіть серверний код, щоб використовувати transport="streamable-http" у mcp.run().
  • Оновіть клієнтський код, щоб використовувати streamablehttp_client замість SSE клієнта.
  • Реалізуйте обробник повідомлень у клієнті для опрацювання сповіщень.
  • Проведіть тестування сумісності з існуючими інструментами та робочими процесами.

Підтримка сумісності

Рекомендується підтримувати сумісність з існуючими 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 тощо) для живих оновлень UI.
  • Далі: Utilising AI Toolkit for VSCode

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