# Производительность MCP-сервера: кэш, размер ответа, тайм-ауты

> Что протокол MCP редакции 2026-07-28 даёт для скорости и масштабирования - отсутствие сессий, подсказки кэширования, отмена, потоки SSE - и где начинается практика

Страница: https://mcpdoc.ru/optimization/performance/
Указатель сайта: https://mcpdoc.ru/llms.txt

Протокол даёт для производительности немного, но точно. В редакции `2026-07-28` нет сессий, поэтому любой экземпляр сервера может ответить на любой запрос. Списки и чтение ресурсов несут подсказки кэширования `ttlMs` и `cacheScope`. Есть постраничная выдача, отмена запроса и правила для потоков SSE.

Чисел - сколько запросов выдержит сервер, какое ставить время ожидания - в спецификации нет, и на этой странице их тоже нет. Всё, что выходит за протокол, вынесено в отдельный раздел практики.

описана редакция 2026-07-28, сверено со спецификацией и документацией nginx 4 октября 2026

Совместимость Modern страница описывает редакцию 2026-07-28; отличия старых редакций названы в тексте

- **Страница описывает редакцию:** 2026-07-28

- **Затрагивает устаревшее:** нет

- **Затрагивает удалённое в редакции 2026-07-28:** нет

- **Проверено:** 2026-10-04

- **Источник:** [modelcontextprotocol.io](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)

## Что даёт протокол

