Fix & clean up examples (#78)
This commit is contained in:
parent
32b8b2ea61
commit
8defd9b17f
22 changed files with 136 additions and 397 deletions
23
README.md
23
README.md
|
|
@ -22,29 +22,16 @@ Until the first major release, this SDK is considered
|
||||||
|
|
||||||
Features
|
Features
|
||||||
- [x] Bring back PHP-MCP examples
|
- [x] Bring back PHP-MCP examples
|
||||||
- [ ] Glue handler, registry and reference handlers
|
- [x] Glue handler, registry and reference handlers
|
||||||
- [ ] Revive `ServerBuilder`
|
- [x] Revive `ServerBuilder`
|
||||||
- [ ] Revive transports
|
- [x] Revive transports
|
||||||
- [ ] Streamable Transport https://github.com/modelcontextprotocol/php-sdk/issues/7
|
- [x] Streamable Transport https://github.com/modelcontextprotocol/php-sdk/issues/7
|
||||||
- [ ] Http/SSE-based Transport https://github.com/modelcontextprotocol/php-sdk/issues/8
|
- [ ] ~~Http/SSE-based Transport https://github.com/modelcontextprotocol/php-sdk/issues/8~~
|
||||||
- [ ] Support pagination
|
- [ ] Support pagination
|
||||||
- [ ] Support Schema validation
|
- [ ] Support Schema validation
|
||||||
- [ ] Support multiple versions of the MCP specification https://github.com/modelcontextprotocol/php-sdk/issues/14
|
- [ ] Support multiple versions of the MCP specification https://github.com/modelcontextprotocol/php-sdk/issues/14
|
||||||
- [ ] (Re-)Implement missing Notification & Request Handlers https://github.com/modelcontextprotocol/php-sdk/issues/9
|
- [ ] (Re-)Implement missing Notification & Request Handlers https://github.com/modelcontextprotocol/php-sdk/issues/9
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Examples working
|
|
||||||
- [x] 01-discovery-stdio-calculator
|
|
||||||
- [ ] 02-discovery-http-userprofile
|
|
||||||
- [x] 03-manual-registration-stdio
|
|
||||||
- [ ] 04-combined-registration-http
|
|
||||||
- [ ] 05-stdio-env-variables
|
|
||||||
- [ ] 06-custom-dependencies-stdio
|
|
||||||
- [ ] 07-complex-tool-schema-http
|
|
||||||
- [ ] 08-schema-showcase-streamable
|
|
||||||
- [ ] 09-standalone-cli
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use Psr\Log\NullLogger;
|
||||||
/**
|
/**
|
||||||
* @phpstan-type Config array{precision: int, allow_negative: bool}
|
* @phpstan-type Config array{precision: int, allow_negative: bool}
|
||||||
*/
|
*/
|
||||||
class McpElements
|
final class McpElements
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Config
|
* @var Config
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,16 @@ use Mcp\Capability\Attribute\McpResourceTemplate;
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class McpElements
|
/**
|
||||||
|
* @phpstan-type User array{name: string, email: string, role: string}
|
||||||
|
*/
|
||||||
|
final class McpElements
|
||||||
{
|
{
|
||||||
// Simulate a simple user database
|
/**
|
||||||
|
* Simulate a simple user database.
|
||||||
|
*
|
||||||
|
* @var array<int, User>
|
||||||
|
*/
|
||||||
private array $users = [
|
private array $users = [
|
||||||
'101' => ['name' => 'Alice', 'email' => 'alice@example.com', 'role' => 'admin'],
|
'101' => ['name' => 'Alice', 'email' => 'alice@example.com', 'role' => 'admin'],
|
||||||
'102' => ['name' => 'Bob', 'email' => 'bob@example.com', 'role' => 'user'],
|
'102' => ['name' => 'Bob', 'email' => 'bob@example.com', 'role' => 'user'],
|
||||||
|
|
@ -28,7 +35,7 @@ class McpElements
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
$this->logger->debug('HttpUserProfileExample McpElements instantiated.');
|
$this->logger->debug('HttpUserProfileExample McpElements instantiated.');
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +45,7 @@ class McpElements
|
||||||
*
|
*
|
||||||
* @param string $userId the ID of the user (from URI)
|
* @param string $userId the ID of the user (from URI)
|
||||||
*
|
*
|
||||||
* @return array user profile data
|
* @return User user profile data
|
||||||
*
|
*
|
||||||
* @throws McpServerException if the user is not found
|
* @throws McpServerException if the user is not found
|
||||||
*/
|
*/
|
||||||
|
|
@ -64,7 +71,7 @@ class McpElements
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of all known user IDs.
|
* Retrieves a list of all known user IDs.
|
||||||
*
|
*
|
||||||
* @return array list of user IDs
|
* @return int[] list of user IDs
|
||||||
*/
|
*/
|
||||||
#[McpResource(
|
#[McpResource(
|
||||||
uri: 'user://list/ids',
|
uri: 'user://list/ids',
|
||||||
|
|
@ -86,7 +93,7 @@ class McpElements
|
||||||
* @param string $userId the ID of the user to message
|
* @param string $userId the ID of the user to message
|
||||||
* @param string|null $customMessage an optional custom message part
|
* @param string|null $customMessage an optional custom message part
|
||||||
*
|
*
|
||||||
* @return array status of the operation
|
* @return array<string, bool|string> status of the operation
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'send_welcome')]
|
#[McpTool(name: 'send_welcome')]
|
||||||
public function sendWelcomeMessage(string $userId, ?string $customMessage = null): array
|
public function sendWelcomeMessage(string $userId, ?string $customMessage = null): array
|
||||||
|
|
@ -106,6 +113,9 @@ class McpElements
|
||||||
return ['success' => true, 'message_sent' => $message];
|
return ['success' => true, 'message_sent' => $message];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, bool|string>
|
||||||
|
*/
|
||||||
#[McpTool(name: 'test_tool_without_params')]
|
#[McpTool(name: 'test_tool_without_params')]
|
||||||
public function testToolWithoutParams(): array
|
public function testToolWithoutParams(): array
|
||||||
{
|
{
|
||||||
|
|
@ -118,7 +128,7 @@ class McpElements
|
||||||
* @param string $userId the user ID to generate the bio for
|
* @param string $userId the user ID to generate the bio for
|
||||||
* @param string $tone Desired tone (e.g., 'formal', 'casual').
|
* @param string $tone Desired tone (e.g., 'formal', 'casual').
|
||||||
*
|
*
|
||||||
* @return array prompt messages
|
* @return array<string, string>[] prompt messages
|
||||||
*
|
*
|
||||||
* @throws McpServerException if user not found
|
* @throws McpServerException if user not found
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@ namespace Mcp\Example\HttpUserProfileExample;
|
||||||
|
|
||||||
use Mcp\Capability\Prompt\Completion\ProviderInterface;
|
use Mcp\Capability\Prompt\Completion\ProviderInterface;
|
||||||
|
|
||||||
class UserIdCompletionProvider implements ProviderInterface
|
final class UserIdCompletionProvider implements ProviderInterface
|
||||||
{
|
{
|
||||||
|
private const AVAILABLE_USER_IDS = ['101', '102', '103'];
|
||||||
|
|
||||||
public function getCompletions(string $currentValue): array
|
public function getCompletions(string $currentValue): array
|
||||||
{
|
{
|
||||||
$availableUserIds = ['101', '102', '103'];
|
return array_filter(self::AVAILABLE_USER_IDS, fn (string $userId) => str_contains($userId, $currentValue));
|
||||||
|
|
||||||
return array_filter($availableUserIds, fn (string $userId) => str_contains($userId, $currentValue));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ $server = Server::make()
|
||||||
function (): array {
|
function (): array {
|
||||||
$memoryUsage = memory_get_usage(true);
|
$memoryUsage = memory_get_usage(true);
|
||||||
$memoryPeak = memory_get_peak_usage(true);
|
$memoryPeak = memory_get_peak_usage(true);
|
||||||
$uptime = time() - $_SERVER['REQUEST_TIME_FLOAT'] ?? time();
|
$uptime = time() - ($_SERVER['REQUEST_TIME_FLOAT'] ?? time());
|
||||||
$serverSoftware = $_SERVER['SERVER_SOFTWARE'] ?? 'CLI';
|
$serverSoftware = $_SERVER['SERVER_SOFTWARE'] ?? 'CLI';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Mcp\Example\ManualStdioExample;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class SimpleHandlers
|
final class SimpleHandlers
|
||||||
{
|
{
|
||||||
private string $appVersion = '1.0-manual';
|
private string $appVersion = '1.0-manual';
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ class SimpleHandlers
|
||||||
*
|
*
|
||||||
* @param string $userName the name of the user
|
* @param string $userName the name of the user
|
||||||
*
|
*
|
||||||
* @return array the prompt messages
|
* @return array<string, string>[] the prompt messages
|
||||||
*/
|
*/
|
||||||
public function greetingPrompt(string $userName): array
|
public function greetingPrompt(string $userName): array
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +70,7 @@ class SimpleHandlers
|
||||||
*
|
*
|
||||||
* @param string $itemId the ID of the item
|
* @param string $itemId the ID of the item
|
||||||
*
|
*
|
||||||
* @return array item details
|
* @return array<string, string> item details
|
||||||
*/
|
*/
|
||||||
public function getItemDetails(string $itemId): array
|
public function getItemDetails(string $itemId): array
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Mcp\Example\CombinedHttpExample;
|
||||||
use Mcp\Capability\Attribute\McpResource;
|
use Mcp\Capability\Attribute\McpResource;
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
|
|
||||||
class DiscoveredElements
|
final class DiscoveredElements
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* A tool discovered via attributes.
|
* A tool discovered via attributes.
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ namespace Mcp\Example\CombinedHttpExample;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class ManualHandlers
|
final class ManualHandlers
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ require_once dirname(__DIR__).'/bootstrap.php';
|
||||||
chdir(__DIR__);
|
chdir(__DIR__);
|
||||||
|
|
||||||
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
|
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||||
use Mcp\CombinedHttpExample\Manual\ManualHandlers;
|
use Mcp\Example\CombinedHttpExample\ManualHandlers;
|
||||||
use Mcp\Server;
|
use Mcp\Server;
|
||||||
use Mcp\Server\Session\FileSessionStore;
|
use Mcp\Server\Session\FileSessionStore;
|
||||||
use Mcp\Server\Transport\StreamableHttpTransport;
|
use Mcp\Server\Transport\StreamableHttpTransport;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Mcp\Example\StdioEnvVariables;
|
||||||
|
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
|
|
||||||
class EnvToolHandler
|
final class EnvToolHandler
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Performs an action that can be modified by an environment variable.
|
* Performs an action that can be modified by an environment variable.
|
||||||
|
|
@ -21,7 +21,7 @@ class EnvToolHandler
|
||||||
*
|
*
|
||||||
* @param string $input some input data
|
* @param string $input some input data
|
||||||
*
|
*
|
||||||
* @return array the result, varying by APP_MODE
|
* @return array<string, string|int> the result, varying by APP_MODE
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'process_data_by_mode')]
|
#[McpTool(name: 'process_data_by_mode')]
|
||||||
public function processData(string $input): array
|
public function processData(string $input): array
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,19 @@ namespace Mcp\Example\DependenciesStdioExample;
|
||||||
|
|
||||||
use Mcp\Capability\Attribute\McpResource;
|
use Mcp\Capability\Attribute\McpResource;
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
use Mcp\DependenciesStdioExample\Services\StatsServiceInterface;
|
use Mcp\Example\DependenciesStdioExample\Service\StatsServiceInterface;
|
||||||
use Mcp\DependenciesStdioExample\Services\TaskRepositoryInterface;
|
use Mcp\Example\DependenciesStdioExample\Service\TaskRepositoryInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class McpTaskHandlers
|
/**
|
||||||
|
* @phpstan-import-type Task from TaskRepositoryInterface
|
||||||
|
*/
|
||||||
|
final class McpTaskHandlers
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private TaskRepositoryInterface $taskRepo,
|
private readonly TaskRepositoryInterface $taskRepo,
|
||||||
private StatsServiceInterface $statsService,
|
private readonly StatsServiceInterface $statsService,
|
||||||
private LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
$this->logger->info('McpTaskHandlers instantiated with dependencies.');
|
$this->logger->info('McpTaskHandlers instantiated with dependencies.');
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +36,7 @@ class McpTaskHandlers
|
||||||
* @param string $userId the ID of the user
|
* @param string $userId the ID of the user
|
||||||
* @param string $description the task description
|
* @param string $description the task description
|
||||||
*
|
*
|
||||||
* @return array the created task details
|
* @return Task the created task details
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'add_task')]
|
#[McpTool(name: 'add_task')]
|
||||||
public function addTask(string $userId, string $description): array
|
public function addTask(string $userId, string $description): array
|
||||||
|
|
@ -48,7 +51,7 @@ class McpTaskHandlers
|
||||||
*
|
*
|
||||||
* @param string $userId the ID of the user
|
* @param string $userId the ID of the user
|
||||||
*
|
*
|
||||||
* @return array a list of tasks
|
* @return Task[] a list of tasks
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'list_user_tasks')]
|
#[McpTool(name: 'list_user_tasks')]
|
||||||
public function listUserTasks(string $userId): array
|
public function listUserTasks(string $userId): array
|
||||||
|
|
@ -63,7 +66,7 @@ class McpTaskHandlers
|
||||||
*
|
*
|
||||||
* @param int $taskId the ID of the task to complete
|
* @param int $taskId the ID of the task to complete
|
||||||
*
|
*
|
||||||
* @return array status of the operation
|
* @return array<string, mixed> status of the operation
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'complete_task')]
|
#[McpTool(name: 'complete_task')]
|
||||||
public function completeTask(int $taskId): array
|
public function completeTask(int $taskId): array
|
||||||
|
|
@ -77,7 +80,7 @@ class McpTaskHandlers
|
||||||
/**
|
/**
|
||||||
* Provides current system statistics.
|
* Provides current system statistics.
|
||||||
*
|
*
|
||||||
* @return array system statistics
|
* @return array<string, int> system statistics
|
||||||
*/
|
*/
|
||||||
#[McpResource(uri: 'stats://system/overview', name: 'system_stats', mimeType: 'application/json')]
|
#[McpResource(uri: 'stats://system/overview', name: 'system_stats', mimeType: 'application/json')]
|
||||||
public function getSystemStatistics(): array
|
public function getSystemStatistics(): array
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,20 @@ namespace Mcp\Example\DependenciesStdioExample\Service;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class InMemoryTaskRepository implements TaskRepositoryInterface
|
/**
|
||||||
|
* @phpstan-import-type Task from TaskRepositoryInterface
|
||||||
|
*/
|
||||||
|
final class InMemoryTaskRepository implements TaskRepositoryInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var array<int, Task>
|
||||||
|
*/
|
||||||
private array $tasks = [];
|
private array $tasks = [];
|
||||||
|
|
||||||
private int $nextTaskId = 1;
|
private int $nextTaskId = 1;
|
||||||
|
|
||||||
private LoggerInterface $logger;
|
public function __construct(
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
public function __construct(LoggerInterface $logger)
|
) {
|
||||||
{
|
|
||||||
$this->logger = $logger;
|
|
||||||
// Add some initial tasks
|
// Add some initial tasks
|
||||||
$this->addTask('user1', 'Buy groceries');
|
$this->addTask('user1', 'Buy groceries');
|
||||||
$this->addTask('user1', 'Write MCP example');
|
$this->addTask('user1', 'Write MCP example');
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,8 @@ namespace Mcp\Example\DependenciesStdioExample\Service;
|
||||||
|
|
||||||
interface StatsServiceInterface
|
interface StatsServiceInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @return array<string, int>
|
||||||
|
*/
|
||||||
public function getSystemStats(): array;
|
public function getSystemStats(): array;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,11 @@
|
||||||
|
|
||||||
namespace Mcp\Example\DependenciesStdioExample\Service;
|
namespace Mcp\Example\DependenciesStdioExample\Service;
|
||||||
|
|
||||||
class SystemStatsService implements StatsServiceInterface
|
final class SystemStatsService implements StatsServiceInterface
|
||||||
{
|
{
|
||||||
private TaskRepositoryInterface $taskRepository;
|
public function __construct(
|
||||||
|
private readonly TaskRepositoryInterface $taskRepository,
|
||||||
public function __construct(TaskRepositoryInterface $taskRepository)
|
) {
|
||||||
{
|
|
||||||
$this->taskRepository = $taskRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSystemStats(): array
|
public function getSystemStats(): array
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,24 @@
|
||||||
|
|
||||||
namespace Mcp\Example\DependenciesStdioExample\Service;
|
namespace Mcp\Example\DependenciesStdioExample\Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-type Task array{id: int, userId: string, description: string, completed: bool, createdAt: string}
|
||||||
|
*/
|
||||||
interface TaskRepositoryInterface
|
interface TaskRepositoryInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @return Task
|
||||||
|
*/
|
||||||
public function addTask(string $userId, string $description): array;
|
public function addTask(string $userId, string $description): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Task[]
|
||||||
|
*/
|
||||||
public function getTasksForUser(string $userId): array;
|
public function getTasksForUser(string $userId): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Task[]
|
||||||
|
*/
|
||||||
public function getAllTasks(): array;
|
public function getAllTasks(): array;
|
||||||
|
|
||||||
public function completeTask(int $taskId): bool;
|
public function completeTask(int $taskId): bool;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@
|
||||||
require_once dirname(__DIR__).'/bootstrap.php';
|
require_once dirname(__DIR__).'/bootstrap.php';
|
||||||
chdir(__DIR__);
|
chdir(__DIR__);
|
||||||
|
|
||||||
use Mcp\DependenciesStdioExample\Services;
|
use Mcp\Example\DependenciesStdioExample\Service\InMemoryTaskRepository;
|
||||||
|
use Mcp\Example\DependenciesStdioExample\Service\StatsServiceInterface;
|
||||||
|
use Mcp\Example\DependenciesStdioExample\Service\SystemStatsService;
|
||||||
|
use Mcp\Example\DependenciesStdioExample\Service\TaskRepositoryInterface;
|
||||||
use Mcp\Server;
|
use Mcp\Server;
|
||||||
use Mcp\Server\Transport\StdioTransport;
|
use Mcp\Server\Transport\StdioTransport;
|
||||||
|
|
||||||
|
|
@ -21,11 +24,11 @@ logger()->info('Starting MCP Custom Dependencies (Stdio) Server...');
|
||||||
|
|
||||||
$container = container();
|
$container = container();
|
||||||
|
|
||||||
$taskRepo = new Services\InMemoryTaskRepository(logger());
|
$taskRepo = new InMemoryTaskRepository(logger());
|
||||||
$container->set(Services\TaskRepositoryInterface::class, $taskRepo);
|
$container->set(TaskRepositoryInterface::class, $taskRepo);
|
||||||
|
|
||||||
$statsService = new Services\SystemStatsService($taskRepo);
|
$statsService = new SystemStatsService($taskRepo);
|
||||||
$container->set(Services\StatsServiceInterface::class, $statsService);
|
$container->set(StatsServiceInterface::class, $statsService);
|
||||||
|
|
||||||
$server = Server::make()
|
$server = Server::make()
|
||||||
->setServerInfo('Task Manager Server', '1.0.0')
|
->setServerInfo('Task Manager Server', '1.0.0')
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@
|
||||||
namespace Mcp\Example\ComplexSchemaHttpExample;
|
namespace Mcp\Example\ComplexSchemaHttpExample;
|
||||||
|
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
use Mcp\ComplexSchemaHttpExample\Model\EventPriority;
|
use Mcp\Example\ComplexSchemaHttpExample\Model\EventPriority;
|
||||||
use Mcp\ComplexSchemaHttpExample\Model\EventType;
|
use Mcp\Example\ComplexSchemaHttpExample\Model\EventType;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class McpEventScheduler
|
final class McpEventScheduler
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,17 +35,17 @@ class McpEventScheduler
|
||||||
* @param string[]|null $attendees an optional list of attendee email addresses
|
* @param string[]|null $attendees an optional list of attendee email addresses
|
||||||
* @param bool $sendInvites send calendar invites to attendees? Defaults to true if attendees are provided
|
* @param bool $sendInvites send calendar invites to attendees? Defaults to true if attendees are provided
|
||||||
*
|
*
|
||||||
* @return array confirmation of the scheduled event
|
* @return array<string, mixed> confirmation of the scheduled event
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'schedule_event')]
|
#[McpTool(name: 'schedule_event')]
|
||||||
public function scheduleEvent(
|
public function scheduleEvent(
|
||||||
string $title,
|
string $title,
|
||||||
string $date,
|
string $date,
|
||||||
EventType $type,
|
EventType $type,
|
||||||
?string $time = null, // Optional, nullable
|
?string $time = null,
|
||||||
EventPriority $priority = EventPriority::Normal, // Optional with enum default
|
EventPriority $priority = EventPriority::Normal,
|
||||||
?array $attendees = null, // Optional array of strings, nullable
|
?array $attendees = null,
|
||||||
bool $sendInvites = true, // Optional with default
|
bool $sendInvites = true,
|
||||||
): array {
|
): array {
|
||||||
$this->logger->info("Tool 'schedule_event' called", compact('title', 'date', 'type', 'time', 'priority', 'attendees', 'sendInvites'));
|
$this->logger->info("Tool 'schedule_event' called", compact('title', 'date', 'type', 'time', 'priority', 'attendees', 'sendInvites'));
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ class McpEventScheduler
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => "Event '{$title}' scheduled successfully for {$date}.",
|
'message' => \sprintf('Event "%s" scheduled successfully for "%s".', $title, $date),
|
||||||
'event_details' => $eventDetails,
|
'event_details' => $eventDetails,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,20 @@ namespace Mcp\Example\SchemaShowcaseExample;
|
||||||
|
|
||||||
use Mcp\Capability\Attribute\McpTool;
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
use Mcp\Capability\Attribute\Schema;
|
use Mcp\Capability\Attribute\Schema;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class SchemaShowcaseElements
|
final class SchemaShowcaseElements
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates and formats text with string constraints.
|
* Validates and formats text with string constraints.
|
||||||
* Demonstrates: minLength, maxLength, pattern validation.
|
* Demonstrates: minLength, maxLength, pattern validation.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(
|
#[McpTool(
|
||||||
name: 'format_text',
|
name: 'format_text',
|
||||||
|
|
@ -41,7 +49,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
string $format = 'sentence',
|
string $format = 'sentence',
|
||||||
): array {
|
): array {
|
||||||
fwrite(\STDERR, "Format text tool called: text='$text', format='$format'\n");
|
$this->logger->info(\sprintf('Tool format_text called with text: %s and format: %s', $text, $format));
|
||||||
|
|
||||||
$formatted = match ($format) {
|
$formatted = match ($format) {
|
||||||
'uppercase' => strtoupper($text),
|
'uppercase' => strtoupper($text),
|
||||||
|
|
@ -63,6 +71,8 @@ class SchemaShowcaseElements
|
||||||
* Performs mathematical operations with numeric constraints.
|
* Performs mathematical operations with numeric constraints.
|
||||||
*
|
*
|
||||||
* Demonstrates: METHOD-LEVEL Schema
|
* Demonstrates: METHOD-LEVEL Schema
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'calculate_range')]
|
#[McpTool(name: 'calculate_range')]
|
||||||
#[Schema(
|
#[Schema(
|
||||||
|
|
@ -97,7 +107,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
public function calculateRange(float $first, float $second, string $operation, int $precision = 2): array
|
public function calculateRange(float $first, float $second, string $operation, int $precision = 2): array
|
||||||
{
|
{
|
||||||
fwrite(\STDERR, "Calculate range tool called: $first $operation $second (precision: $precision)\n");
|
$this->logger->info(\sprintf('Tool calculate_range called with: %f %s %f (precision: %d)', $first, $operation, $second, $precision));
|
||||||
|
|
||||||
$result = match ($operation) {
|
$result = match ($operation) {
|
||||||
'add' => $first + $second,
|
'add' => $first + $second,
|
||||||
|
|
@ -126,6 +136,10 @@ class SchemaShowcaseElements
|
||||||
/**
|
/**
|
||||||
* Processes user profile data with object schema validation.
|
* Processes user profile data with object schema validation.
|
||||||
* Demonstrates: object properties, required fields, additionalProperties.
|
* Demonstrates: object properties, required fields, additionalProperties.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $profile
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(
|
#[McpTool(
|
||||||
name: 'validate_profile',
|
name: 'validate_profile',
|
||||||
|
|
@ -172,7 +186,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
array $profile,
|
array $profile,
|
||||||
): array {
|
): array {
|
||||||
fwrite(\STDERR, 'Validate profile tool called with: '.json_encode($profile)."\n");
|
$this->logger->info(\sprintf('Tool validate_profile called: %s', json_encode($profile)));
|
||||||
|
|
||||||
$errors = [];
|
$errors = [];
|
||||||
$warnings = [];
|
$warnings = [];
|
||||||
|
|
@ -203,6 +217,10 @@ class SchemaShowcaseElements
|
||||||
/**
|
/**
|
||||||
* Manages a list of items with array constraints.
|
* Manages a list of items with array constraints.
|
||||||
* Demonstrates: array items, minItems, maxItems, uniqueItems.
|
* Demonstrates: array items, minItems, maxItems, uniqueItems.
|
||||||
|
*
|
||||||
|
* @param string[] $items
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(
|
#[McpTool(
|
||||||
name: 'manage_list',
|
name: 'manage_list',
|
||||||
|
|
@ -230,7 +248,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
string $action = 'sort',
|
string $action = 'sort',
|
||||||
): array {
|
): array {
|
||||||
fwrite(\STDERR, 'Manage list tool called with '.\count($items)." items, action: $action\n");
|
$this->logger->info(\sprintf('Tool manage_list called with %d items, action: %s', \count($items), $action));
|
||||||
|
|
||||||
$original = $items;
|
$original = $items;
|
||||||
$processed = $items;
|
$processed = $items;
|
||||||
|
|
@ -273,6 +291,8 @@ class SchemaShowcaseElements
|
||||||
/**
|
/**
|
||||||
* Generates configuration with format validation.
|
* Generates configuration with format validation.
|
||||||
* Demonstrates: format constraints (date-time, uri, etc).
|
* Demonstrates: format constraints (date-time, uri, etc).
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(
|
#[McpTool(
|
||||||
name: 'generate_config',
|
name: 'generate_config',
|
||||||
|
|
@ -316,7 +336,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
int $port = 8080,
|
int $port = 8080,
|
||||||
): array {
|
): array {
|
||||||
fwrite(\STDERR, "Generate config tool called for app: $appName\n");
|
$this->logger->info(\sprintf('Tool generate_config called for app: %s at %s', $appName, $baseUrl));
|
||||||
|
|
||||||
$config = [
|
$config = [
|
||||||
'app' => [
|
'app' => [
|
||||||
|
|
@ -350,6 +370,10 @@ class SchemaShowcaseElements
|
||||||
/**
|
/**
|
||||||
* Processes time-based data with date-time format validation.
|
* Processes time-based data with date-time format validation.
|
||||||
* Demonstrates: date-time format, exclusiveMinimum, exclusiveMaximum.
|
* Demonstrates: date-time format, exclusiveMinimum, exclusiveMaximum.
|
||||||
|
*
|
||||||
|
* @param string[] $attendees
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
#[McpTool(
|
#[McpTool(
|
||||||
name: 'schedule_event',
|
name: 'schedule_event',
|
||||||
|
|
@ -398,7 +422,7 @@ class SchemaShowcaseElements
|
||||||
)]
|
)]
|
||||||
array $attendees = [],
|
array $attendees = [],
|
||||||
): array {
|
): array {
|
||||||
fwrite(\STDERR, "Schedule event tool called: $title at $startTime\n");
|
$this->logger->info(\sprintf('Tool schedule_event called: %s at %s for %.1f hours', $title, $startTime, $durationHours));
|
||||||
|
|
||||||
$start = \DateTime::createFromFormat(\DateTime::ISO8601, $startTime);
|
$start = \DateTime::createFromFormat(\DateTime::ISO8601, $startTime);
|
||||||
if (!$start) {
|
if (!$start) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ $request = $creator->fromGlobals();
|
||||||
|
|
||||||
$server = Server::make()
|
$server = Server::make()
|
||||||
->setServerInfo('Schema Showcase', '1.0.0')
|
->setServerInfo('Schema Showcase', '1.0.0')
|
||||||
|
->setContainer(container())
|
||||||
->setLogger(logger())
|
->setLogger(logger())
|
||||||
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
||||||
->setDiscovery(__DIR__, ['.'])
|
->setDiscovery(__DIR__, ['.'])
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,11 @@ README in the `examples/09-standalone-cli` directory.
|
||||||
|
|
||||||
For running an example, you execute the `server.php` like this:
|
For running an example, you execute the `server.php` like this:
|
||||||
```bash
|
```bash
|
||||||
|
# For examples using STDIO transport
|
||||||
php examples/01-discovery-stdio-calculator/server.php
|
php examples/01-discovery-stdio-calculator/server.php
|
||||||
|
|
||||||
|
# For examples using Streamable HTTP transport
|
||||||
|
php -S localhost:8000 examples/02-discovery-http-userprofile/server.php
|
||||||
```
|
```
|
||||||
|
|
||||||
You will see debug outputs to help you understand what is happening.
|
You will see debug outputs to help you understand what is happening.
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue