Skip to content

Commit 4f6bbfa

Browse files
committed
[Client] Default to protocol version 2026-07-28
1 parent fac34d0 commit 4f6bbfa

14 files changed

Lines changed: 61 additions & 28 deletions

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ All notable changes to `mcp/sdk` will be documented in this file.
2828
* Serve both protocol eras over stdio: `StdioTransport` settles the era on the client's first request and serves `2026-07-28` requests, `subscriptions/listen` and `notifications/cancelled` on the one channel.
2929
* Answer a bare `initialize` on a `2026-07-28`-only endpoint with `-32022` naming the served revisions, and a request without a session on the handshake leg with its id.
3030
* Speak both protocol eras from a client configured with `2026-07-28`: `connect()` probes with `server/discover` and falls back to the `initialize` handshake on `2025-11-25` when the server does not speak the modern era. `Builder::setFallbackProtocolVersion()` picks the fallback revision, or `null` for a modern-only client.
31+
* [BC Break] Bump the client's default protocol version to `2026-07-28`, so a client speaks both protocol eras unless told otherwise. Against a server that speaks both, a default client now settles on `2026-07-28`, which removed sampling and roots; call `Builder::setProtocolVersion(ProtocolVersion::V2025_11_25)` to keep them.
3132
* On a `2026-07-28` connection, `Client::setLoggingLevel()` stamps the level on every following request, `Client::ping()` sends `server/discover` and `Client::sendRootsListChanged()` sends nothing.
3233
* Fail a client request at once when the HTTP server refuses it with an error status or the stdio server process exits, instead of waiting out the timeout.
3334

‎docs/client/connecting.md‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,34 +61,33 @@ $client = Client::builder()
6161

6262
### Protocol Version
6363

64-
Specify the MCP protocol version to speak (defaults to `V2025_11_25`). A handshake revision opens with `initialize`:
65-
66-
```php
67-
use Mcp\Schema\Enum\ProtocolVersion;
68-
69-
$client = Client::builder()
70-
->setProtocolVersion(ProtocolVersion::V2025_11_25)
71-
->build();
72-
```
73-
74-
A modern revision makes the client speak both protocol eras: it probes for `2026-07-28` with `server/discover` when
64+
A client speaks both protocol eras by default. It prefers `2026-07-28`, probes for it with `server/discover` when
7565
connecting, and falls back to the `initialize` handshake on `2025-11-25` when the server turns out not to speak it.
7666
Use `$client->getProtocolVersion()` after connecting to read what the connection settled on.
7767

7868
```php
69+
use Mcp\Schema\Enum\ProtocolVersion;
70+
7971
// Fall back to an older handshake revision instead of 2025-11-25…
8072
$client = Client::builder()
81-
->setProtocolVersion(ProtocolVersion::V2026_07_28)
8273
->setFallbackProtocolVersion(ProtocolVersion::V2025_06_18)
8374
->build();
8475

8576
// …or not at all, refusing servers without the modern era.
8677
$client = Client::builder()
87-
->setProtocolVersion(ProtocolVersion::V2026_07_28)
8878
->setFallbackProtocolVersion(null)
8979
->build();
9080
```
9181