| Средство | Что оно даёт | Сила | Где описано |
|---|---|---|---|
| Нет сессий | запрос можно отдать любому экземпляру | сервер не должен полагаться на прежние запросы | [основы протокола](https://modelcontextprotocol.io/specification/2026-07-28/basic) |
| `ttlMs`, `cacheScope` | клиент реже запрашивает списки заново | сервер обязан их указывать | [Caching](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching) |
| Постоянный порядок инструментов | стабильный кэш списка и кэш запроса к модели | серверу следует | [Tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) |
| Постраничная выдача | длинный список не приходит одним ответом | размер страницы выбирает сервер | [Pagination](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination) |
| Отмена | сервер не тратит ресурсы на ненужный запрос | серверу следует остановить работу | [Cancellation](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation) |
| `X-Accel-Buffering: no` | события SSE не задерживаются в прокси | серверу следует | [Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http) |
| Заголовки `Mcp-Method`, `Mcp-Name` | посредник направляет запрос, не разбирая тело | `Mcp-Method` обязателен во всех запросах, `Mcp-Name` - в `tools/call`, `resources/read` и `prompts/get` | там же |

## Нет сессий - нет привязки к экземпляру

По [основам протокола](https://modelcontextprotocol.io/specification/2026-07-28/basic) MCP в этой редакции - протокол без состояния: всё нужное для обработки запроса есть в самом запросе.

- Сервер не должен полагаться на прежние запросы по тому же соединению, чтобы узнать версию протокола, возможности клиента или его имя. Эти сведения приходят в `_meta` каждого запроса.
- Серверу не следует требовать, чтобы клиент выполнял связанные операции через то же соединение или тот же процесс.
- Состояние, которое должно жить дольше одного запроса, обязано адресоваться явным идентификатором, который клиент передаёт в каждом запросе.

[Журнал изменений редакции](https://modelcontextprotocol.io/specification/2026-07-28/changelog) удаляет сессии протокола и заголовок `Mcp-Session-Id` из Streamable HTTP. Механизм [MRTR](https://mcpdoc.ru/protocol/mrtr/) описан в спецификации как способ получить от клиента дополнительные данные без общего хранилища между экземплярами и без балансировки с учётом состояния.

Следствие: самому протоколу Modern привязка клиента к экземпляру не нужна. Это не снимает вопроса о состоянии вашего приложения. Если инструмент создаёт что-то долгоживущее, все экземпляры должны уметь найти это по идентификатору из запроса. Как это устроить, спецификация не определяет.

В редакциях с `2025-03-26` по `2025-11-25` сервер мог выдать номер сессии, и клиент был обязан присылать его в каждом запросе. Сервер для двух эпох обслуживает такие сессии по правилам старой редакции, и для них вопрос маршрутизации остаётся. Подробности - на странице [Сервер для двух эпох](https://mcpdoc.ru/deployment/dual-era/).

## Подсказки кэширования

Правила взяты со страницы [Caching](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching).

Сервер обязан включать подсказки в завершённые результаты шести операций: `server/discover`, `tools/list`, `prompts/list`, `resources/list`, `resources/templates/list`, `resources/read`. Промежуточные результаты с `resultType: "input_required"` не кэшируются и подсказок не несут.

### `ttlMs`

Сколько миллисекунд клиент может считать результат свежим.

- Сервер обязан указывать значение не меньше нуля.
- `0` - результат следует считать устаревшим сразу.
- Поля нет - клиенту следует принять `0`. По спецификации так бывает только у старых серверов.
- Отрицательное значение клиенту следует считать нулём.

Это подсказка, а не обещание: данные могут измениться раньше срока. Клиенту не следует превращать `ttlMs` в период опроса. Свежесть проверяется тогда, когда данные понадобились. Реализация, которая всё же опрашивает сервер по расписанию, обязана добавлять случайный разброс и увеличивать паузы.

### `cacheScope`

| Значение | Кто может хранить ответ |
|---|---|
| `"public"` | любой клиент, общий шлюз или кэширующий прокси, для любого пользователя |
| `"private"` | только для того же контекста авторизации; делить кэш между разными контекстами нельзя |

Спецификация советует `"public"` для списков, одинаковых у всех пользователей, и `"private"` для чтения ресурсов, зависящих от пользователя, и для списков, отфильтрованных под пользователя.

Ответ с `"public"` может быть отдан другому вызывающему, даже если он получен с адреса, закрытого авторизацией. Сервер обязан применять проверку доступа к каждому инструменту, ресурсу и подсказке отдельно и не должен полагаться на `cacheScope` как на защиту от чужого доступа.

### Что ещё входит в правила

- Ключ кэша - метод и параметры, влияющие на результат. Клиент не должен отдавать сохранённый ответ на запрос с другим методом или параметрами.
- Результаты повторных запросов MRTR, то есть запросов с `inputResponses` или `requestState`, кэшировать нельзя.
- Каждая страница списка кэшируется отдельно и несёт свой `ttlMs`. Сервер обязан ставить один и тот же `cacheScope` на все страницы одного списка.
- Уведомление об изменении списка сразу делает сохранённый ответ устаревшим, даже если срок не вышел.
- Клиент может отдать устаревший ответ, если повторный запрос не удался.

## Порядок инструментов

По странице [Tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) серверу следует возвращать инструменты в одном и том же порядке, пока набор не изменился. Спецификация называет две причины: клиент может надёжно кэшировать список, и чаще срабатывает кэш запроса к языковой модели, когда инструменты входят в её контекст.

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

## Постраничная выдача

По странице [Pagination](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination):

- Размер страницы выбирает сервер. Клиент не должен рассчитывать на постоянный размер.
- Курсор - непрозрачная строка. Клиент обязан не разбирать и не менять его.
- Серверу следует выдавать устойчивые курсоры.

Числа записей на страницу спецификация не называет.

## Размер результата инструмента

Предела на размер результата инструмента в разделе Tools спецификации нет. Есть одно относящееся к делу средство: инструмент может вернуть ссылку на ресурс (`resource_link`), то есть URI, по которому клиент сам запросит данные или подпишется на них. Спецификация не называет это способом уменьшить ответ, она лишь разрешает такой вид результата.

Пределы, которые ставит клиент или языковая модель, протоколом не описаны. Смотрите страницу своего клиента в разделе [Клиенты MCP](https://mcpdoc.ru/reference/clients/).

## Отмена и время ожидания

По странице [Cancellation](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation):

- В Streamable HTTP отмена - это закрытие потока ответа. Сервер обязан считать разрыв соединения клиентом отменой этого запроса.
- В stdio клиент обязан отправить уведомление `notifications/cancelled` с номером запроса.
- Серверу следует прекратить обработку и освободить ресурсы.
- Реализациям следует ставить время ожидания на все отправленные запросы. Уведомление о ходе выполнения может сбрасывать отсчёт, но предельное время следует соблюдать всегда.

Для производительности важен первый пункт. Сервер, который не замечает закрытия потока, продолжает считать ответ, который никто не прочтёт. В Legacy было наоборот: разрыв соединения отменой не считался.

Значений времени ожидания спецификация не задаёт.

## Потоки SSE

По странице [Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http):

- Открывая поток SSE, серверу следует отправить заголовок `X-Accel-Buffering: no`. Без него прокси может копить сообщения и отдавать их с задержкой.
- Для долгих потоков, прежде всего у `subscriptions/listen`, спецификация в примечании предлагает время от времени отправлять строку-комментарий SSE, то есть строку, начинающуюся с двоеточия. Это совет, а не требование. Он не даёт посреднику или клиенту закрыть соединение в тихий период.
- Возобновления потока по `Last-Event-ID` нет. Оборванный поток теряет запрос, и клиент обязан отправить его заново как новый, с новым номером запроса (это требование записано в [перечне изменений редакции](https://modelcontextprotocol.io/specification/2026-07-28/changelog)).

## Практика, не правило MCP

Ниже - общие приёмы эксплуатации. Спецификация MCP их не требует.

### Сначала измерьте

Спецификация не содержит ни одной цифры производительности. Любое число из чужой статьи относится к чужому серверу, чужим инструментам и чужой сети. Прежде чем что-то менять, измерьте свой сервер: время ответа по каждому инструменту, долю отменённых запросов, время до первого события в потоке.

Для проверки запросов к Streamable HTTP [руководство по отладке](https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging) на сайте MCP называет обычные средства HTTP: curl и вкладку сети в инструментах разработчика браузера. Нагрузочный запрос должен быть настоящим запросом Modern: POST на адрес MCP с заголовками `MCP-Protocol-Version`, `Mcp-Method` и, где нужно, `Mcp-Name`. Иначе вы измеряете скорость отказа с кодом 400.

### Буферизация в прокси

По [документации модуля proxy в nginx](https://nginx.org/en/docs/http/ngx_http_proxy_module.html):

- `proxy_buffering` по умолчанию включена, и nginx сначала собирает ответ в буферы. При выключенной буферизации ответ передаётся клиенту сразу по мере получения.
- Заголовок ответа `X-Accel-Buffering` со значением `no` выключает буферизацию для этого ответа. Директива `proxy_ignore_headers` может отключить эту способность.
- `proxy_read_timeout` отсчитывается между двумя чтениями, а не на весь ответ. Если сервер молчит дольше, соединение закрывается. Отсюда польза строк-комментариев в долгом потоке.

### Повторное использование соединений

В Modern каждое сообщение клиента - отдельный POST. Сколько при этом открывается соединений TCP, зависит не от MCP, а от HTTP и от настройки посредников.

По документации nginx директива `proxy_http_version` задаёт версию HTTP для связи с сервером за прокси, и для постоянных соединений рекомендуется версия 1.1 или 2. Директива [`keepalive` в блоке `upstream`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) включает хранение простаивающих соединений с серверами за прокси для повторного использования. Значения по умолчанию у обеих директив менялись между версиями nginx, поэтому сверяйтесь с документацией своей версии.

Не ставьте перед адресом MCP общий кэш ответов HTTP по собственному почину. Кто и что может хранить, определяют `cacheScope` и `ttlMs` внутри результата, а не заголовки HTTP. Спецификация не описывает кэширование POST-запросов MCP средствами HTTP.

## Чего здесь нет и что неизвестно

- Измерений нет: ни числа запросов в секунду, ни объёма памяти, ни рекомендуемых значений времени ожидания. Их нет в спецификации, а чужие числа к вашему серверу не относятся.
- Как каждый клиент пользуется `ttlMs` и `cacheScope` и соблюдает ли он их, по спецификации установить нельзя. Сведения по SDK - в разделе [SDK](https://mcpdoc.ru/sdk/).
- Пределы на размер результата инструмента у клиентов и моделей протоколом не заданы.
- Настройка ядра, пулы соединений с базами данных, очереди и автоматическое масштабирование не рассматриваются: к MCP они отношения не имеют.
- Балансировка сессий Legacy разобрана не здесь, а на странице про сервер для двух эпох.

## Что читать дальше

- [MCP без состояния](https://mcpdoc.ru/protocol/stateless/)
- [Транспорты MCP](https://mcpdoc.ru/protocol/transports/)
- [Streamable HTTP и переход с HTTP+SSE](https://mcpdoc.ru/deployment/http-sse/)
- [Linux](https://mcpdoc.ru/deployment/ubuntu/)
