Эта глава представляет подробное руководство по реализации безопасного, масштабируемого и потокового взаимодействия в реальном времени с использованием протокола 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 | Да | Да | Высокая | Облако, многоклиентские приложения |
Совет: Выбор правильного механизма передачи данных влияет на производительность, масштабируемость и пользовательский опыт. 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-потоковая передача (уведомления) |
|---|---|---|
| Основной ответ | Передается частями | Единый, в конце |
| Обновления прогресса | Отправляются как части данных | Отправляются как уведомления |
| Требования к клиенту | Должен обрабатывать поток | Должен реализовать обработчик сообщений |
| Сценарий использования | Большие файлы, потоки токенов ИИ | Прогресс, логи, обратная связь в реальном времени |
Кроме того, вот некоторые ключевые различия:
-
Паттерн взаимодействия:
- Классическая HTTP-потоковая передача: Использует простую кодировку chunked transfer для отправки данных частями.
- MCP-потоковая передача: Использует структурированную систему уведомлений с протоколом JSON-RPC.
-
Формат сообщений:
- Классическая HTTP: Простые текстовые части с переводами строк.
- MCP: Структурированные объекты LoggingMessageNotification с метаданными.
-
Реализация клиента:
- Классическая HTTP: Простой клиент, обрабатывающий потоковые ответы.
- MCP: Более сложный клиент с обработчиком сообщений для обработки различных типов сообщений.
-
Обновления прогресса:
- Классическая HTTP: Прогресс является частью основного потока ответа.
- MCP: Прогресс отправляется через отдельные уведомления, а основной ответ приходит в конце.
Есть несколько рекомендаций по выбору между реализацией классической потоковой передачи (как показано выше через /stream) и выбором потоковой передачи через MCP.
- Для простых потребностей потоковой передачи: Классическая HTTP-потоковая передача проще в реализации и достаточна для базовых потребностей.
- Для сложных, интерактивных приложений: MCP-потоковая передача предоставляет более структурированный подход с богатыми метаданными и разделением между уведомлениями и конечными результатами.
- Для приложений с ИИ: Система уведомлений 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 вы определяете инструменты, которые могут отправлять уведомления во время обработки запросов. Сервер использует объект контекста (обычно 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()для отправки уведомлений по мере обработки каждого элемента. Это отправляет сообщение клиенту до готовности основного результата. - На клиенте: Реализуйте обработчик сообщений, который слушает и отображает уведомления по мере их поступления. Этот обработчик различает уведомления и конечный результат.
Пример сервера:
@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-транспортами безопасность становится первоочередной задачей, требующей внимательного подхода к множеству векторов атак и механизмов защиты.
Безопасность критически важна при открытии MCP-серверов через HTTP. Streamable HTTP вводит новые поверхности атаки и требует тщательной настройки.
- Проверка заголовка Origin: Всегда проверяйте заголовок
Origin, чтобы предотвратить атаки DNS rebinding. - Привязка к localhost: Для локальной разработки привязывайте серверы к
localhost, чтобы избежать их публичного доступа. - Аутентификация: Реализуйте аутентификацию (например, API-ключи, OAuth) для производственных развертываний.
- CORS: Настройте политики Cross-Origin Resource Sharing (CORS) для ограничения доступа.
- HTTPS: Используйте HTTPS в производственной среде для шифрования трафика.
- Никогда не доверяйте входящим запросам без проверки.
- Логируйте и мониторьте все обращения и ошибки.
- Регулярно обновляйте зависимости для устранения уязвимостей.
- Баланс между безопасностью и удобством разработки.
- Обеспечение совместимости с различными клиентскими средами.
Для приложений, которые в настоящее время используют Server-Sent Events (SSE), переход на Streamable HTTP предоставляет расширенные возможности и лучшую долгосрочную устойчивость для ваших реализаций MCP.
Есть две веские причины перейти с 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 Streaming
- Microsoft: Server-Sent Events (SSE)
- Microsoft: CORS в ASP.NET Core
- Python requests: Потоковые запросы
- Попробуйте создать более сложные MCP-инструменты, использующие потоковую передачу для аналитики в реальном времени, чатов или совместного редактирования.
- Изучите интеграцию MCP-потоков с фронтенд-фреймворками (React, Vue и т.д.) для обновления интерфейса в реальном времени.
- Далее: Использование AI Toolkit для VSCode
Отказ от ответственности:
Этот документ был переведен с использованием сервиса автоматического перевода Co-op Translator. Хотя мы стремимся к точности, пожалуйста, учитывайте, что автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникающие в результате использования данного перевода.