# MCP PHP SDK: установка, версии и редакции протокола

> Официальный PHP SDK для MCP, пакет mcp/sdk 0.8.1 - сервер отвечает обеим эпохам с одного адреса, клиент по умолчанию говорит на 2025-11-25, SDK ещё не достиг версии 1.0

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

PHP SDK - официальный SDK третьего уровня (Tier 3), пакет Composer `mcp/sdk`. Выпуск 0.8.1 понимает редакцию `2026-07-28` и четыре предыдущие. Сервер отвечает клиентам обеих эпох с одного адреса без настройки. Клиент по умолчанию предлагает `2025-11-25`, а редакцию `2026-07-28` нужно выбрать явно. До версии 1.0 SDK называет себя экспериментальным.

сверено с выпуском 0.8.1 4 октября 2026

Совместимость Dual-era работает с обеими эпохами и выбирает по собеседнику

- **Проверенная версия:** 0.8.1, выпуск от 2026-08-29

- **Новейшая поддерживаемая редакция:** 2026-07-28

- **С сервером только Modern:** работает

- **С сервером только Legacy:** работает

- **Переход на старую редакцию:** вручную

- **Использует устаревшее:** Roots, Sampling, Logging, динамическая регистрация клиента (DCR)

- **Сохраняет удалённое в редакции 2026-07-28:** сессии, рукопожатие initialize

- **Расширение Tasks:** нет

- **Расширение MCP Apps:** частично

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

