From fbb4a9c93d7af39d506517e48df306fc218b4cee Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 30 Jul 2025 10:34:34 +0200 Subject: [PATCH] [MCP Bundle] Add test case for configuration --- src/mcp-bundle/phpstan.dist.neon | 3 + .../DependencyInjection/McpBundleTest.php | 158 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 src/mcp-bundle/tests/DependencyInjection/McpBundleTest.php diff --git a/src/mcp-bundle/phpstan.dist.neon b/src/mcp-bundle/phpstan.dist.neon index 29384d1a..e9fa8eb5 100644 --- a/src/mcp-bundle/phpstan.dist.neon +++ b/src/mcp-bundle/phpstan.dist.neon @@ -7,6 +7,9 @@ parameters: - src/ - tests/ ignoreErrors: + - + identifier: missingType.iterableValue + path: tests/* - message: "#^Method .*::test.*\\(\\) has no return type specified\\.$#" reportUnmatched: false # we don't have tests yet diff --git a/src/mcp-bundle/tests/DependencyInjection/McpBundleTest.php b/src/mcp-bundle/tests/DependencyInjection/McpBundleTest.php new file mode 100644 index 00000000..88b8bee9 --- /dev/null +++ b/src/mcp-bundle/tests/DependencyInjection/McpBundleTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\McpBundle\Tests\DependencyInjection; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use Symfony\AI\McpBundle\McpBundle; +use Symfony\AI\McpSdk\Capability\Tool\IdentifierInterface; +use Symfony\AI\McpSdk\Server\NotificationHandlerInterface; +use Symfony\AI\McpSdk\Server\RequestHandlerInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +#[CoversClass(McpBundle::class)] +class McpBundleTest extends TestCase +{ + public function testDefaultConfiguration() + { + $container = $this->buildContainer([]); + + $this->assertSame('app', $container->getParameter('mcp.app')); + $this->assertSame('0.0.1', $container->getParameter('mcp.version')); + } + + public function testCustomConfiguration() + { + $container = $this->buildContainer([ + 'mcp' => [ + 'app' => 'my-mcp-app', + 'version' => '1.2.3', + ], + ]); + + $this->assertSame('my-mcp-app', $container->getParameter('mcp.app')); + $this->assertSame('1.2.3', $container->getParameter('mcp.version')); + } + + #[DataProvider('provideClientTransportsConfiguration')] + public function testClientTransportsConfiguration(array $config, array $expectedServices) + { + $container = $this->buildContainer([ + 'mcp' => [ + 'client_transports' => $config, + ], + ]); + + foreach ($expectedServices as $serviceId => $shouldExist) { + if ($shouldExist) { + $this->assertTrue($container->hasDefinition($serviceId), \sprintf('Service "%s" should exist', $serviceId)); + } else { + $this->assertFalse($container->hasDefinition($serviceId), \sprintf('Service "%s" should not exist', $serviceId)); + } + } + } + + public static function provideClientTransportsConfiguration(): iterable + { + yield 'no transports enabled' => [ + 'config' => [ + 'stdio' => false, + 'sse' => false, + ], + 'expectedServices' => [ + 'mcp.server.command' => false, + 'mcp.server.controller' => false, + 'mcp.server.route_loader' => false, + ], + ]; + + yield 'stdio transport enabled' => [ + 'config' => [ + 'stdio' => true, + 'sse' => false, + ], + 'expectedServices' => [ + 'mcp.server.command' => true, + 'mcp.server.controller' => false, + 'mcp.server.route_loader' => true, + ], + ]; + + yield 'sse transport enabled' => [ + 'config' => [ + 'stdio' => false, + 'sse' => true, + ], + 'expectedServices' => [ + 'mcp.server.command' => false, + 'mcp.server.controller' => true, + 'mcp.server.route_loader' => true, + ], + ]; + + yield 'both transports enabled' => [ + 'config' => [ + 'stdio' => true, + 'sse' => true, + ], + 'expectedServices' => [ + 'mcp.server.command' => true, + 'mcp.server.controller' => true, + 'mcp.server.route_loader' => true, + ], + ]; + } + + public function testToolAutoconfiguration() + { + $container = $this->buildContainer([]); + + $autoconfiguredInstances = $container->getAutoconfiguredInstanceof(); + + $this->assertArrayHasKey(IdentifierInterface::class, $autoconfiguredInstances); + $this->assertArrayHasKey('mcp.tool', $autoconfiguredInstances[IdentifierInterface::class]->getTags()); + } + + public function testServerAutoconfigurations() + { + $container = $this->buildContainer([ + 'mcp' => [ + 'client_transports' => [ + 'stdio' => true, + 'sse' => true, + ], + ], + ]); + + $autoconfiguredInstances = $container->getAutoconfiguredInstanceof(); + + $this->assertArrayHasKey(NotificationHandlerInterface::class, $autoconfiguredInstances); + $this->assertArrayHasKey(RequestHandlerInterface::class, $autoconfiguredInstances); + + $this->assertArrayHasKey('mcp.server.notification_handler', $autoconfiguredInstances[NotificationHandlerInterface::class]->getTags()); + $this->assertArrayHasKey('mcp.server.request_handler', $autoconfiguredInstances[RequestHandlerInterface::class]->getTags()); + } + + private function buildContainer(array $configuration): ContainerBuilder + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', true); + $container->setParameter('kernel.environment', 'test'); + $container->setParameter('kernel.build_dir', 'public'); + + $extension = (new McpBundle())->getContainerExtension(); + $extension->load($configuration, $container); + + return $container; + } +}