[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:
parent
60711951d4
commit
3d596ca75b
1 changed files with 1735 additions and 16 deletions
|
|
@ -14,6 +14,7 @@ namespace Mcp\Server\Handler\Request;
|
|||
use Mcp\Capability\Discovery\SchemaValidator;
|
||||
use Mcp\Capability\Registry\ReferenceHandlerInterface;
|
||||
use Mcp\Capability\RegistryInterface;
|
||||
use Mcp\Exception\MissingRequiredClientCapabilityException;
|
||||
use Mcp\Exception\ToolCallException;
|
||||
use Mcp\Exception\ToolNotFoundException;
|
||||
use Mcp\Schema\Content\TextContent;
|
||||
|
|
@ -22,13 +23,17 @@ use Mcp\Schema\JsonRpc\Request;
|
|||
use Mcp\Schema\JsonRpc\Response;
|
||||
use Mcp\Schema\Request\CallToolRequest;
|
||||
use Mcp\Schema\Result\CallToolResult;
|
||||
use Mcp\Schema\Result\InputRequiredResult;
|
||||
use Mcp\Server\RequestContext;
|
||||
use Mcp\Server\Session\SessionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<CallToolResult>
|
||||
* A tools/call can answer with the tool's output or, under MRTR, with a request
|
||||
* for the input the tool still needs — hence the two result types.
|
||||
*
|
||||
* @implements RequestHandlerInterface<CallToolResult|InputRequiredResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
|
|
@ -52,7 +57,7 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Response<CallToolResult>|Error
|
||||
* @return Response<CallToolResult|InputRequiredResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error
|
||||
{
|
||||
|
|
@ -98,6 +103,11 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
try {
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
// Tool asking for more input as response
|
||||
if ($result instanceof InputRequiredResult) {
|
||||
return new Response($request->getId(), $result);
|
||||
}
|
||||
|
||||
$protocolVersion = $context->getProtocolVersion();
|
||||
|
||||
$structuredContent = null;
|
||||
|
|
@ -135,6 +145,8 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
]);
|
||||
|
||||
return new Response($request->getId(), $result);
|
||||
} catch (MissingRequiredClientCapabilityException $e) {
|
||||
throw $e;
|
||||
} catch (ToolCallException $e) {
|
||||
$this->logger->error(\sprintf('Error while executing tool "%s": "%s".', $toolName, $e->getMessage()), [
|
||||
'tool' => $toolName,
|
||||
|
|
|
|||
Loading…
Reference in a new issue