- **Источник:** [github.com](https://github.com/modelcontextprotocol/php-sdk/releases/tag/v0.8.1)

## Что это

По [README выпуска](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/README.md) это официальный PHP SDK для MCP, не привязанный к какой-либо программной платформе: серверы и клиенты, транспорты stdio и HTTP, обе эпохи протокола.

README называет и тех, кто ведёт проект: это совместная работа The PHP Foundation и проекта Symfony. Проект следует стандартам кода Symfony и его обещанию обратной совместимости.

В [списке официальных SDK](https://modelcontextprotocol.io/docs/sdk) у PHP третий уровень (Tier 3). По [правилам уровней](https://modelcontextprotocol.io/community/sdk-tiers) третий уровень - это экспериментальные, частично реализованные или специализированные SDK.

README: «Until the first major release, this SDK is considered experimental». По [правилам устаревания SDK](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/deprecation-policy.md) до версии 1.0 открытый интерфейс может меняться без периода устаревания. В журнале изменений такие правки помечены «BC Break».

## Выпуск и установка

Проверенный выпуск - 0.8.1 от 29 августа 2026: [выпуск на GitHub](https://github.com/modelcontextprotocol/php-sdk/releases/tag/v0.8.1), пакет [`mcp/sdk`](https://packagist.org/packages/mcp/sdk) на Packagist. Помеченных предварительных выпусков нет.

По [руководству по установке](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/get-started/installation.md) нужны PHP 8.1 или новее и расширение `fileinfo`.

```bash title="Установка"
composer require mcp/sdk
```

Этого хватает для сервера и клиента на stdio. Остальное ставится по задаче:

| Что нужно | Что доставить |
|---|---|
| искать `#[McpTool]` и другие атрибуты в каталоге | `symfony/finder` |
| сервер по HTTP | любую реализацию PSR-17, например `nyholm/psr7` |
| отдать ответ из отдельной точки входа HTTP | `laminas/laminas-httphandlerrunner` |
| клиент по HTTP | любой клиент PSR-18, например `symfony/http-client` |
| проверять токены доступа JWT | `firebase/php-jwt` |

## Какие редакции понимает выпуск

Список записан в [`ProtocolVersion.php`](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/src/Schema/Enum/ProtocolVersion.php): `2024-11-05`, `2025-03-26`, `2025-06-18`, `2025-11-25`, `2026-07-28`. Граница эпох задана константой `FIRST_MODERN_VERSION`, она равна `2026-07-28`.

По [журналу изменений](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/CHANGELOG.md) редакция `2026-07-28` появилась в выпуске 0.8.0.

Для вас это значит следующее. Сервер на этом выпуске обслуживает и клиента Modern, и клиента Legacy. Клиент на этом выпуске умеет обе эпохи, но не выбирает между ними сам: эпоху задаёте вы.

## Что клиент отправляет по умолчанию

По [документации клиента](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/client/connecting.md) клиент по умолчанию предлагает в рукопожатии `V2025_11_25`. Редакцию `2026-07-28` нужно выбрать явно.

Клиент с настройками по умолчанию начинает с `initialize`. К серверу, который понимает только Modern, он так не подключится. Чтобы работать с таким сервером, задайте редакцию `2026-07-28` явно.

```php title="Клиент в эпохе Modern"
$client = Client::builder()
    ->setClientInfo('my-client', '1.0.0')
    ->setProtocolVersion(ProtocolVersion::V2026_07_28)
    ->setCapabilities(new ClientCapabilities(elicitation: true))
    ->addRequestHandler($myElicitationHandler)
    ->build();

$client->connect(new HttpTransport('https://example.com/mcp'));

$client->callTool('greet', []);
```

Пример взят из документации выпуска 0.8.1 и здесь не запускался.

Что при этом меняется, описано в [документации о версиях](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/protocol-versions.md):

- `connect()` не отправляет `initialize`. Клиент запрашивает `server/discover` только ради сведений о сервере. Если сервер на этот запрос не ответил, соединение всё равно считается рабочим.
- Если ответ `server/discover` содержит `supportedVersions` и выбранной редакции там нет, клиент переходит на редакцию Modern из списка сервера или отказывается от соединения.
- Перехода на `initialize` при неудаче нет. В [коде клиента](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/src/Client/Protocol.php) отказ `server/discover` записывается в журнал, и работа продолжается в эпохе Modern.

В старой эпохе выбранная версия - это предложение. Клиент принимает встречное предложение сервера, если знает такую редакцию. Иначе рукопожатие завершается ошибкой `ConnectionException`.

## Что принимает сервер

По [описанию работы с двумя эпохами](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/run/protocol-eras.md) `Server::builder()->build()` собирает сервер с обработчиком для каждой эпохи, а `StreamableHttpTransport` решает по каждому запросу, какой из них ответит. Один адрес отвечает и на `initialize`, и на `server/discover`.

Решение принимается по телу запроса:

| Что в запросе | Куда он попадает |
|---|---|
| `params._meta` называет редакцию Modern | эпоха Modern |
| `params._meta` называет редакцию рукопожатия | эпоха Legacy |
| такого поля нет | эпоха Legacy, включая `initialize` |
| запрос `GET` или `DELETE` | эпоха Legacy |

Заголовок `MCP-Protocol-Version` решения не принимает. Он сверяется с телом. Запрос, в котором заголовок противоречит `_meta`, отклоняется с кодом `-32020`. Неподдерживаемая версия отклоняется с кодом `-32022` и списком поддерживаемых.

Рукопожатие не договаривается о версии Modern. Клиенту, который просит в `initialize` версию `2026-07-28`, сервер предложит последнюю версию рукопожатия.

Оставить одну эпоху можно так:

- `withoutModernEra()` - сервер только старой эпохи;
- `buildStateless()` вместе со `StatelessHttpTransport` - адрес только эпохи Modern;
- `setModernVersions()` - сузить список редакций Modern.

## Минимальный сервер

```php title="server.php"
use Mcp\Capability\Attribute\McpResource;
use Mcp\Capability\Attribute\McpTool;
use Mcp\Server;
use Mcp\Server\Transport\StdioTransport;

class Calculator
{
    /**
     * Adds two numbers.
     */
    #[McpTool]
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }

    #[McpResource(uri: 'config://calculator/settings')]
    public function settings(): array
    {
        return ['precision' => 2];
    }
}

exit(Server::builder()
    ->setServerInfo('Calculator', '1.0.0')
    ->setDiscovery(__DIR__, ['.'], excludeDirs: ['vendor'])
    ->build()
    ->run(new StdioTransport()));
```

Пример взят из документации выпуска 0.8.1 и здесь не запускался.

Метод `setDiscovery()` ищет атрибуты в каталоге, для этого нужен пакет `symfony/finder`.

## Минимальный клиент

```php title="client.php"
use Mcp\Client;
use Mcp\Client\Transport\StdioTransport;

$client = Client::builder()
    ->setClientInfo('My Application', '1.0.0')
    ->build();

$client->connect(new StdioTransport(command: 'php', args: ['/path/to/server.php']));

$tools = $client->listTools();
$result = $client->callTool('add', ['a' => 5, 'b' => 3]);

$client->disconnect();
```

Пример взят из документации выпуска 0.8.1 и здесь не запускался.

Этот клиент не задаёт редакцию, поэтому начинает с `initialize` и предлагает `2025-11-25`.

## Расширения

**Tasks.** В выпуске не реализовано. В [плане развития](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/ROADMAP.md) пункт «Implement the Tasks extension» не отмечен как выполненный.

**MCP Apps.** Есть типы и средства для сервера. По [документации расширений](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/advanced/extensions.md) сервер включает расширение вызовом `enableExtension(new McpApps())`, описывает ресурс с адресом `ui://` и связывает с ним инструмент. Клиент может объявить расширение через `Client\Builder::enableExtension()`. Показ интерфейса в изолированной рамке - задача программы-хоста, готового средства для этого документация выпуска не описывает. Поэтому в блоке совместимости стоит «частично».

## Устаревшие функции в выпуске

| Функция | Как с ней обходится выпуск 0.8.1 |
|---|---|
| Roots, Sampling, Logging | Помечены устаревшими и выдают предупреждение, но работают. Журнал изменений называет самый ранний срок удаления - 28 июля 2027. На редакции `2026-07-28` вызовы `sample()` и `listRoots()` бросают `LogicException` |
| `initialize` и сеансы | Работают для клиентов старой эпохи. [Документация о сеансах](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/run/sessions.md): сеансы относятся к эпохе рукопожатия, редакция `2026-07-28` их убрала |
| Динамическая регистрация клиента (RFC 7591) | На стороне сервера есть `ClientRegistrationMiddleware` |
| HTTP+SSE из `2024-11-05` | В выпуске не реализован. [Документ об уровне SDK](https://github.com/modelcontextprotocol/php-sdk/blob/v0.8.1/docs/sdk-tier.md) относит его к пробелам, которые нужно либо реализовать, либо явно назвать намеренно пропущенными |

Авторизация OAuth в SDK не завершена. В плане развития пункты «Implement OAuth2 authentication for server» и «Implement OAuth2 authentication for client» не отмечены как выполненные. Документ об уровне SDK сообщает о результатах проверки соответствия: сервер - 100%, клиент - 20%, почти все провалы клиента относятся к OAuth. Этот документ написан до выпуска 0.8.x: последней версией в нём названа 0.7.1.

## Выпуск и ветка main

На 4 октября 2026 ветка `main` опережает метку `v0.8.1` на 13 изменений. Список редакций в `ProtocolVersion.php` там тот же. В журнале изменений на `main` есть раздел 0.9.0, который ещё не выпущен. В нём, например, удалён один из аргументов атрибута `#[CompletionProvider]` и добавлен метод `HttpTransport::getSessionId()`.

## Что неизвестно

- Когда выйдет версия 1.0: план развития перечисляет цели, но сроков не называет.
- Текущие результаты проверки соответствия для выпуска 0.8.1: опубликованные в документации цифры относятся к более раннему состоянию.
- Как сервер на stdio выбирает эпоху: документация выпуска описывает разбор запросов только для `StreamableHttpTransport`.

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

- [Все SDK](https://mcpdoc.ru/sdk/) - сравнение официальных SDK по эпохам.
- [Две эпохи на одном сервере](https://mcpdoc.ru/deployment/dual-era/) - как обслуживать старых и новых клиентов.
- [Ядро без состояния](https://mcpdoc.ru/protocol/stateless/) - поля `_meta`, которые несёт каждый запрос Modern.
- [Устаревшие функции](https://mcpdoc.ru/protocol/deprecations/) - сроки для Roots, Sampling и Logging.
