@@ -420,6 +420,7 @@ public function testToolsList(): void
420420 self ::assertContains ('generate_markdown ' , $ toolNames );
421421 self ::assertContains ('process_message ' , $ toolNames );
422422 self ::assertContains ('list_books ' , $ toolNames );
423+ self ::assertContains ('list_books_dto ' , $ toolNames );
423424
424425 foreach ($ tools as $ tool ) {
425426 self ::assertArrayHasKey ('name ' , $ tool );
@@ -785,6 +786,82 @@ public function testMcpListBooks(): void
785786 self ::assertArrayHasKeyAndValue ('status ' , 'available ' , $ actualBook );
786787 }
787788
789+ public function testMcpListBooksDto (): void
790+ {
791+ if (!class_exists (McpBundle::class)) {
792+ $ this ->markTestSkipped ('MCP bundle is not installed ' );
793+ }
794+
795+ if ($ this ->isMongoDB ()) {
796+ $ this ->markTestSkipped ('MCP is not supported with MongoDB ' );
797+ }
798+
799+ if (!$ this ->isPsr17FactoryAvailable ()) {
800+ $ this ->markTestSkipped ('PSR-17 HTTP factory implementation not available (required for MCP) ' );
801+ }
802+
803+ $ this ->recreateSchema ([
804+ McpBook::class,
805+ ]);
806+
807+ $ book = new McpBook ();
808+ $ book ->setTitle ('API Platform Guide for MCP ' );
809+ $ book ->setIsbn ('1-528491 ' );
810+ $ book ->setStatus ('available ' );
811+ $ manager = $ this ->getContainer ()->get ('doctrine.orm.entity_manager ' );
812+ $ manager ->persist ($ book );
813+ $ manager ->flush ();
814+
815+ $ client = self ::createClient ();
816+ $ sessionId = $ this ->initializeMcpSession ($ client );
817+
818+ $ res = $ client ->request ('POST ' , '/mcp ' , [
819+ 'headers ' => [
820+ 'Accept ' => 'application/json, text/event-stream ' ,
821+ 'Content-Type ' => 'application/json ' ,
822+ 'mcp-session-id ' => $ sessionId ,
823+ ],
824+ 'json ' => [
825+ 'jsonrpc ' => '2.0 ' ,
826+ 'id ' => 2 ,
827+ 'method ' => 'tools/call ' ,
828+ 'params ' => [
829+ 'name ' => 'list_books_dto ' ,
830+ 'arguments ' => [
831+ 'search ' => '' ,
832+ ],
833+ ],
834+ ],
835+ ]);
836+
837+ self ::assertResponseIsSuccessful ();
838+ $ result = $ res ->toArray ()['result ' ] ?? null ;
839+ self ::assertIsArray ($ result );
840+ self ::assertArrayHasKey ('content ' , $ result );
841+ $ content = $ result ['content ' ][0 ]['text ' ] ?? null ;
842+ self ::assertNotNull ($ content , 'No text content in result ' );
843+ self ::assertStringContainsString ('Raiders of the Lost Ark ' , $ content );
844+ self ::assertStringContainsString ('1-528491 ' , $ content );
845+
846+ $ structuredContent = $ result ['structuredContent ' ] ?? null ;
847+ $ this ->assertIsArray ($ structuredContent );
848+
849+ $ actualBook = $ structuredContent ;
850+
851+ // when api_platform.use_symfony_listeners is true, the result is formatted as JSON-LD
852+ if (true === $ this ->getContainer ()->getParameter ('api_platform.use_symfony_listeners ' )) {
853+ self ::assertArrayHasKey ('@context ' , $ structuredContent );
854+ $ context = $ structuredContent ['@context ' ];
855+ self ::assertArrayHasKeyAndValue ('@vocab ' , 'http://localhost/docs.jsonld# ' , $ context );
856+ self ::assertArrayHasKeyAndValue ('hydra ' , 'http://www.w3.org/ns/hydra/core# ' , $ context );
857+ }
858+
859+ self ::assertArrayHasKeyAndValue ('id ' , 528491 , $ actualBook );
860+ self ::assertArrayHasKeyAndValue ('name ' , 'Raiders of the Lost Ark ' , $ actualBook );
861+ self ::assertArrayHasKeyAndValue ('isbn ' , '1-528491 ' , $ actualBook );
862+ self ::assertArrayNotHasKey ('status ' , $ actualBook );
863+ }
864+
788865 private static function assertArrayHasKeyAndValue (string $ key , mixed $ value , array $ data ): void
789866 {
790867 self ::assertArrayHasKey ($ key , $ data );
0 commit comments