From 9d04eb15ec824cd490bf0de0c58af7d72c04e898 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Sat, 22 Aug 2026 01:41:17 +0200 Subject: [PATCH] [Server] Log failures in CompletionCompleteHandler --- src/Server/Builder.php | 2 +- .../Request/CompletionCompleteHandler.php | 7 ++++ .../Request/CompletionCompleteHandlerTest.php | 39 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Server/Builder.php b/src/Server/Builder.php index e38e6830..90272ef3 100644 --- a/src/Server/Builder.php +++ b/src/Server/Builder.php @@ -1079,7 +1079,7 @@ private function resolve(): array $requestHandlers = array_merge($this->requestHandlers, [ new Handler\Request\CallToolHandler($registry, $referenceHandler, $logger), - new Handler\Request\CompletionCompleteHandler($registry, $container), + new Handler\Request\CompletionCompleteHandler($registry, $container, $logger), new Handler\Request\GetPromptHandler($registry, $referenceHandler, $logger), new Handler\Request\InitializeHandler($configuration), new Handler\Request\ListPromptsHandler($registry, $this->paginationLimit), diff --git a/src/Server/Handler/Request/CompletionCompleteHandler.php b/src/Server/Handler/Request/CompletionCompleteHandler.php index a1eab00b..704116da 100644 --- a/src/Server/Handler/Request/CompletionCompleteHandler.php +++ b/src/Server/Handler/Request/CompletionCompleteHandler.php @@ -25,6 +25,8 @@ use Mcp\Schema\Result\CompletionCompleteResult; use Mcp\Server\Session\SessionInterface; use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; /** * Handles completion/complete requests. @@ -38,6 +40,7 @@ final class CompletionCompleteHandler implements RequestHandlerInterface public function __construct( private readonly RegistryInterface $registry, private readonly ?ContainerInterface $container = null, + private readonly LoggerInterface $logger = new NullLogger(), ) { } @@ -87,8 +90,12 @@ public function handle(Request $request, SessionInterface $session): Response|Er } catch (PromptNotFoundException|ResourceNotFoundException $e) { // The reference names something the server does not have, which is // a bad parameter rather than a missing resource. + $this->logger->warning(\sprintf('Completion requested for unknown reference: %s', $e->getMessage()), ['exception' => $e]); + return Error::forInvalidParams($e->getMessage(), $request->getId()); } catch (\Throwable $e) { + $this->logger->error(\sprintf('Error while handling completion request: %s', $e->getMessage()), ['exception' => $e]); + return Error::forInternalError('Error while handling completion request', $request->getId()); } } diff --git a/tests/Unit/Server/Handler/Request/CompletionCompleteHandlerTest.php b/tests/Unit/Server/Handler/Request/CompletionCompleteHandlerTest.php index 63eefba3..b35347a9 100644 --- a/tests/Unit/Server/Handler/Request/CompletionCompleteHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/CompletionCompleteHandlerTest.php @@ -11,9 +11,11 @@ namespace Mcp\Tests\Unit\Server\Handler\Request; +use Mcp\Capability\Completion\ProviderInterface; use Mcp\Capability\Registry\ResourceReference; use Mcp\Capability\Registry\ResourceTemplateReference; use Mcp\Capability\RegistryInterface; +use Mcp\Schema\JsonRpc\Error; use Mcp\Schema\JsonRpc\Response; use Mcp\Schema\Request\CompletionCompleteRequest; use Mcp\Schema\ResourceTemplate; @@ -23,6 +25,7 @@ use Mcp\Tests\Unit\Capability\Attribute\CompletionProviderFixture; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; class CompletionCompleteHandlerTest extends TestCase { @@ -79,6 +82,42 @@ public function testReturnsCompletionsForResourceTemplate(): void $this->assertEquals(new CompletionCompleteResult(['alpha'], 1, false), $response->result); } + public function testLogsProviderFailureBeforeReturningInternalError(): void + { + $uri = 'file://users/alice'; + $request = $this->createCompletionRequest($uri, ['name' => 'id', 'value' => 'al']); + + $exception = new \RuntimeException('Provider blew up'); + $provider = $this->createMock(ProviderInterface::class); + $provider->method('getCompletions')->willThrowException($exception); + + $templateReference = new ResourceTemplateReference( + new ResourceTemplate('file://users/{id}', 'user'), + static fn () => null, + ['id' => $provider], + ); + + $this->registry + ->method('getResource') + ->with($uri) + ->willReturn($templateReference); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->once()) + ->method('error') + ->with( + 'Error while handling completion request: Provider blew up', + ['exception' => $exception], + ); + + $handler = new CompletionCompleteHandler($this->registry, null, $logger); + $response = $handler->handle($request, $this->session); + + $this->assertInstanceOf(Error::class, $response); + $this->assertSame('Error while handling completion request', $response->message); + } + /** * @param array{ name: string, value: string } $argument */