From df74ab2c6159c87562ff29457c255c10909ef97c Mon Sep 17 00:00:00 2001 From: Faneraiy14 Date: Wed, 19 Aug 2026 16:42:49 +0300 Subject: [PATCH] Fail loudly when discovery is configured but symfony/finder is missing Builder::build() previously routed around Discoverer::__construct()'s own class_exists(Finder::class) guard: instead of throwing, it logged a single warning and silently skipped the DiscoveryLoader. The result is the worst failure mode available - the server builds successfully, initialize succeeds, and tools/list quietly returns an empty array, with no actionable signal beyond one log line the operator may never see. setDiscovery() is an explicit request for file-based discovery; if that request can't be honored, build() should fail immediately with the same RuntimeException and message Discoverer already throws for the identical condition, rather than downgrading a configured-but- impossible feature to a whisper. Fixes #398 --- src/Server/Builder.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Server/Builder.php b/src/Server/Builder.php index e38e6830..88c2f051 100644 --- a/src/Server/Builder.php +++ b/src/Server/Builder.php @@ -29,6 +29,7 @@ use Mcp\Capability\RegistryInterface; use Mcp\Exception\InvalidArgumentException; use Mcp\Exception\LogicException; +use Mcp\Exception\RuntimeException; use Mcp\JsonRpc\MessageFactory; use Mcp\Schema\Annotations; use Mcp\Schema\Enum\ProtocolVersion; @@ -1037,7 +1038,13 @@ private function resolve(): array $discoverer = $this->discoverer ?? $this->createDiscoverer($logger); $loaders[] = new DiscoveryLoader($this->discoveryBasePath, $this->discoveryScanDirs, $this->discoveryExcludeDirs, $discoverer, $this->discoveryNamePatterns, $logger); } else { - $logger->warning('File-based discovery requires symfony/finder. Skipping automatic discovery. Run: composer require symfony/finder'); + // Warning-and-skip here used to route around the identical guard in + // Discoverer::__construct(), turning a configured-but-impossible feature + // into a silent no-op: build() succeeds, initialize succeeds, and + // tools/list quietly returns an empty array with no actionable signal + // beyond a single log line. setDiscovery() is an explicit request for + // file-based discovery, so failing to honor it must fail loudly. + throw new RuntimeException('File-based discovery requires symfony/finder. Run: composer require symfony/finder'); } }