# Версии и совместимость

Как клиент и сервер договариваются, на каком протоколе говорят

> Страница сайта MCP Docs — неофициального перевода документации Model Context Protocol (https://mcpdocs.ru/protocol/versions/). Тип: Перевод. Основа: Спецификация, раздел «Versioning and Compatibility» (https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning). Ревизия спецификации 2026-07-28, сверено 05.10.2026.

Здесь описано, как клиент и сервер согласуют протокол: версию, объявляемую в каждом запросе, необязательные расширения и совместимость с прежними версиями, где было рукопожатие. **Согласования-рукопожатия больше нет.** Каждый запрос несёт свою версию, а сервер принимает или отклоняет каждый запрос независимо.

## Термины

- **Современные** версии передают версию, идентичность и возможности как метаданные каждого запроса (ревизия 2026-07-28 и новее).
- **Прежние** версии устанавливают сессию рукопожатием `initialize` (2025-11-25 и ранее).
- **Двухэпохная** реализация поддерживает и современные, и прежние версии.

> **Заметка переводчика.** В оригинале эти три понятия называются modern, legacy и dual-era. Мы называем их «современные», «прежние» и «двухэпохные» и пишем «эпоха» там, где речь о принадлежности к группе версий.

## Согласование версии

Каждый запрос объявляет версию в `_meta`, а по HTTP ещё и в заголовке `MCP-Protocol-Version` ([подробнее](https://mcpdocs.ru/protocol/transports/#zagolovok-versii-protokola)). Если сервер не реализует запрошенную версию (неизвестную ему или известную, но отключённую), он ДОЛЖЕН ответить ошибкой `UnsupportedProtocolVersionError` со списком поддерживаемых версий:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32022,
    "message": "Unsupported protocol version",
    "data": {
      "supported": ["2026-07-28", "2025-11-25"],
      "requested": "1900-01-01"
    }
  }
}
```

Клиенту СЛЕДУЕТ выбрать из `supported` общую версию и повторить запрос либо показать пользователю ошибку, если совместимой версии нет.

Серверы ДОЛЖНЫ реализовывать [`server/discover`](https://mcpdocs.ru/concepts/discovery/). Клиенты МОГУТ вызвать его до других запросов, чтобы заранее узнать версии, но не обязаны: можно сразу вызвать любой метод и обработать `UnsupportedProtocolVersionError`.

## Согласование расширений

Клиенты и серверы могут договариваться о необязательных [расширениях](https://modelcontextprotocol.io/docs/extensions/overview). Расширения объявляются в поле `extensions` возможностей. Это словарь «идентификатор расширения → настройки». Идентификатор ДОЛЖЕН подчиняться [правилам именования ключей `_meta`](https://mcpdocs.ru/protocol/#format-imen-klyuchey) с обязательным префиксом.

Пример клиента, который объявляет расширение MCP Apps (`io.modelcontextprotocol/ui`):

```json
{
  "capabilities": {
    "roots": {},
    "extensions": {
      "io.modelcontextprotocol/ui": {
        "mimeTypes": ["text/html;profile=mcp-app"]
      }
    }
  }
}
```

Пример расширения Tasks (`io.modelcontextprotocol/tasks`):

```json
{
  "capabilities": {
    "tools": {},
    "extensions": {
      "io.modelcontextprotocol/tasks": {}
    }
  }
}
```

Каждое расширение определяет схему своих настроек, а пустой объект значит поддержку без дополнительных настроек. Если одна сторона поддерживает расширение, а другая нет, поддерживающая сторона ДОЛЖНА либо вернуться к поведению базового протокола, либо отклонить запрос подходящей ошибкой. Расширениям СЛЕДУЕТ описывать, как они ведут себя в таком случае.

## Совместимость с версиями на основе рукопожатия

Сервер, который хочет поддерживать и прежних клиентов (ждущих `initialize`), и современных (с метаданными в запросах), МОЖЕТ реализовать оба поведения. Клиент, которому нужно работать с серверами обоих видов, определяет эпоху сервера способом, зависящим от транспорта.

- **stdio.** Отправить пробный `server/discover` и откатиться, если пришла любая ошибка, не распознанная как современная.
- **Streamable HTTP.** Отправить современный запрос и при `400 Bad Request` проверить тело, прежде чем откатываться ([подробнее](https://mcpdocs.ru/protocol/transports/#obratnaya-sovmestimost)).

В обоих случаях распознанная современная ошибка JSON-RPC (например, `UnsupportedProtocolVersionError`) означает современный сервер: нужно повторить запрос с поддерживаемой версией, а не откатываться. Всё остальное означает прежний сервер.

Эпоха — свойство сервера, а не отдельного запроса. Клиентам СЛЕДУЕТ кэшировать результат на время жизни процесса сервера (stdio) или источника (HTTP) и МОГУТ сохранять его между перезапусками той же конфигурации, повторяя пробу, если предположение перестало работать.

Сервер, который поддерживает только современные версии, СЛЕДУЕТ называть поддерживаемые версии в любой ошибке на запрос `initialize`, на любом транспорте: у прежних клиентов нет способа перейти вперёд, и это сообщение может оказаться единственным, что они смогут показать пользователю.

## Матрица совместимости

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



Та же матрица в виде таблицы:

| Клиент | Сервер | Итог |
| --- | --- | --- |
| Современный | Современный | Работает. `server/discover` необязателен; несовпадение версий возвращается как `UnsupportedProtocolVersionError`, и клиент повторяет запрос с общей версией. |
| Современный | Прежний | Не работает. Сервер может отклонить запрос по-своему, промолчать или даже обработать неоднозначный по эпохе метод по прежним правилам. На stdio клиентам СЛЕДУЕТ отправить `server/discover` первым, чтобы отказ был предсказуемым. Затем клиент показывает пользователю понятную ошибку. |
| Двухэпохный | Современный | Работает. Проба на stdio возвращает `DiscoverResult` (или `UnsupportedProtocolVersionError`); по HTTP первый современный запрос проходит или возвращает современную ошибку. Клиент остаётся современным. |
| Двухэпохный | Прежний | Работает. stdio: проба возвращает не-современную ошибку или молчит, клиент возвращается к `initialize`. HTTP: современный запрос получает `4xx` без распознанной современной ошибки, клиент возвращается к `initialize` (и, возможно, дальше к устаревшему HTTP+SSE). |
| Прежний | Современный | Не работает. stdio: сервер отвечает на `initialize` ошибкой JSON-RPC, код зависит от реализации. HTTP: запрос без обязательных заголовков отклоняется статусом `400 Bad Request` (клиент на HTTP+SSE споткнётся уже на начальном GET). У прежних клиентов нет способа перейти вперёд. |
| Прежний | Двухэпохный | Работает. Сервер отвечает на `initialize` и обслуживает клиента по согласованной прежней ревизии. |
| Прежний | Прежний | Работает по правилам прежней ревизии; вне рамок этого документа. |

Двухэпохный **сервер** выбирает поведение по тому, как клиент начинает обмен. Запрос с современными `_meta` обслуживается без состояния по этой ревизии. Запрос `initialize` выбирает прежние правила, ограниченные процессом stdio или сессией HTTP по согласованной прежней версии. Такой сервер МОЖЕТ обслуживать обе эпохи одновременно на одной конечной точке или в одном процессе.

> **Заметка переводчика.** В таблице спецификации нет строк «современный клиент — двухэпохный сервер» и «двухэпохный клиент — двухэпохный сервер», поэтому на схеме эти ячейки пустые. Из описания двухэпохного сервера логично, что клиент любой эпохи с ним работает, но это вывод, а не норма.
