@@ -405,6 +405,7 @@ public function testToolsList(): void
405405 ],
406406 ]);
407407
408+ self ::assertResponseIsSuccessful ();
408409 $ data = $ res ->toArray ();
409410 self ::assertArrayHasKey ('result ' , $ data );
410411 self ::assertArrayHasKey ('tools ' , $ data ['result ' ]);
@@ -418,14 +419,68 @@ public function testToolsList(): void
418419 self ::assertContains ('validate_input ' , $ toolNames );
419420 self ::assertContains ('generate_markdown ' , $ toolNames );
420421 self ::assertContains ('process_message ' , $ toolNames );
422+ self ::assertContains ('list_books ' , $ toolNames );
421423
422424 foreach ($ tools as $ tool ) {
423425 self ::assertArrayHasKey ('name ' , $ tool );
424426 self ::assertArrayHasKey ('inputSchema ' , $ tool );
425427 self ::assertEquals ('object ' , $ tool ['inputSchema ' ]['type ' ]);
426428 }
427429
428- self ::assertResponseIsSuccessful ();
430+ $ listBooks = array_filter ($ tools , static function (array $ input ) {
431+ return 'list_books ' === $ input ['name ' ];
432+ });
433+
434+ self ::assertCount (1 , $ listBooks );
435+
436+ $ listBooks = array_first ($ listBooks );
437+
438+ self ::assertArrayHasKeyAndValue ('inputSchema ' , [
439+ 'type ' => 'object ' ,
440+ 'properties ' => [
441+ 'search ' => ['type ' => 'string ' ],
442+ ],
443+ ], $ listBooks );
444+ self ::assertArrayHasKeyAndValue ('description ' , 'List Books ' , $ listBooks );
445+
446+ $ outputSchema = $ listBooks ['outputSchema ' ];
447+ self ::assertArrayHasKeyAndValue ('$schema ' , 'http://json-schema.org/draft-07/schema# ' , $ outputSchema );
448+ self ::assertArrayHasKeyAndValue ('type ' , 'object ' , $ outputSchema );
449+
450+ self ::assertArrayHasKey ('definitions ' , $ outputSchema );
451+ $ definitions = $ outputSchema ['definitions ' ];
452+ self ::assertArrayHasKey ('McpBook.jsonld ' , $ definitions );
453+ $ McpBookJsonLd = $ definitions ['McpBook.jsonld ' ];
454+ self ::assertArrayHasKeyAndValue ('allOf ' , [
455+ [
456+ '$ref ' => '#/definitions/HydraItemBaseSchema ' ,
457+ ],
458+ [
459+ 'type ' => 'object ' ,
460+ 'properties ' => [
461+ 'id ' => ['readOnly ' => true , 'type ' => 'integer ' ],
462+ 'title ' => ['type ' => 'string ' ],
463+ 'isbn ' => ['type ' => 'string ' ],
464+ 'status ' => ['type ' => ['string ' , 'null ' ]],
465+ ]
466+ ],
467+ ], $ McpBookJsonLd );
468+
469+ self ::assertArrayHasKeyAndValue ('allOf ' , [
470+ ['$ref ' => '#/definitions/HydraCollectionBaseSchema ' ],
471+ [
472+ 'type ' => 'object ' ,
473+ 'required ' => ['hydra:member ' ],
474+ 'properties ' => [
475+ 'hydra:member ' => [
476+ 'type ' => 'array ' ,
477+ 'items ' => [
478+ '$ref ' => '#/definitions/McpBook.jsonld '
479+ ],
480+ ],
481+ ]
482+ ],
483+ ], $ outputSchema );
429484 }
430485
431486 public function testMcpToolAttribute (): void
@@ -651,4 +706,88 @@ public function testMcpMarkdownContent(): void
651706 self ::assertStringContainsString ("echo 'Hello, World!'; " , $ content );
652707 self ::assertStringContainsString ('``` ' , $ content );
653708 }
709+
710+ public function testMcpListBooks (): void
711+ {
712+ if (!class_exists (McpBundle::class)) {
713+ $ this ->markTestSkipped ('MCP bundle is not installed ' );
714+ }
715+
716+ if ($ this ->isMongoDB ()) {
717+ $ this ->markTestSkipped ('MCP is not supported with MongoDB ' );
718+ }
719+
720+ if (!$ this ->isPsr17FactoryAvailable ()) {
721+ $ this ->markTestSkipped ('PSR-17 HTTP factory implementation not available (required for MCP) ' );
722+ }
723+
724+ $ this ->recreateSchema ([
725+ McpBook::class,
726+ ]);
727+
728+ $ book = new McpBook ();
729+ $ book ->setTitle ('API Platform Guide for MCP ' );
730+ $ book ->setIsbn ('1-528491 ' );
731+ $ book ->setStatus ('available ' );
732+ $ manager = $ this ->getContainer ()->get ('doctrine.orm.entity_manager ' );
733+ $ manager ->persist ($ book );
734+ $ manager ->flush ();
735+
736+ $ client = self ::createClient ();
737+ $ sessionId = $ this ->initializeMcpSession ($ client );
738+
739+ $ res = $ client ->request ('POST ' , '/mcp ' , [
740+ 'headers ' => [
741+ 'Accept ' => 'application/json, text/event-stream ' ,
742+ 'Content-Type ' => 'application/json ' ,
743+ 'mcp-session-id ' => $ sessionId ,
744+ ],
745+ 'json ' => [
746+ 'jsonrpc ' => '2.0 ' ,
747+ 'id ' => 2 ,
748+ 'method ' => 'tools/call ' ,
749+ 'params ' => [
750+ 'name ' => 'list_books ' ,
751+ 'arguments ' => [
752+ 'search ' => '' ,
753+ ],
754+ ],
755+ ],
756+ ]);
757+
758+ self ::assertResponseIsSuccessful ();
759+ $ result = $ res ->toArray ()['result ' ] ?? null ;
760+ self ::assertIsArray ($ result );
761+ self ::assertArrayHasKey ('content ' , $ result );
762+ $ content = $ result ['content ' ][0 ]['text ' ] ?? null ;
763+ self ::assertNotNull ($ content , 'No text content in result ' );
764+ self ::assertStringContainsString ('API Platform Guide for MCP ' , $ content );
765+ self ::assertStringContainsString ('1-528491 ' , $ content );
766+
767+ $ structuredContent = $ result ['structuredContent ' ] ?? null ;
768+ $ this ->assertIsArray ($ structuredContent );
769+
770+ // when api_platform.use_symfony_listeners is true, the result is formatted as JSON-LD
771+ if (true === $ this ->getContainer ()->getParameter ('api_platform.use_symfony_listeners ' )) {
772+ self ::assertArrayHasKeyAndValue ('@context ' , '/contexts/McpBook ' , $ structuredContent );
773+ self ::assertArrayHasKeyAndValue ('hydra:totalItems ' , 1 , $ structuredContent );
774+ $ members = $ structuredContent ['hydra:member ' ];
775+ } else {
776+ $ members = $ structuredContent ;
777+ }
778+
779+ $ this ->assertCount (1 , $ members , json_encode ($ members , \JSON_PRETTY_PRINT ));
780+ $ actualBook = array_first ($ members );
781+
782+ self ::assertArrayHasKeyAndValue ('id ' , 1 , $ actualBook );
783+ self ::assertArrayHasKeyAndValue ('title ' , 'API Platform Guide for MCP ' , $ actualBook );
784+ self ::assertArrayHasKeyAndValue ('isbn ' , '1-528491 ' , $ actualBook );
785+ self ::assertArrayHasKeyAndValue ('status ' , 'available ' , $ actualBook );
786+ }
787+
788+ private static function assertArrayHasKeyAndValue (string $ key , mixed $ value , array $ data ): void
789+ {
790+ self ::assertArrayHasKey ($ key , $ data );
791+ self ::assertSame ($ value , $ data [$ key ]);
792+ }
654793}
0 commit comments