Легаси-спецификация
legacy-spec — это опциональный флаг Cargo, возвращающий поколение
протокола до 2026-07-28, то есть MCP 2024-11-05 … 2025-11-25.
[dependencies]
neva = { version = "0.5", features = ["server-full", "legacy-spec"] }
Это переключатель поколения, а не добавка: его включение компилирует поверхность MCP 2026-07-28 прочь. Два поколения никогда не сосуществуют в одной сборке.
--all-features выбирает легаси-профильФлаги Cargo аддитивны, поэтому --all-features включает legacy-spec и,
следовательно, проверяет именно легаси-профиль. Профилю по умолчанию нужен
явный список флагов — например, --features "server-full client-full" или
--features full. По той же причине docs.rs публикует neva с
features = ["full"], а не со всеми флагами.
Переход на 0.5.0
| Что было в 0.4.x | Что делать |
|---|---|
features = ["proto-2026-07-28-rc"] | Убрать флаг. Его больше не существует — то, что он включал, теперь работает по умолчанию. |
| Поведение по умолчанию (без флага протокола) | Добавить legacy-spec, чтобы сохранить прежний протокол, либо перейти на MCP 2026-07-28. |
Помимо флага стоит проверить следующие изменения в коде:
- Задачи —
opt.with_tasks()не принимает замыкание;list_tasks()удалён (вместо него опрашивайтеtasks/get);Task::ttlсериализуется какttlMsи теперь имеет типOption<usize>. См. Задачи. - Результаты — каждый успешный результат теперь несёт
resultType. Если вы разбираете сырые ответы, читайте его черезResponse::result_type(). - Адаптеры HTTP-движков —
SseResponseпереименован вStreamResponse(вариантStatus— вComplete), аhandlers::dispatch_postвозвращаетStreamResponse<…>вместо обычного ответа. См. Собственный HTTP-стек. Устаревший псевдонимSseResponseсохраняется на один релиз. - Удалённые вызовы —
ping,complete_elicitation,on_elicitation_completed,with_logging/set_log_level. - Подписки на ресурсы —
resources/subscribe/resources/unsubscribeсвёрнуты в фильтрsubscriptions/listen. Заменитеclient.subscribe_to_resource(uri)наclient.listen(SubscriptionFilter::new().with_resource(uri)), а из серверных обработчиков уберитеctx.subscribe_to_resource(..)— подпиской теперь владеет клиент. См. Подписки. - Сэмплирование и корневые каталоги — по-прежнему доступны, но как
виды input-запросов MRTR
и с пометкой
#[deprecated]. Атрибутный макрос#[sampling]относится к легаси-модели с серверным пушем и в сборке по умолчанию недоступен — регистрируйте обработчик черезmap_sampling.
Что возвращает legacy-spec
| Область | Легаси-поведение |
|---|---|
| Рукопожатие | initialize / initialized, с serverInfo в InitializeResult |
| Транспорт | Streamable HTTP с сессиями: Mcp-Session-Id, DELETE сессии, отдельный SSE-поток GET с воспроизведением по Last-Event-ID |
| Возобновление потока | Оборвавшийся поток ответа на POST возобновляется один раз — запросом GET с Last-Event-ID после паузы, о которой попросил сервер, и только если сервер назвал идентификатор, с которого продолжать. У каждого потока свой курсор и своя задержка переподключения, взятая из поля SSE retry: этого потока, а не фиксированные три секунды |
| Выбор версии | with_mcp_version(...) на сервере |
| Запросы сервер→клиент | Пуш, управляемый возможностями, для sampling/createMessage, roots/list, elicitation/create — без MRTR |
| Макросы | Атрибутный макрос #[sampling] |
| Логирование | logging/setLevel, а также with_logging(handle) и глобальный путь отправки notifications/message |
| Инструменты | Легаси-тип ToolSchema (не JSON Schema 2020-12) |
| Задачи | Поверхность 2025-11-25: tasks/list, tasks/result, поддерево возможностей cancel/list/requests, with_tasks(|t| …), задачи на стороне клиента |
| Уведомления | ping, notifications/roots/list_changed, notifications/elicitation/complete |
| Подписки | Пара RPC-методов resources/subscribe / resources/unsubscribe, Context::subscribe_to_resource / unsubscribe_from_resource и resource::commands::{SUBSCRIBE, UNSUBSCRIBE} — состояние подписки на сервере вместо потока subscriptions/listen |
| Запросы | Нет обязательных ключей _meta, нет проверки заголовков маршрутизации, нет resultType |
Всё остальное — DI, промежуточные обработчики, типы содержимого, JWT-аутентификация, TLS, собственные HTTP-движки, батч-запросы — общее для обоих поколений и ведёт себя одинаково.
Работа с легаси-узлом без legacy-spec
На стороне клиента флаг обычно не нужен. Клиент в сборке по умолчанию
работает в двойном режиме: он открывает соединение через
server/discover и, если узел явно не понимает MCP 2026-07-28, откатывается
к рукопожатию initialize и до конца соединения говорит с ним на старом
протоколе. См.
Discovery вместо рукопожатия.
На сервере такого отката нет — он определяется на этапе компиляции.
Серверу, который должен обслуживать легаси-клиентов, нужна сборка с
legacy-spec.
Примеры
Легаси-варианты примеров с корневыми каталогами и сэмплированием лежат в
подкаталоге legacy/, каждый — отдельное рабочее пространство Cargo (Cargo
объединяет флаги для участников, собираемых вместе, поэтому общее рабочее
пространство переключило бы поколение для всех крейтов в нём):