Skip to content

Latest commit

 

History

History
526 lines (370 loc) · 36.2 KB

File metadata and controls

526 lines (370 loc) · 36.2 KB

HTTPS Стрийминг с Протокол за Контекст на Модела (MCP)

Тази глава предоставя изчерпателно ръководство за внедряване на сигурен, мащабируем и реалновременен стрийминг с Протокол за Контекст на Модела (MCP) чрез HTTPS. Тя обхваща мотивацията за стрийминг, наличните транспортни механизми, как да се внедри стрийминг HTTP в MCP, най-добрите практики за сигурност, миграция от SSE и практически насоки за изграждане на собствени MCP приложения за стрийминг.

Транспортни механизми и стрийминг в MCP

Този раздел разглежда различните транспортни механизми, налични в MCP, и тяхната роля в осигуряването на стрийминг възможности за реалновременна комуникация между клиенти и сървъри.

Какво е транспортен механизъм?

Транспортният механизъм определя как данните се обменят между клиента и сървъра. MCP поддържа множество типове транспорт, за да отговори на различни среди и изисквания:

  • stdio: Стандартен вход/изход, подходящ за локални и CLI-базирани инструменти. Прост, но неподходящ за уеб или облачни приложения.
  • SSE (Server-Sent Events): Позволява на сървърите да изпращат реалновременни актуализации към клиентите чрез HTTP. Добър за уеб интерфейси, но ограничен в мащабируемост и гъвкавост.
  • Streamable HTTP: Модерен HTTP-базиран транспорт за стрийминг, поддържащ известия и по-добра мащабируемост. Препоръчва се за повечето производствени и облачни сценарии.

Сравнителна таблица

Разгледайте таблицата по-долу, за да разберете разликите между тези транспортни механизми:

Транспорт Реалновременни актуализации Стрийминг Мащабируемост Приложение
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).
  • 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) за по-добра обработка от клиента.

Сравнение: Класически стрийминг срещу MCP стрийминг

Разликите между начина, по който стриймингът работи в "класически" стил, и начина, по който работи в MCP, могат да бъдат представени така:

Характеристика Класически HTTP стрийминг MCP стрийминг (известия)
Основен отговор На части Единичен, в края
Актуализации за напредък Изпращат се като части данни Изпращат се като известия
Изисквания към клиента Трябва да обработва потока Трябва да внедри обработчик на съобщения
Приложение Големи файлове, AI токени Напредък, логове, реалновременна обратна връзка

Наблюдавани ключови разлики

Допълнително, ето някои ключови разлики:

  • Модел на комуникация:

    • Класически HTTP стрийминг: Използва прост кодиране на трансфер на части за изпращане на данни.
    • 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

@@CODE_BLOCK_13 Има две убедителни причини да преминете от 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. Тествайте вашата реализация, като стартирате както сървъра, така и клиента, и наблюдавайте известията.

Решение

Допълнителна литература и какво следва?

За да продължите своето пътешествие с MCP стрийминг и да разширите знанията си, този раздел предоставя допълнителни ресурси и предложени следващи стъпки за създаване на по-усъвършенствани приложения.

Допълнителна литература

Какво следва?

  • Опитайте да създадете по-усъвършенствани MCP инструменти, които използват стрийминг за анализи в реално време, чат или съвместно редактиране.
  • Изследвайте интеграцията на MCP стрийминг с фронтенд рамки (React, Vue и др.) за актуализации на потребителския интерфейс в реално време.
  • Следващо: Използване на AI Toolkit за VSCode

Отказ от отговорност:
Този документ е преведен с помощта на AI услуга за превод Co-op Translator. Въпреки че се стремим към точност, моля, имайте предвид, че автоматичните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия изходен език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Не носим отговорност за каквито и да е недоразумения или погрешни интерпретации, произтичащи от използването на този превод.