[Server][Tests] Serve the modern (SEP-2575) lifecycle (#444)

* [Server][Tests] Serve the modern (SEP-2575) lifecycle

The revision removed the initialize handshake: every request carries its own
_meta - protocol version, client capabilities, client info - and answers
server/discover for what initialize used to return. There is no session to
keep, so there is nothing for the handshake-era dispatcher to do.

Builder::buildStateless() produces StatelessProtocol, and
StatelessHttpTransport serves it over one POST-only endpoint - GET and
DELETE are 405, and no Mcp-Session-Id exists to hand out.

Results go through a per-era wire codec rather than the handlers, so
resultType and the caching hints are stamped for 2026-07-28 and left off the
revisions that do not define them.

Covered by the modern conformance suite (make conformance-draft-server)
against its own baseline; unit coverage arrives with the fixes stacked on
this.

* Apply suggestions from code review

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* Fix critical stateless-lifecycle bugs from review

- Don't leak internal exception messages to clients on uncaught
  \Throwable; use a generic message like the handshake-era protocol
  and every built-in handler already do.
- Default a missing/invalid request id to null instead of "", and
  stop answering notifications and malformed messages as if they
  were "method not found" 404s.
- Read the POST body in a loop instead of a single read() call,
  which PSR-7 allows to return short.
This commit is contained in:
Christopher Hertel 2026-08-18 22:08:54 +02:00 • committed by GitHub
commit 3d596ca75b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the official PHP MCP SDK.
*
* A collaboration between Symfony and the PHP Foundation.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Mcp\Server\Wire;
/**
* The wire codec for every revision through 2025-11-25.
*
* The identity transform, and deliberately so. These revisions have no
* `resultType`, no caching hints and no `_meta` serverInfo requirement, so the
* neutral result body *is* the wire body — there is nothing to stamp and,
* more importantly, nothing newer that may leak in. A server negotiating one
* of these revisions emits exactly the bytes it emitted before the modern era
* existed.
*
* @author Christopher Hertel <mail@christopher-hertel.de>
*/
final class Rev2025Codec implements WireCodecInterface
{
public function encodeResult(string $method, array $result): array
{
return $result;
}
}