[Server] Add Bidirectional Client Communication Support (#109)
* feat(server): add bidirectional client communication support * fix(server): use correct session ID string conversion method * fix: clean up docblocks for request handler methods in Builder * fix: merge artifacts
This commit is contained in:
parent
0963d243bc
commit
f1b471a219
11 changed files with 1973 additions and 445 deletions
|
|
@ -26,6 +26,8 @@ use Psr\Log\LoggerInterface;
|
|||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<CallToolResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
|
|
@ -43,6 +45,9 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
return $request instanceof CallToolRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<CallToolResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error
|
||||
{
|
||||
\assert($request instanceof CallToolRequest);
|
||||
|
|
@ -58,6 +63,8 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
throw new ToolNotFoundException($request);
|
||||
}
|
||||
|
||||
$arguments['_session'] = $session;
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
if (!$result instanceof CallToolResult) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ use Psr\Container\ContainerInterface;
|
|||
/**
|
||||
* Handles completion/complete requests.
|
||||
*
|
||||
* @implements RequestHandlerInterface<CompletionCompleteResult>
|
||||
*
|
||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||
*/
|
||||
final class CompletionCompleteHandler implements RequestHandlerInterface
|
||||
|
|
@ -39,6 +41,9 @@ final class CompletionCompleteHandler implements RequestHandlerInterface
|
|||
return $request instanceof CompletionCompleteRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<CompletionCompleteResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error
|
||||
{
|
||||
\assert($request instanceof CompletionCompleteRequest);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ use Psr\Log\LoggerInterface;
|
|||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<GetPromptResult>
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class GetPromptHandler implements RequestHandlerInterface
|
||||
|
|
@ -42,6 +44,9 @@ final class GetPromptHandler implements RequestHandlerInterface
|
|||
return $request instanceof GetPromptRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<GetPromptResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error
|
||||
{
|
||||
\assert($request instanceof GetPromptRequest);
|
||||
|
|
@ -55,6 +60,8 @@ final class GetPromptHandler implements RequestHandlerInterface
|
|||
throw new PromptNotFoundException($request);
|
||||
}
|
||||
|
||||
$arguments['_session'] = $session;
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
$formatted = $reference->formatResult($result);
|
||||
|
|
@ -67,11 +74,11 @@ final class GetPromptHandler implements RequestHandlerInterface
|
|||
} catch (PromptGetException|ExceptionInterface $e) {
|
||||
$this->logger->error('Error while handling prompt', ['prompt_name' => $promptName]);
|
||||
|
||||
return Error::forInternalError('Error while handling prompt', $request->getId());
|
||||
return Error::forInternalError('Error while handling prompt: '.$e->getMessage(), $request->getId());
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('Error while handling prompt', ['prompt_name' => $promptName]);
|
||||
|
||||
return Error::forInternalError('Error while handling prompt', $request->getId());
|
||||
return Error::forInternalError('Error while handling prompt: '.$e->getMessage(), $request->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ use Mcp\Server\Configuration;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<InitializeResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
*/
|
||||
final class InitializeHandler implements RequestHandlerInterface
|
||||
|
|
@ -35,6 +37,9 @@ final class InitializeHandler implements RequestHandlerInterface
|
|||
return $request instanceof InitializeRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<InitializeResult>
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
\assert($request instanceof InitializeRequest);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use Mcp\Schema\Result\ListPromptsResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<ListPromptsResult>
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class ListPromptsHandler implements RequestHandlerInterface
|
||||
|
|
@ -36,6 +38,8 @@ final class ListPromptsHandler implements RequestHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Response<ListPromptsResult>
|
||||
*
|
||||
* @throws InvalidCursorException
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use Mcp\Schema\Result\ListResourceTemplatesResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<ListResourceTemplatesResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
*/
|
||||
final class ListResourceTemplatesHandler implements RequestHandlerInterface
|
||||
|
|
@ -36,6 +38,8 @@ final class ListResourceTemplatesHandler implements RequestHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Response<ListResourceTemplatesResult>
|
||||
*
|
||||
* @throws InvalidCursorException
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use Mcp\Schema\Result\ListResourcesResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<ListResourcesResult>
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class ListResourcesHandler implements RequestHandlerInterface
|
||||
|
|
@ -36,6 +38,8 @@ final class ListResourcesHandler implements RequestHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Response<ListResourcesResult>
|
||||
*
|
||||
* @throws InvalidCursorException
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use Mcp\Schema\Result\ListToolsResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<ListToolsResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
|
|
@ -37,6 +39,8 @@ final class ListToolsHandler implements RequestHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Response<ListToolsResult>
|
||||
*
|
||||
* @throws InvalidCursorException When the cursor is invalid
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ use Mcp\Schema\Result\EmptyResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<EmptyResult>
|
||||
*
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
*/
|
||||
final class PingHandler implements RequestHandlerInterface
|
||||
|
|
@ -27,6 +29,9 @@ final class PingHandler implements RequestHandlerInterface
|
|||
return $request instanceof PingRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<EmptyResult>
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
\assert($request instanceof PingRequest);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ use Psr\Log\LoggerInterface;
|
|||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* @implements RequestHandlerInterface<ReadResourceResult>
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class ReadResourceHandler implements RequestHandlerInterface
|
||||
|
|
@ -41,6 +43,9 @@ final class ReadResourceHandler implements RequestHandlerInterface
|
|||
return $request instanceof ReadResourceRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<ReadResourceResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error
|
||||
{
|
||||
\assert($request instanceof ReadResourceRequest);
|
||||
|
|
@ -55,7 +60,12 @@ final class ReadResourceHandler implements RequestHandlerInterface
|
|||
throw new ResourceNotFoundException($request);
|
||||
}
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, ['uri' => $uri]);
|
||||
$arguments = [
|
||||
'uri' => $uri,
|
||||
'_session' => $session,
|
||||
];
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
if ($reference instanceof ResourceTemplateReference) {
|
||||
$formatted = $reference->formatResult($result, $uri, $reference->resourceTemplate->mimeType);
|
||||
|
|
|
|||
|
|
@ -17,11 +17,16 @@ use Mcp\Schema\JsonRpc\Response;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @template TResult
|
||||
*
|
||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||
*/
|
||||
interface RequestHandlerInterface
|
||||
{
|
||||
public function supports(Request $request): bool;
|
||||
|
||||
/**
|
||||
* @return Response<TResult>|Error
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response|Error;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue