1111
1212namespace Mcp \Server \Handler \Request ;
1313
14+ use Mcp \Capability \Discovery \SchemaValidator ;
1415use Mcp \Capability \Registry \ReferenceHandlerInterface ;
1516use Mcp \Capability \RegistryInterface ;
1617use Mcp \Exception \ToolCallException ;
3334 */
3435final class CallToolHandler implements RequestHandlerInterface
3536{
37+ private SchemaValidator $ schemaValidator ;
38+
3639 public function __construct (
3740 private readonly RegistryInterface $ registry ,
3841 private readonly ReferenceHandlerInterface $ referenceHandler ,
3942 private readonly LoggerInterface $ logger = new NullLogger (),
43+ ?SchemaValidator $ schemaValidator = null ,
4044 ) {
45+ $ this ->schemaValidator = $ schemaValidator ?? new SchemaValidator ($ logger );
4146 }
4247
4348 public function supports (Request $ request ): bool
@@ -59,10 +64,35 @@ public function handle(Request $request, SessionInterface $session): Response|Er
5964
6065 try {
6166 $ reference = $ this ->registry ->getTool ($ toolName );
67+ } catch (ToolNotFoundException $ e ) {
68+ $ this ->logger ->error ('Tool not found ' , ['name ' => $ toolName ]);
69+
70+ return new Error ($ request ->getId (), Error::METHOD_NOT_FOUND , $ e ->getMessage ());
71+ }
72+
73+ $ inputSchema = $ reference ->tool ->inputSchema ;
74+ $ validationErrors = $ this ->schemaValidator ->validateAgainstJsonSchema ($ arguments , $ inputSchema );
75+ if (!empty ($ validationErrors )) {
76+ $ errorMessages = [];
77+
78+ foreach ($ validationErrors as $ errorDetail ) {
79+ $ pointer = $ errorDetail ['pointer ' ] ?? '' ;
80+ $ message = $ errorDetail ['message ' ] ?? 'Unknown validation error ' ;
81+ $ errorMessages [] = ('/ ' !== $ pointer && '' !== $ pointer ? "Property ' {$ pointer }': " : '' ).$ message ;
82+ }
6283
63- $ arguments ['_session ' ] = $ session ;
64- $ arguments ['_request ' ] = $ request ;
84+ $ summaryMessage = "Invalid parameters for tool ' {$ toolName }': " .implode ('; ' , \array_slice ($ errorMessages , 0 , 3 ));
85+ if (\count ($ errorMessages ) > 3 ) {
86+ $ summaryMessage .= '; ...and more errors. ' ;
87+ }
88+
89+ return Error::forInvalidParams ($ summaryMessage , $ request ->getId (), ['validation_errors ' => $ validationErrors ]);
90+ }
6591
92+ $ arguments ['_session ' ] = $ session ;
93+ $ arguments ['_request ' ] = $ request ;
94+
95+ try {
6696 $ result = $ this ->referenceHandler ->handle ($ reference , $ arguments );
6797
6898 $ structuredContent = null ;
@@ -87,10 +117,6 @@ public function handle(Request $request, SessionInterface $session): Response|Er
87117 $ errorContent = [new TextContent ($ e ->getMessage ())];
88118
89119 return new Response ($ request ->getId (), CallToolResult::error ($ errorContent ));
90- } catch (ToolNotFoundException $ e ) {
91- $ this ->logger ->error ('Tool not found ' , ['name ' => $ toolName ]);
92-
93- return new Error ($ request ->getId (), Error::METHOD_NOT_FOUND , $ e ->getMessage ());
94120 } catch (\Throwable $ e ) {
95121 $ this ->logger ->error ('Unhandled error during tool execution ' , [
96122 'name ' => $ toolName ,
0 commit comments