Skip to content

[Client] Speak the 2026-07-28 lifecycle - #456

Merged
chr-hertel merged 3 commits into
modelcontextprotocol:mainfrom
chr-hertel:pr/2026-client
Aug 19, 2026
Merged

[Client] Speak the 2026-07-28 lifecycle#456
chr-hertel merged 3 commits into
modelcontextprotocol:mainfrom
chr-hertel:pr/2026-client

Conversation

@chr-hertel

Copy link
Copy Markdown
Member

Stacked on #455. This is the client half of the revision — with it, both sides of the SDK speak 2026-07-28.

Client opens with server/discover instead of initialize on that revision, stamps each request's _meta with the protocol version, its own capabilities and client info, and sends the standard Mcp-Method / Mcp-Name / Mcp-Param-* headers an intermediary routes on. Mcp\Client\Stateless\ToolCatalog is what knows, from the tool list, which arguments a call has to mirror.

An input_required result is answered rather than surfaced: InputRequestResolver asks the host's elicitation, sampling and roots handlers and retries the same request carrying inputResponses and the requestState the server sent.

One refactor to already-merged code. Mcp\Schema\Wire\McpHeader holds the header names and the =?base64?…?= sentinel both sides share. The x-mcp-header annotation rules from #441 move there too, as McpHeader::checkAnnotations() / annotations(), and Tool delegates to them. The client needs those rules for a schema a peer sent, which the private methods on Tool could not serve; the rules themselves are unchanged, and ToolHeaderAnnotationTest still covers them through Tool.


Cross-fork PRs can only target main, so this diff also carries its ancestors until they merge. Only the last commit(s) belong to this PR — GitHub's "Commits" tab separates them.

On that revision the client opens with server/discover instead of
initialize, stamps each request's _meta with the protocol version, its own
capabilities and client info, and sends the standard Mcp-Method / Mcp-Name /
Mcp-Param-* headers an intermediary routes on. ToolCatalog is what knows,
from the tool list, which arguments a call has to mirror.

An input_required result is answered rather than surfaced: InputRequestResolver
asks the host's elicitation, sampling and roots handlers and retries the same
request carrying inputResponses and the requestState the server sent.

McpHeader holds the header names and the =?base64?…?= sentinel, so the two
sides no longer keep their own copies of the same rules.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds client support for the 2026-07-28 stateless MCP lifecycle.

Changes:

  • Adds discovery, request envelopes, protocol headers, and version reconciliation.
  • Resolves multi-round-trip input requests automatically.
  • Shares header validation rules and adds dual-era/conformance coverage.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
CHANGELOG.md Documents client lifecycle support.
src/Client.php Integrates tool catalog validation.
src/Client/Protocol.php Implements modern lifecycle and retries.
src/Client/Stateless/HeaderFactory.php Generates protocol headers.
src/Client/Stateless/InputRequestResolver.php Resolves embedded input requests.
src/Client/Stateless/RequestEnvelope.php Stamps modern request metadata.
src/Client/Stateless/ToolCatalog.php Tracks tool header annotations.
src/Client/Transport/HeaderAwareTransportInterface.php Defines per-message header callbacks.
src/Client/Transport/HttpTransport.php Sends generated HTTP headers.
src/Schema/Request/DiscoverRequest.php Models server/discover.
src/Schema/Tool.php Delegates annotation validation.
src/Schema/Wire/McpHeader.php Centralizes header rules.
src/Server/Stateless/StandardHeaderValidator.php Uses shared header utilities.
examples/server/client-communication/ClientAwareService.php Converts examples to MRTR.
examples/server/elicitation/ElicitationHandlers.php Supports elicitation across eras.
tests/Conformance/client.php Adds modern conformance scenarios.
tests/Integration/DualEraElicitationTest.php Tests elicitation in both eras.
tests/Integration/DualEraExampleTestCase.php Provides dual-era test infrastructure.
tests/Integration/HandshakeTest.php Updates lifecycle expectations.
tests/Unit/Client/ProtocolTest.php Tests modern protocol initialization.
tests/Unit/Client/Stateless/HeaderFactoryTest.php Tests generated headers.
tests/Unit/Client/Stateless/InputRequestResolverTest.php Tests input resolution.
tests/Unit/Client/Stateless/ToolCatalogTest.php Tests catalog behavior.
tests/Unit/Schema/Wire/McpHeaderTest.php Tests shared header encoding.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

return null;
}

return self::isSafe($rendered) ? $rendered : self::wrap($rendered);
Comment thread src/Client/Protocol.php Outdated
// between rounds.
$payload['params'] = [
...($payload['params'] ?? []),
'inputResponses' => $this->inputRequests->resolve($asked),
);

$result = $clientGateway->sample($prompt, 350, 90, ['temperature' => 0.5]);
$result = $context->getInputContext()?->samplingResult('recommendation');
Comment thread src/Client/Protocol.php
@@ -80,37 +128,65 @@ public function __construct(
public function connect(TransportInterface $transport, Configuration $config): void
{
$this->transport = $transport;
Drop stale expected-failure entries the new client fixture now passes.

Copilot review: fix McpHeader round-trip for a wrapper-shaped literal,
encode empty/numeric-keyed inputResponses as a JSON object, stop the
incident example repeating side effects on MRTR retry, and reset
ToolCatalog on reconnect instead of carrying the previous server's
verdicts.
PHP_CLI_SERVER_WORKERS does not reliably fork multiple php -S
workers there (php/php-src#9400), reproducing the single-worker
deadlock the extra workers exist to avoid.
@chr-hertel
chr-hertel merged commit 8c06dce into modelcontextprotocol:main Aug 19, 2026
25 checks passed
@chr-hertel
chr-hertel deleted the pr/2026-client branch August 19, 2026 00:41
@chr-hertel chr-hertel added the 2026-07-28 All issues and PRs related to the spec release 2026-07-28 label Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2026-07-28 All issues and PRs related to the spec release 2026-07-28

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants