@@ -418,6 +418,7 @@ public function testToolsList(): void
418418 self ::assertContains ('validate_input ' , $ toolNames );
419419 self ::assertContains ('generate_markdown ' , $ toolNames );
420420 self ::assertContains ('process_message ' , $ toolNames );
421+ self ::assertContains ('list_books ' , $ toolNames );
421422
422423 foreach ($ tools as $ tool ) {
423424 self ::assertArrayHasKey ('name ' , $ tool );
@@ -651,4 +652,88 @@ public function testMcpMarkdownContent(): void
651652 self ::assertStringContainsString ("echo 'Hello, World!'; " , $ content );
652653 self ::assertStringContainsString ('``` ' , $ content );
653654 }
655+
656+ public function testMcpListBooks (): void
657+ {
658+ if (!class_exists (McpBundle::class)) {
659+ $ this ->markTestSkipped ('MCP bundle is not installed ' );
660+ }
661+
662+ if ($ this ->isMongoDB ()) {
663+ $ this ->markTestSkipped ('MCP is not supported with MongoDB ' );
664+ }
665+
666+ if (!$ this ->isPsr17FactoryAvailable ()) {
667+ $ this ->markTestSkipped ('PSR-17 HTTP factory implementation not available (required for MCP) ' );
668+ }
669+
670+ $ this ->recreateSchema ([
671+ McpBook::class,
672+ ]);
673+
674+ $ book = new McpBook ();
675+ $ book ->setTitle ('API Platform Guide for MCP ' );
676+ $ book ->setIsbn ('1-528491 ' );
677+ $ book ->setStatus ('available ' );
678+ $ manager = $ this ->getContainer ()->get ('doctrine.orm.entity_manager ' );
679+ $ manager ->persist ($ book );
680+ $ manager ->flush ();
681+
682+ $ client = self ::createClient ();
683+ $ sessionId = $ this ->initializeMcpSession ($ client );
684+
685+ $ res = $ client ->request ('POST ' , '/mcp ' , [
686+ 'headers ' => [
687+ 'Accept ' => 'application/json, text/event-stream ' ,
688+ 'Content-Type ' => 'application/json ' ,
689+ 'mcp-session-id ' => $ sessionId ,
690+ ],
691+ 'json ' => [
692+ 'jsonrpc ' => '2.0 ' ,
693+ 'id ' => 2 ,
694+ 'method ' => 'tools/call ' ,
695+ 'params ' => [
696+ 'name ' => 'list_books ' ,
697+ 'arguments ' => [
698+ 'search ' => '' ,
699+ ],
700+ ],
701+ ],
702+ ]);
703+
704+ self ::assertResponseIsSuccessful ();
705+ $ result = $ res ->toArray ()['result ' ] ?? null ;
706+ self ::assertIsArray ($ result );
707+ self ::assertArrayHasKey ('content ' , $ result );
708+ $ content = $ result ['content ' ][0 ]['text ' ] ?? null ;
709+ self ::assertNotNull ($ content , 'No text content in result ' );
710+ self ::assertStringContainsString ('API Platform Guide for MCP ' , $ content );
711+ self ::assertStringContainsString ('1-528491 ' , $ content );
712+
713+ $ structuredContent = $ result ['structuredContent ' ] ?? null ;
714+ $ this ->assertIsArray ($ structuredContent );
715+
716+ // when api_platform.use_symfony_listeners is true, the result has JSON-LD format
717+ if (true === $ this ->getContainer ()->getParameter ('api_platform.use_symfony_listeners ' )) {
718+ self ::assertArrayHasKeyAndValue ('@context ' , '/contexts/McpBook ' , $ structuredContent );
719+ self ::assertArrayHasKeyAndValue ('hydra:totalItems ' , 1 , $ structuredContent );
720+ $ members = $ structuredContent ['hydra:member ' ];
721+ } else {
722+ $ members = $ structuredContent ;
723+ }
724+
725+ $ this ->assertCount (1 , $ members , json_encode ($ members , \JSON_PRETTY_PRINT ));
726+ $ actualBook = array_first ($ members );
727+
728+ self ::assertArrayHasKeyAndValue ('id ' , 1 , $ actualBook );
729+ self ::assertArrayHasKeyAndValue ('title ' , 'API Platform Guide for MCP ' , $ actualBook );
730+ self ::assertArrayHasKeyAndValue ('isbn ' , '1-528491 ' , $ actualBook );
731+ self ::assertArrayHasKeyAndValue ('status ' , 'available ' , $ actualBook );
732+ }
733+
734+ private static function assertArrayHasKeyAndValue (string $ key , mixed $ value , array $ data ): void
735+ {
736+ self ::assertArrayHasKey ($ key , $ data );
737+ self ::assertSame ($ value , $ data [$ key ]);
738+ }
654739}
0 commit comments