* * @author Christopher Hertel * @author Tobias Nyholm */ final class CallToolHandler implements RequestHandlerInterface { public function __construct( private readonly ReferenceProviderInterface $referenceProvider, private readonly ReferenceHandlerInterface $referenceHandler, private readonly LoggerInterface $logger = new NullLogger(), ) { } public function supports(Request $request): bool { return $request instanceof CallToolRequest; } /** * @return Response|Error */ public function handle(Request $request, SessionInterface $session): Response|Error { \assert($request instanceof CallToolRequest); $toolName = $request->name; $arguments = $request->arguments ?? []; $this->logger->debug('Executing tool', ['name' => $toolName, 'arguments' => $arguments]); try { $reference = $this->referenceProvider->getTool($toolName); $arguments['_session'] = $session; $result = $this->referenceHandler->handle($reference, $arguments); if (!$result instanceof CallToolResult) { $result = new CallToolResult($reference->formatResult($result)); } $this->logger->debug('Tool executed successfully', [ 'name' => $toolName, 'result_type' => \gettype($result), ]); return new Response($request->getId(), $result); } catch (ToolCallException $e) { $this->logger->error(\sprintf('Error while executing tool "%s": "%s".', $toolName, $e->getMessage()), [ 'tool' => $toolName, 'arguments' => $arguments, ]); $errorContent = [new TextContent($e->getMessage())]; return new Response($request->getId(), CallToolResult::error($errorContent)); } catch (ToolNotFoundException $e) { $this->logger->error('Tool not found', ['name' => $toolName]); return new Error($request->getId(), Error::METHOD_NOT_FOUND, $e->getMessage()); } catch (\Throwable $e) { $this->logger->error('Unhandled error during tool execution', [ 'name' => $toolName, 'exception' => $e->getMessage(), ]); return Error::forInternalError('Error while executing tool', $request->getId()); } } }