82+
Passing a handshake revision to `setProtocolVersion()` skips the probe and opens with `initialize`, the way a client
83+
from before the modern era would:
84+
85+
```php
86+
$client = Client::builder()
87+
->setProtocolVersion(ProtocolVersion::V2025_11_25)
88+
->build();
89+
```
90+
9291
The handshake is an offer, not a demand. A server that does not support the requested revision counter-offers one it
9392
does, as described in the specification's
9493
[protocol version negotiation](https://modelcontextprotocol.io/specification/latest/basic/versioning#protocol-version-negotiation)

‎docs/protocol-versions.md‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,13 @@ either lifecycle. What changes:
106106

107107
## Speaking it from a client
108108

109-
Ask for `2026-07-28` and the client speaks both eras: it finds out on `connect()` whether
110-
the server does too, and nothing about the [client API](client/index.md) depends on the
111-
answer.
109+
A client speaks both eras out of the box. It prefers `2026-07-28`, and finds out on
110+
`connect()` whether the server does too; nothing about the [client API](client/index.md)
111+
depends on the answer.
112112

113113
```php
114114
$client = Client::builder()
115115
->setClientInfo('my-client', '1.0.0')
116-
->setProtocolVersion(ProtocolVersion::V2026_07_28)
117116
->setCapabilities(new ClientCapabilities(elicitation: true))
118117
->addRequestHandler($myElicitationHandler)
119118
->build();

‎src/Client/Builder.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function setClientInfo(string $name, string $version, ?string $descriptio
6969
/**
7070
* Set the protocol version the client prefers.
7171
*
72-
* Defaults to 2025-11-25. A modern revision is probed for with
72+
* Defaults to 2026-07-28. A modern revision is probed for with
7373
* `server/discover` and falls back to the `initialize` handshake when the
7474
* server turns out not to speak it, see {@see self::setFallbackProtocolVersion()};
7575
* a handshake revision skips the probe and opens with the handshake.
@@ -218,7 +218,7 @@ public function build(): Client
218218
$config = new Configuration(
219219
clientInfo: $clientInfo,
220220
capabilities: $capabilities,
221-
protocolVersion: $this->protocolVersion ?? ProtocolVersion::V2025_11_25,
221+
protocolVersion: $this->protocolVersion ?? ProtocolVersion::V2026_07_28,
222222
initTimeout: $this->initTimeout,
223223
requestTimeout: $this->requestTimeout,
224224
maxRetries: $this->maxRetries,

‎src/Client/Configuration.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Configuration
3434
public function __construct(
3535
public readonly Implementation $clientInfo,
3636
public readonly ClientCapabilities $capabilities,
37-
public readonly ProtocolVersion $protocolVersion = ProtocolVersion::V2025_11_25,
37+
public readonly ProtocolVersion $protocolVersion = ProtocolVersion::V2026_07_28,
3838
public readonly int $initTimeout = 30,
3939
public readonly int $requestTimeout = 120,
4040
public readonly int $maxRetries = 3,

‎src/Schema/JsonRpc/MessageInterface.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
interface MessageInterface extends \JsonSerializable
2222
{
2323
public const JSONRPC_VERSION = '2.0';
24-
public const PROTOCOL_VERSION = ProtocolVersion::V2025_11_25;
24+
public const PROTOCOL_VERSION = ProtocolVersion::V2026_07_28;
2525
}

‎src/Schema/Result/InitializeResult.php‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Mcp\Exception\InvalidArgumentException;
1515
use Mcp\Schema\Enum\ProtocolVersion;
1616
use Mcp\Schema\Implementation;
17-
use Mcp\Schema\JsonRpc\MessageInterface;
1817
use Mcp\Schema\JsonRpc\Response;
1918
use Mcp\Schema\JsonRpc\ResultInterface;
2019
use Mcp\Schema\ServerCapabilities;
@@ -91,7 +90,7 @@ public static function fromArray(array $data): self
9190
*/
9291
public function jsonSerialize(): array
9392
{
94-
$protocolVersion = $this->protocolVersion ?? MessageInterface::PROTOCOL_VERSION;
93+
$protocolVersion = $this->protocolVersion ?? ProtocolVersion::latestHandshake();
9594
$data = [
9695
'protocolVersion' => $protocolVersion->value,
9796
'capabilities' => $this->capabilities,

‎tests/Integration/ElicitationTest.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ public function testAdvertisedCapabilityWithoutHandler(): void
8282
// with an error, see below.
8383
$client = $this->connect(
8484
'elicitation',
85-
$this->clientBuilder()->setCapabilities(new ClientCapabilities(elicitation: true)),
85+
$this->clientBuilder()
86+
->setProtocolVersion(ProtocolVersion::V2025_11_25)
87+
->setCapabilities(new ClientCapabilities(elicitation: true)),
8688
);
8789

8890
$result = $client->callTool('ask_name');

‎tests/Integration/HandshakeTest.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ public function testNegotiatedVersion(?ProtocolVersion $clientVersion, ?Protocol
4747
*/
4848
public static function provideNegotiations(): iterable
4949
{
50-
yield 'both unconfigured' => [null, null, ProtocolVersion::latestHandshake()];
50+
// Both ends speak both eras, so they settle on the modern one.
51+
yield 'both unconfigured' => [null, null, ProtocolVersion::V2026_07_28];
52+
yield 'server without the modern era, client unconfigured' => [null, null, ProtocolVersion::V2025_11_25, true];
5153

5254
// Whichever end of the supported range it sits at.
5355
foreach (ProtocolVersion::handshakeVersions() as $version) {

‎tests/Integration/RootsTest.php‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Mcp\Client\Handler\Request\RootsCallbackInterface;
1717
use Mcp\Schema\ClientCapabilities;
1818
use Mcp\Schema\Content\TextContent;
19+
use Mcp\Schema\Enum\ProtocolVersion;
1920
use Mcp\Schema\Request\ListRootsRequest;
2021
use Mcp\Schema\Result\ListRootsResult;
2122
use Mcp\Schema\Root;
@@ -28,6 +29,15 @@
2829
*/
2930
final class RootsTest extends IntegrationTestCase
3031
{
32+
/**
33+
* Roots exists only on the handshake era: 2026-07-28 removed it, so a
34+
* client and server that could both settle on the modern era are kept off it.
35+
*/
36+
protected function clientBuilder(): ClientBuilder
37+
{
38+
return parent::clientBuilder()->setProtocolVersion(ProtocolVersion::V2025_11_25);
39+
}
40+
3141
#[TestDox('the roots the client exposes reach the tool that asked')]
3242
public function testRootsReachTheTool(): void
3343
{

0 commit comments

Comments
 (0)