Add RequestContext and logging (#176)
* Implemented MCP logging specification with auto-injection * Add RequestContext * fix tests and style * Better deprecation * fix: minor * Remove ClientAwareInterface * fix cs * fix docs --------- Co-authored-by: Adam Jamiu <jamiuadam120@gmail.com>
This commit is contained in:
parent
369932378f
commit
a1e0f61b6b
27 changed files with 578 additions and 162 deletions
|
|
@ -63,6 +63,7 @@
|
|||
"Mcp\\Example\\EnvVariables\\": "examples/env-variables/",
|
||||
"Mcp\\Example\\ExplicitRegistration\\": "examples/explicit-registration/",
|
||||
"Mcp\\Example\\SchemaShowcase\\": "examples/schema-showcase/",
|
||||
"Mcp\\Example\\ClientLogging\\": "examples/client-logging/",
|
||||
"Mcp\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,44 +13,21 @@ MCP supports various ways a server can communicate back to a server on top of th
|
|||
## ClientGateway
|
||||
|
||||
Every communication back to client is handled using the `Mcp\Server\ClientGateway` and its dedicated methods per
|
||||
operation. To use the `ClientGateway` in your code, there are two ways to do so:
|
||||
operation. To use the `ClientGateway` in your code, you need to use method argument injection for `RequestContext`.
|
||||
|
||||
### 1. Method Argument Injection
|
||||
|
||||
Every refernce of a MCP element, that translates to an actual method call, can just add an type-hinted argument for the
|
||||
`ClientGateway` and the SDK will take care to include the gateway in the arguments of the method call:
|
||||
Every reference of a MCP element, that translates to an actual method call, can just add an type-hinted argument for the
|
||||
`RequestContext` and the SDK will take care to include the gateway in the arguments of the method call:
|
||||
|
||||
```php
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Server\ClientGateway;
|
||||
use Mcp\Server\RequestContext;
|
||||
|
||||
class MyService
|
||||
{
|
||||
#[McpTool('my_tool', 'My Tool Description')]
|
||||
public function myTool(ClientGateway $client): string
|
||||
public function myTool(RequestContext $context): string
|
||||
{
|
||||
$client->log(...);
|
||||
```
|
||||
|
||||
### 2. Implementing `ClientAwareInterface`
|
||||
|
||||
Whenever a service class of an MCP element implements the interface `Mcp\Server\ClientAwareInterface` the `setClient`
|
||||
method of that class will get called while handling the reference, and in combination with `Mcp\Server\ClientAwareTrait`
|
||||
this ends up with code like this:
|
||||
|
||||
```php
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Server\ClientAwareInterface;
|
||||
use Mcp\Server\ClientAwareTrait;
|
||||
|
||||
class MyService implements ClientAwareInterface
|
||||
{
|
||||
use ClientAwareTrait;
|
||||
|
||||
#[McpTool('my_tool', 'My Tool Description')]
|
||||
public function myTool(): string
|
||||
{
|
||||
$this->log(...);
|
||||
$context->getClientGateway()->log(...);
|
||||
```
|
||||
|
||||
## Sampling
|
||||
|
|
|
|||
|
|
@ -166,11 +166,10 @@ $server = Server::builder()
|
|||
|
||||
**File**: `examples/client-communication/`
|
||||
|
||||
**What it demostrates:**
|
||||
- Server initiated communcation back to the client
|
||||
**What it demonstrates:**
|
||||
- Server initiated communication back to the client
|
||||
- Logging, sampling, progress and notifications
|
||||
- Using `ClientGateway` in service class via `ClientAwareInterface` and corresponding trait
|
||||
- Using `ClientGateway` in tool method via method argument injection
|
||||
- Using `ClientGateway` in tool method via method argument injection of `RequestContext`
|
||||
|
||||
### Discovery User Profile
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ discovery and manual registration methods.
|
|||
- [Resources](#resources)
|
||||
- [Resource Templates](#resource-templates)
|
||||
- [Prompts](#prompts)
|
||||
- [Logging](#logging)
|
||||
- [Completion Providers](#completion-providers)
|
||||
- [Schema Generation and Validation](#schema-generation-and-validation)
|
||||
- [Discovery vs Manual Registration](#discovery-vs-manual-registration)
|
||||
|
|
@ -504,6 +505,33 @@ public function generatePrompt(string $topic, string $style): array
|
|||
|
||||
**Recommendation**: Use `PromptGetException` when you want to communicate specific errors to clients. Any other exception will still be converted to JSON-RPC compliant errors but with generic error messages.
|
||||
|
||||
## Logging
|
||||
|
||||
The SDK provides support to send structured log messages to clients. All standard PSR-3 log levels are supported.
|
||||
Level **warning** as the default level.
|
||||
|
||||
### Usage
|
||||
|
||||
The SDK automatically injects a `RequestContext` instance into handlers. This can be used to create a `ClientLogger`.
|
||||
|
||||
```php
|
||||
use Mcp\Capability\Logger\ClientLogger;
|
||||
use Mcp\Server\RequestContext;
|
||||
|
||||
#[McpTool]
|
||||
public function processData(string $input, RequestContext $context): array {
|
||||
$logger = $context->getClientLogger();
|
||||
|
||||
$logger->info('Processing started', ['input' => $input]);
|
||||
$logger->warning('Deprecated API used');
|
||||
|
||||
// ... processing logic ...
|
||||
|
||||
$logger->info('Processing completed');
|
||||
return ['result' => 'processed'];
|
||||
}
|
||||
```
|
||||
|
||||
## Completion Providers
|
||||
|
||||
Completion providers help MCP clients offer auto-completion suggestions for Resource Templates and Prompts. Unlike Tools and static Resources (which can be listed via `tools/list` and `resources/list`), Resource Templates and Prompts have dynamic parameters that benefit from completion hints.
|
||||
|
|
|
|||
|
|
@ -14,14 +14,11 @@ namespace Mcp\Example\ClientCommunication;
|
|||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Schema\Content\TextContent;
|
||||
use Mcp\Schema\Enum\LoggingLevel;
|
||||
use Mcp\Server\ClientAwareInterface;
|
||||
use Mcp\Server\ClientAwareTrait;
|
||||
use Mcp\Server\RequestContext;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
final class ClientAwareService implements ClientAwareInterface
|
||||
final class ClientAwareService
|
||||
{
|
||||
use ClientAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
|
|
@ -32,9 +29,10 @@ final class ClientAwareService implements ClientAwareInterface
|
|||
* @return array{incident: string, recommended_actions: string, model: string}
|
||||
*/
|
||||
#[McpTool('coordinate_incident_response', 'Coordinate an incident response with logging, progress, and sampling.')]
|
||||
public function coordinateIncident(string $incidentTitle): array
|
||||
public function coordinateIncident(RequestContext $context, string $incidentTitle): array
|
||||
{
|
||||
$this->log(LoggingLevel::Warning, \sprintf('Incident triage started: %s', $incidentTitle));
|
||||
$clientGateway = $context->getClientGateway();
|
||||
$clientGateway->log(LoggingLevel::Warning, \sprintf('Incident triage started: %s', $incidentTitle));
|
||||
|
||||
$steps = [
|
||||
'Collecting telemetry',
|
||||
|
|
@ -45,7 +43,7 @@ final class ClientAwareService implements ClientAwareInterface
|
|||
foreach ($steps as $index => $step) {
|
||||
$progress = ($index + 1) / \count($steps);
|
||||
|
||||
$this->progress($progress, 1, $step);
|
||||
$clientGateway->progress($progress, 1, $step);
|
||||
|
||||
usleep(180_000); // Simulate work being done
|
||||
}
|
||||
|
|
@ -56,11 +54,11 @@ final class ClientAwareService implements ClientAwareInterface
|
|||
implode(', ', $steps)
|
||||
);
|
||||
|
||||
$result = $this->sample($prompt, 350, 90, ['temperature' => 0.5]);
|
||||
$result = $clientGateway->sample($prompt, 350, 90, ['temperature' => 0.5]);
|
||||
|
||||
$recommendation = $result->content instanceof TextContent ? trim((string) $result->content->text) : '';
|
||||
|
||||
$this->log(LoggingLevel::Info, \sprintf('Incident triage completed for %s', $incidentTitle));
|
||||
$clientGateway->log(LoggingLevel::Info, \sprintf('Incident triage completed for %s', $incidentTitle));
|
||||
|
||||
return [
|
||||
'incident' => $incidentTitle,
|
||||
|
|
|
|||
81
examples/client-logging/LoggingShowcaseHandlers.php
Normal file
81
examples/client-logging/LoggingShowcaseHandlers.php
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Example\ClientLogging;
|
||||
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Capability\Logger\ClientLogger;
|
||||
use Mcp\Server\RequestContext;
|
||||
|
||||
/**
|
||||
* Example handlers showcasing auto-injected MCP logging capabilities.
|
||||
*
|
||||
* This demonstrates how handlers can receive ClientLogger automatically
|
||||
* without any manual configuration - just declare it as a parameter!
|
||||
*/
|
||||
final class LoggingShowcaseHandlers
|
||||
{
|
||||
/**
|
||||
* Tool that demonstrates different logging levels.
|
||||
*
|
||||
* @param string $message The message to log
|
||||
* @param string $level The logging level (debug, info, warning, error)
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
#[McpTool(name: 'log_message', description: 'Demonstrates MCP logging with different levels')]
|
||||
public function logMessage(RequestContext $context, string $message, string $level): array
|
||||
{
|
||||
$logger = $context->getClientLogger();
|
||||
$logger->info('🚀 Starting log_message tool', [
|
||||
'requested_level' => $level,
|
||||
'message_length' => \strlen($message),
|
||||
]);
|
||||
|
||||
switch (strtolower($level)) {
|
||||
case 'debug':
|
||||
$logger->debug("Debug: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'info':
|
||||
$logger->info("Info: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'notice':
|
||||
$logger->notice("Notice: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'warning':
|
||||
$logger->warning("Warning: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'error':
|
||||
$logger->error("Error: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'critical':
|
||||
$logger->critical("Critical: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'alert':
|
||||
$logger->alert("Alert: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
case 'emergency':
|
||||
$logger->emergency("Emergency: $message", ['tool' => 'log_message']);
|
||||
break;
|
||||
default:
|
||||
$logger->warning("Unknown level '$level', defaulting to info");
|
||||
$logger->info("Info: $message", ['tool' => 'log_message']);
|
||||
}
|
||||
|
||||
$logger->debug('log_message tool completed successfully');
|
||||
|
||||
return [
|
||||
'message' => "Logged message with level: $level",
|
||||
'logged_at' => date('Y-m-d H:i:s'),
|
||||
'level_used' => $level,
|
||||
];
|
||||
}
|
||||
}
|
||||
29
examples/client-logging/server.php
Normal file
29
examples/client-logging/server.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
chdir(__DIR__);
|
||||
|
||||
use Mcp\Server;
|
||||
|
||||
$server = Server::builder()
|
||||
->setServerInfo('Client Logging', '1.0.0', 'Demonstration of MCP logging in capability handlers.')
|
||||
->setContainer(container())
|
||||
->setLogger(logger())
|
||||
->setDiscovery(__DIR__)
|
||||
->build();
|
||||
|
||||
$result = $server->run(transport());
|
||||
|
||||
logger()->info('Server listener stopped gracefully.', ['result' => $result]);
|
||||
|
||||
shutdown($result);
|
||||
|
|
@ -13,6 +13,7 @@ namespace Mcp\Capability\Discovery;
|
|||
|
||||
use Mcp\Capability\Attribute\Schema;
|
||||
use Mcp\Server\ClientGateway;
|
||||
use Mcp\Server\RequestContext;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||
|
||||
/**
|
||||
|
|
@ -415,7 +416,7 @@ class SchemaGenerator
|
|||
if ($reflectionType instanceof \ReflectionNamedType && !$reflectionType->isBuiltin()) {
|
||||
$typeName = $reflectionType->getName();
|
||||
|
||||
if (is_a($typeName, ClientGateway::class, true)) {
|
||||
if (is_a($typeName, ClientGateway::class, true) || is_a($typeName, RequestContext::class, true)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
99
src/Capability/Logger/ClientLogger.php
Normal file
99
src/Capability/Logger/ClientLogger.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Capability\Logger;
|
||||
|
||||
use Mcp\Schema\Enum\LoggingLevel;
|
||||
use Mcp\Server\ClientGateway;
|
||||
use Mcp\Server\Protocol;
|
||||
use Mcp\Server\Session\SessionInterface;
|
||||
use Psr\Log\AbstractLogger;
|
||||
|
||||
/**
|
||||
* MCP-aware PSR-3 logger that sends log messages as MCP notifications.
|
||||
*
|
||||
* @author Adam Jamiu <jamiuadam120@gmail.com>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class ClientLogger extends AbstractLogger
|
||||
{
|
||||
public function __construct(
|
||||
private ClientGateway $client,
|
||||
private SessionInterface $session,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs with an arbitrary level.
|
||||
*
|
||||
* @param string|\Stringable $message
|
||||
* @param array<string, mixed> $context
|
||||
*/
|
||||
public function log($level, $message, array $context = []): void
|
||||
{
|
||||
// Convert PSR-3 level to MCP LoggingLevel
|
||||
$mcpLevel = $this->convertToMcpLevel($level);
|
||||
if (null === $mcpLevel) {
|
||||
return; // Unknown level, skip MCP notification
|
||||
}
|
||||
|
||||
$minimumLevel = $this->session->get(Protocol::SESSION_LOGGING_LEVEL, '');
|
||||
$minimumLevel = LoggingLevel::tryFrom($minimumLevel) ?? LoggingLevel::Warning;
|
||||
|
||||
if ($this->getSeverityIndex($minimumLevel) > $this->getSeverityIndex($mcpLevel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->client->log($mcpLevel, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts PSR-3 log level to MCP LoggingLevel.
|
||||
*
|
||||
* @param mixed $level PSR-3 level
|
||||
*
|
||||
* @return LoggingLevel|null MCP level or null if unknown
|
||||
*/
|
||||
private function convertToMcpLevel($level): ?LoggingLevel
|
||||
{
|
||||
return match (strtolower((string) $level)) {
|
||||
'emergency' => LoggingLevel::Emergency,
|
||||
'alert' => LoggingLevel::Alert,
|
||||
'critical' => LoggingLevel::Critical,
|
||||
'error' => LoggingLevel::Error,
|
||||
'warning' => LoggingLevel::Warning,
|
||||
'notice' => LoggingLevel::Notice,
|
||||
'info' => LoggingLevel::Info,
|
||||
'debug' => LoggingLevel::Debug,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the severity index for this log level.
|
||||
* Higher values indicate more severe log levels.
|
||||
*
|
||||
* @return int Severity index (0-7, where 7 is most severe)
|
||||
*/
|
||||
private function getSeverityIndex(LoggingLevel $level): int
|
||||
{
|
||||
return match ($level) {
|
||||
LoggingLevel::Debug => 0,
|
||||
LoggingLevel::Info => 1,
|
||||
LoggingLevel::Notice => 2,
|
||||
LoggingLevel::Warning => 3,
|
||||
LoggingLevel::Error => 4,
|
||||
LoggingLevel::Critical => 5,
|
||||
LoggingLevel::Alert => 6,
|
||||
LoggingLevel::Emergency => 7,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,7 @@ namespace Mcp\Capability\Registry;
|
|||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Exception\RegistryException;
|
||||
use Mcp\Server\ClientAwareInterface;
|
||||
use Mcp\Server\ClientGateway;
|
||||
use Mcp\Server\RequestContext;
|
||||
use Mcp\Server\Session\SessionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
|
|
@ -41,10 +40,6 @@ final class ReferenceHandler implements ReferenceHandlerInterface
|
|||
$instance = $this->getClassInstance($reference->handler);
|
||||
$arguments = $this->prepareArguments($reflection, $arguments);
|
||||
|
||||
if ($instance instanceof ClientAwareInterface) {
|
||||
$instance->setClient(new ClientGateway($session));
|
||||
}
|
||||
|
||||
return \call_user_func($instance, ...$arguments);
|
||||
}
|
||||
|
||||
|
|
@ -67,11 +62,6 @@ final class ReferenceHandler implements ReferenceHandlerInterface
|
|||
[$className, $methodName] = $reference->handler;
|
||||
$reflection = new \ReflectionMethod($className, $methodName);
|
||||
$instance = $this->getClassInstance($className);
|
||||
|
||||
if ($instance instanceof ClientAwareInterface) {
|
||||
$instance->setClient(new ClientGateway($session));
|
||||
}
|
||||
|
||||
$arguments = $this->prepareArguments($reflection, $arguments);
|
||||
|
||||
return \call_user_func([$instance, $methodName], ...$arguments);
|
||||
|
|
@ -108,8 +98,8 @@ final class ReferenceHandler implements ReferenceHandlerInterface
|
|||
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
|
||||
$typeName = $type->getName();
|
||||
|
||||
if (ClientGateway::class === $typeName && isset($arguments['_session'])) {
|
||||
$finalArgs[$paramPosition] = new ClientGateway($arguments['_session']);
|
||||
if (RequestContext::class === $typeName && isset($arguments['_session'], $arguments['_request'])) {
|
||||
$finalArgs[$paramPosition] = new RequestContext($arguments['_session'], $arguments['_request']);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -156,10 +146,6 @@ final class ReferenceHandler implements ReferenceHandlerInterface
|
|||
if (\is_array($handler) && 2 === \count($handler)) {
|
||||
[$class, $method] = $handler;
|
||||
|
||||
if ($class instanceof ClientAwareInterface) {
|
||||
$class->setClient(new ClientGateway($session));
|
||||
}
|
||||
|
||||
return new \ReflectionMethod($class, $method);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ final class SetLogLevelRequest extends Request
|
|||
|
||||
protected static function fromParams(?array $params): static
|
||||
{
|
||||
if (!isset($params['level']) || !\is_string($params['level']) || empty($params['level'])) {
|
||||
if (!isset($params['level']) || !\is_string($params['level']) || '' === $params['level']) {
|
||||
throw new InvalidArgumentException('Missing or invalid "level" parameter for "logging/setLevel".');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ final class Builder
|
|||
resourcesListChanged: $this->eventDispatcher instanceof EventDispatcherInterface,
|
||||
prompts: $registry->hasPrompts(),
|
||||
promptsListChanged: $this->eventDispatcher instanceof EventDispatcherInterface,
|
||||
logging: false,
|
||||
logging: true,
|
||||
completions: true,
|
||||
);
|
||||
|
||||
|
|
@ -509,6 +509,7 @@ final class Builder
|
|||
new Handler\Request\ListToolsHandler($registry, $this->paginationLimit),
|
||||
new Handler\Request\PingHandler(),
|
||||
new Handler\Request\ReadResourceHandler($registry, $referenceHandler, $logger),
|
||||
new Handler\Request\SetLogLevelHandler(),
|
||||
]);
|
||||
|
||||
$notificationHandlers = array_merge($this->notificationHandlers, [
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Server;
|
||||
|
||||
interface ClientAwareInterface
|
||||
{
|
||||
public function setClient(ClientGateway $clientGateway): void;
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Server;
|
||||
|
||||
use Mcp\Schema\Enum\LoggingLevel;
|
||||
use Mcp\Schema\JsonRpc\Notification;
|
||||
use Mcp\Schema\Result\CreateSamplingMessageResult;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type SampleOptions from ClientGateway
|
||||
*/
|
||||
trait ClientAwareTrait
|
||||
{
|
||||
private ClientGateway $client;
|
||||
|
||||
public function setClient(ClientGateway $client): void
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
private function notify(Notification $notification): void
|
||||
{
|
||||
$this->client->notify($notification);
|
||||
}
|
||||
|
||||
private function log(LoggingLevel $level, mixed $data, ?string $logger = null): void
|
||||
{
|
||||
$this->client->log($level, $data, $logger);
|
||||
}
|
||||
|
||||
private function progress(float $progress, ?float $total = null, ?string $message = null): void
|
||||
{
|
||||
$this->client->progress($progress, $total, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SampleOptions $options
|
||||
*/
|
||||
private function sample(string $prompt, int $maxTokens = 1000, int $timeout = 120, array $options = []): CreateSamplingMessageResult
|
||||
{
|
||||
return $this->client->sample($prompt, $maxTokens, $timeout, $options);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ use Mcp\Schema\Result\CreateSamplingMessageResult;
|
|||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* @final
|
||||
* Helper class for tools to communicate with the client.
|
||||
*
|
||||
* This class provides a clean API for element handlers to send requests and notifications
|
||||
|
|
@ -64,7 +65,7 @@ use Mcp\Server\Session\SessionInterface;
|
|||
*
|
||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||
*/
|
||||
final class ClientGateway
|
||||
class ClientGateway
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SessionInterface $session,
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ final class InitializedHandler implements NotificationHandlerInterface
|
|||
return $notification instanceof InitializedNotification;
|
||||
}
|
||||
|
||||
public function handle(Notification $message, SessionInterface $session): void
|
||||
public function handle(Notification $notification, SessionInterface $session): void
|
||||
{
|
||||
\assert($message instanceof InitializedNotification);
|
||||
\assert($notification instanceof InitializedNotification);
|
||||
|
||||
$session->set('initialized', true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ final class CallToolHandler implements RequestHandlerInterface
|
|||
$reference = $this->registry->getTool($toolName);
|
||||
|
||||
$arguments['_session'] = $session;
|
||||
$arguments['_request'] = $request;
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ final class GetPromptHandler implements RequestHandlerInterface
|
|||
$reference = $this->registry->getPrompt($promptName);
|
||||
|
||||
$arguments['_session'] = $session;
|
||||
$arguments['_request'] = $request;
|
||||
|
||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ final class ReadResourceHandler implements RequestHandlerInterface
|
|||
$arguments = [
|
||||
'uri' => $uri,
|
||||
'_session' => $session,
|
||||
'_request' => $request,
|
||||
];
|
||||
|
||||
if ($reference instanceof ResourceTemplateReference) {
|
||||
|
|
|
|||
49
src/Server/Handler/Request/SetLogLevelHandler.php
Normal file
49
src/Server/Handler/Request/SetLogLevelHandler.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Server\Handler\Request;
|
||||
|
||||
use Mcp\Schema\JsonRpc\Request;
|
||||
use Mcp\Schema\JsonRpc\Response;
|
||||
use Mcp\Schema\Request\SetLogLevelRequest;
|
||||
use Mcp\Schema\Result\EmptyResult;
|
||||
use Mcp\Server\Protocol;
|
||||
use Mcp\Server\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* Handler for the logging/setLevel request.
|
||||
*
|
||||
* Handles client requests to set the logging level for the server.
|
||||
* The server should send all logs at this level and higher (more severe) to the client.
|
||||
*
|
||||
* @implements RequestHandlerInterface<EmptyResult>
|
||||
*
|
||||
* @author Adam Jamiu <jamiuadam120@gmail.com>
|
||||
*/
|
||||
final class SetLogLevelHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function supports(Request $request): bool
|
||||
{
|
||||
return $request instanceof SetLogLevelRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response<EmptyResult>
|
||||
*/
|
||||
public function handle(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
\assert($request instanceof SetLogLevelRequest);
|
||||
|
||||
$session->set(Protocol::SESSION_LOGGING_LEVEL, $request->level->value);
|
||||
|
||||
return new Response($request->getId(), new EmptyResult());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue