Registry Architecture Refactoring - Enhanced Separation of Concerns (#46)

* refactor: Separate Registry concerns following SOLID principles [WIP]

- Extract ReferenceProvider and ReferenceRegistryInterface interfaces
- Create DefaultToolExecutor with ReferenceHandlerInterface
- Remove execution responsibility from Registry class
- Enable custom handler and executor implementations

* refactor: implement SOLID principles with separated execution concerns

* Create DefaultResourceReader, DefaultPromptGetter
* Refactor JsonRpc Handler and RequestHandlers to use dedicated executors
* Update ServerBuilder to support custom executors via dependency injection

* chore: remove extra comments

* feat: introduce DispatchableRegistry for enhanced tool and resource management

* refactor: use proper interfaces

* refactor: implement HandlerInterface for improved abstraction and flexibility

* test: add unit tests for DispatchableRegistry and Registry classes

* refactor: cover with unit tests Resource reader, Prompt getter and Tool executor

* cs fix

* phpstan fix

* test: add unit tests for CallToolHandler, GetPromptHandler, PingHandler, and ReadResourceHandler

* refactor: revert Handler

* chore: remove style guide for tests

* refactor: remove "Default" prefix from classes

* refactor: remove DispatchableRegistry

* refactor: use package specific exception classes

* refactor: remove DispatchableRegistry

* refactor: add logger support to PromptGetter and ResourceReader classes

* Update src/Capability/Prompt/PromptGetter.php

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* refactor: Use FQN for Resource class to avoid cs-fixer misinterpreting it as `resource`

* refactor: rename ToolExecutor to ToolCaller and related classes for clarity and consistency

* refactor: add missed docblock

* refactor: rename ToolExecutor references to ToolCaller

* refactor: rename ToolCallerTest property and variable references

* cs fix

* ignore some phpstan errors

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
This commit is contained in:
Pavel Buchnev 2025-09-14 22:44:18 +04:00 • committed by GitHub
commit 99bf56eef8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,13 +11,12 @@
namespace Mcp\Server\RequestHandler;
use Mcp\Capability\Registry;
use Mcp\Capability\Tool\ToolCallerInterface;
use Mcp\Exception\ExceptionInterface;
use Mcp\Schema\JsonRpc\Error;
use Mcp\Schema\JsonRpc\HasMethodInterface;
use Mcp\Schema\JsonRpc\Response;
use Mcp\Schema\Request\CallToolRequest;
use Mcp\Schema\Result\CallToolResult;
use Mcp\Server\MethodHandlerInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
@ -29,7 +28,7 @@ use Psr\Log\NullLogger;
final class CallToolHandler implements MethodHandlerInterface
{
public function __construct(
private readonly Registry $registry,
private readonly ToolCallerInterface $toolCaller,
private readonly LoggerInterface $logger = new NullLogger(),
) {
}
@ -44,16 +43,19 @@ final class CallToolHandler implements MethodHandlerInterface
\assert($message instanceof CallToolRequest);
try {
$content = $this->registry->handleCallTool($message->name, $message->arguments);
$content = $this->toolCaller->call($message);
} catch (ExceptionInterface $exception) {
$this->logger->error(\sprintf('Error while executing tool "%s": "%s".', $message->name, $exception->getMessage()), [
'tool' => $message->name,
'arguments' => $message->arguments,
]);
$this->logger->error(
\sprintf('Error while executing tool "%s": "%s".', $message->name, $exception->getMessage()),
[
'tool' => $message->name,
'arguments' => $message->arguments,
],
);
return Error::forInternalError('Error while executing tool', $message->getId());
}
return new Response($message->getId(), new CallToolResult($content));
return new Response($message->getId(), $content);
}
}