Repository navigation
[Client][Server] Negotiate 2026-07-28 across both eras on stdio and HTTP - #537
Closed
chr-hertel wants to merge 17 commits into
Closed
chr-hertel wants to merge 17 commits into
chr-hertel wants to merge 17 commits into
Conversation
2026-07-28 across both eras on stdio and HTTP
chr-hertel
marked this pull request as ready for review
October 6, 2026 23:04
chr-hertel
requested review from
CodeWithKyrian,
Nyholm and
soyuka
as code owners
October 6, 2026 23:04
benjaminkott
added a commit
to TYPO3/dev-companion
that referenced
this pull request
Oct 7, 2026
The Skills extension declares itself in the answer to server/discover, which the server refused over stdio. The transport now takes the SDK's modern dispatcher and settles the era on the first request. It follows modelcontextprotocol/php-sdk#537 in behaviour and names, so that release replaces the class. D-ANS-175 lists where it differs, and revokes D-ANS-172.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Transport correlation, pending-request cleanup, stream ID handling, and disconnected logging behavior contain unresolved bugs.
5 open findings
Abort suspended request to clear stale client state · New Reject envelope updates when the client is disconnected · New Require exact response ID match before dispatching · New Use type-preserving keys for cancellation lookup and removal · New Split builder calls for separate configuration examples · New
What changed in this PR
Adds dual-era MCP negotiation across stdio and HTTP, preferring 2026-07-28 while retaining handshake compatibility.
Changes:
- Adds modern-protocol probing with configurable handshake fallback.
- Enables dual-era stdio routing, streaming, and cancellation.
- Updates client behavior, tests, fixtures, and documentation for both eras.
| File | Description |
|---|---|
| tests/Unit/Server/Transport/StdioDualEraTest.php | Tests dual-era stdio routing and streams. |
| tests/Unit/Server/Stateless/StatelessProtocolTest.php | Tests inline modern requests and refusals. |
| tests/Unit/Server/ProtocolTest.php | Verifies request IDs on session errors. |
| tests/Unit/Client/Transport/StdioTransportTest.php | Tests dead-process handling. |
| tests/Unit/Client/Transport/HttpTransportTest.php | Tests HTTP probe refusal handling. |
| tests/Unit/Client/ProtocolTest.php | Covers negotiation and fallback behavior. |
| tests/Unit/Client/ConfigurationTest.php | Tests new protocol defaults. |
| tests/Integration/SamplingToolsTest.php | Pins sampling tools to handshake mode. |
| tests/Integration/SamplingTest.php | Covers sampling across era boundaries. |
| tests/Integration/RootsTest.php | Pins roots tests to handshake mode. |
| tests/Integration/NotificationTest.php | Tests notifications across both eras. |
| tests/Integration/IntegrationTestCase.php | Adds shared era datasets. |
| tests/Integration/HttpNegotiationTest.php | Adds HTTP negotiation coverage. |
| tests/Integration/HandshakeTest.php | Expands stdio negotiation coverage. |
| tests/Integration/Fixture/http.php | Adds dual-era HTTP fixture. |
| tests/Integration/Fixture/handshake.php | Adds handshake-only fixture mode. |
| tests/Integration/ElicitationTest.php | Tests modern elicitation failures. |
| src/Server/Transport/StdioTransport.php | Routes stdio traffic by protocol era. |
| src/Server/Stateless/StatelessProtocol.php | Supports headerless inline dispatch. |
| src/Server/Protocol.php | Correlates missing-session errors. |
| src/Schema/Result/InitializeResult.php | Retains handshake initialization default. |
| src/Schema/JsonRpc/MessageInterface.php | Changes the default protocol revision. |
| src/Client/Transport/StdioTransport.php | Detects terminated server processes. |
| src/Client/Transport/HttpTransport.php | Converts HTTP refusals into responses. |
| src/Client/Stateless/RequestEnvelope.php | Adds per-request logging level metadata. |
| src/Client/Protocol.php | Implements probing and fallback negotiation. |
| src/Client/Configuration.php | Adds modern defaults and fallback configuration. |
| src/Client/Builder.php | Exposes fallback configuration. |
| src/Client.php | Adapts ping, logging, and roots behavior. |
| examples/server/bootstrap.php | Documents dual-era stdio examples. |
| docs/run/protocol-eras.md | Documents stdio era routing. |
| docs/protocol-versions.md | Documents client negotiation behavior. |
| docs/client/connecting.md | Updates connection configuration guidance. |
| CHANGELOG.md | Records behavior and compatibility changes. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+270
to
+272
| if (feof($this->stdout)) { | ||
| throw new ConnectionException('The server process closed its output; it is no longer running.'); | ||
| } |
Comment on lines
+211
to
+215
| if (\is_array($answer) && \array_key_exists('id', $answer) && null !== $answer['id']) { | ||
| $this->handleMessage($body); | ||
|
|
||
| return; | ||
| } |
Comment on lines
+229
to
+232
| if ((\is_string($requestId) || \is_int($requestId)) && isset($this->streams[$requestId])) { | ||
| unset($this->streams[$requestId]); | ||
| $this->logger->debug('StdioTransport dropped a cancelled request.', ['request_id' => $requestId]); | ||
| } |
Comment on lines
+71
to
+76
| $client = Client::builder() | ||
| // Fall back to an older handshake revision instead of 2025-11-25… | ||
| ->setFallbackProtocolVersion(ProtocolVersion::V2025_06_18) | ||
| // …or not at all, refusing servers without the modern era. | ||
| ->setFallbackProtocolVersion(null) | ||
| ->build(); |
This was referenced Oct 7, 2026
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Defaults the client to
2026-07-28and lets one client or server speak both eras on stdio and HTTP, following the backward compatibility rules of the spec.server/discoverand falls back toinitializeon2025-11-25unless the server proves to be modern -setFallbackProtocolVersion()picks the revision,nullmakes it modern-onlyStdioTransportsettles the era on the client's first request and serves2026-07-28incl.subscriptions/listenandnotifications/cancelled-32022naming the revisions on a bareinitialize, HTTP error statuses and a dead stdio process fail the request at oncesetLoggingLevel()rides on every request,ping()usesserver/discoverand the roots notification is skipped[BC Break] A default client against a dual-era server now lands on
2026-07-28, so sampling and roots are gone there - pinsetProtocolVersion(ProtocolVersion::V2025_11_25)to keep them.Server conformance runs at 100% locally for both revisions, client baselines pass.