refactor: transport agnostic examples (#131)
This commit is contained in:
parent
fb3c1e65a6
commit
ff26b4ff61
46 changed files with 157 additions and 289 deletions
|
|
@ -52,17 +52,17 @@
|
|||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Mcp\\Example\\HttpCombinedRegistration\\": "examples/http-combined-registration/",
|
||||
"Mcp\\Example\\HttpComplexToolSchema\\": "examples/http-complex-tool-schema/",
|
||||
"Mcp\\Example\\HttpDiscoveryUserProfile\\": "examples/http-discovery-userprofile/",
|
||||
"Mcp\\Example\\HttpSchemaShowcase\\": "examples/http-schema-showcase/",
|
||||
"Mcp\\Example\\StdioCachedDiscovery\\": "examples/stdio-cached-discovery/",
|
||||
"Mcp\\Example\\StdioClientCommunication\\": "examples/stdio-client-communication/",
|
||||
"Mcp\\Example\\StdioCustomDependencies\\": "examples/stdio-custom-dependencies/",
|
||||
"Mcp\\Example\\StdioDiscoveryCalculator\\": "examples/stdio-discovery-calculator/",
|
||||
"Mcp\\Example\\StdioEnvVariables\\": "examples/stdio-env-variables/",
|
||||
"Mcp\\Example\\StdioExplicitRegistration\\": "examples/stdio-explicit-registration/",
|
||||
"Mcp\\Example\\CachedDiscovery\\": "examples/cached-discovery/",
|
||||
"Mcp\\Example\\ClientCommunication\\": "examples/client-communication/",
|
||||
"Mcp\\Example\\CombinedRegistration\\": "examples/combined-registration/",
|
||||
"Mcp\\Example\\ComplexToolSchema\\": "examples/complex-tool-schema/",
|
||||
"Mcp\\Example\\CustomDependencies\\": "examples/custom-dependencies/",
|
||||
"Mcp\\Example\\CustomMethodHandlers\\": "examples/custom-method-handlers/",
|
||||
"Mcp\\Example\\DiscoveryCalculator\\": "examples/discovery-calculator/",
|
||||
"Mcp\\Example\\DiscoveryUserProfile\\": "examples/discovery-userprofile/",
|
||||
"Mcp\\Example\\EnvVariables\\": "examples/env-variables/",
|
||||
"Mcp\\Example\\ExplicitRegistration\\": "examples/explicit-registration/",
|
||||
"Mcp\\Example\\SchemaShowcase\\": "examples/schema-showcase/",
|
||||
"Mcp\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ specific features and can be run independently to understand how the SDK works.
|
|||
|
||||
- [Getting Started](#getting-started)
|
||||
- [Running Examples](#running-examples)
|
||||
- [STDIO Examples](#stdio-examples)
|
||||
- [HTTP Examples](#http-examples)
|
||||
- [Advanced Patterns](#advanced-patterns)
|
||||
- [Testing and Debugging](#testing-and-debugging)
|
||||
- [Examples](#examples)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
@ -26,28 +23,30 @@ composer install
|
|||
|
||||
## Running Examples
|
||||
|
||||
### STDIO Examples
|
||||
The bootstrapping of the example will choose the used transport based on the SAPI you use.
|
||||
|
||||
STDIO examples use standard input/output for communication:
|
||||
### STDIO Transport
|
||||
|
||||
The STDIO transport will use standard input/output for communication:
|
||||
|
||||
```bash
|
||||
# Interactive testing with MCP Inspector
|
||||
npx @modelcontextprotocol/inspector php examples/stdio-discovery-calculator/server.php
|
||||
npx @modelcontextprotocol/inspector php examples/discovery-calculator/server.php
|
||||
|
||||
# Run with debugging enabled
|
||||
npx @modelcontextprotocol/inspector -e DEBUG=1 -e FILE_LOG=1 php examples/stdio-discovery-calculator/server.php
|
||||
npx @modelcontextprotocol/inspector -e DEBUG=1 -e FILE_LOG=1 php examples/discovery-calculator/server.php
|
||||
|
||||
# Or configure the script path in your MCP client
|
||||
# Path: php examples/stdio-discovery-calculator/server.php
|
||||
# Path: php examples/discovery-calculator/server.php
|
||||
```
|
||||
|
||||
### HTTP Examples
|
||||
### HTTP Transport
|
||||
|
||||
HTTP examples run as web servers:
|
||||
The Streamable HTTP transport will be chosen if running examples with a web servers:
|
||||
|
||||
```bash
|
||||
# Start the server
|
||||
php -S localhost:8000 examples/http-discovery-userprofile/server.php
|
||||
php -S localhost:8000 examples/discovery-userprofile/server.php
|
||||
|
||||
# Test with MCP Inspector
|
||||
npx @modelcontextprotocol/inspector http://localhost:8000
|
||||
|
|
@ -59,11 +58,11 @@ curl -X POST http://localhost:8000 \
|
|||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0.0"},"capabilities":{}}}'
|
||||
```
|
||||
|
||||
## STDIO Examples
|
||||
## Examples
|
||||
|
||||
### Discovery Calculator
|
||||
|
||||
**File**: `examples/stdio-discovery-calculator/`
|
||||
**File**: `examples/discovery-calculator/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Attribute-based discovery using `#[McpTool]` and `#[McpResource]`
|
||||
|
|
@ -87,14 +86,14 @@ public function getConfiguration(): array
|
|||
**Usage:**
|
||||
```bash
|
||||
# Interactive testing
|
||||
npx @modelcontextprotocol/inspector php examples/stdio-discovery-calculator/server.php
|
||||
npx @modelcontextprotocol/inspector php examples/discovery-calculator/server.php
|
||||
|
||||
# Or configure in MCP client: php examples/stdio-discovery-calculator/server.php
|
||||
# Or configure in MCP client: php examples/discovery-calculator/server.php
|
||||
```
|
||||
|
||||
### Explicit Registration
|
||||
|
||||
**File**: `examples/stdio-explicit-registration/`
|
||||
**File**: `examples/explicit-registration/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Manual registration of tools, resources, and prompts
|
||||
|
|
@ -111,7 +110,7 @@ $server = Server::builder()
|
|||
|
||||
### Environment Variables
|
||||
|
||||
**File**: `examples/stdio-env-variables/`
|
||||
**File**: `examples/env-variables/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Environment variable integration
|
||||
|
|
@ -125,7 +124,7 @@ $server = Server::builder()
|
|||
|
||||
### Custom Dependencies
|
||||
|
||||
**File**: `examples/stdio-custom-dependencies/`
|
||||
**File**: `examples/custom-dependencies/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Dependency injection with PSR-11 containers
|
||||
|
|
@ -145,7 +144,7 @@ $server = Server::builder()
|
|||
|
||||
### Cached Discovery
|
||||
|
||||
**File**: `examples/stdio-cached-discovery/`
|
||||
**File**: `examples/cached-discovery/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Discovery caching for improved performance
|
||||
|
|
@ -165,7 +164,7 @@ $server = Server::builder()
|
|||
|
||||
### Client Communication
|
||||
|
||||
**File**: `examples/stdio-client-communication/`
|
||||
**File**: `examples/client-communication/`
|
||||
|
||||
**What it demostrates:**
|
||||
- Server initiated communcation back to the client
|
||||
|
|
@ -173,11 +172,9 @@ $server = Server::builder()
|
|||
- Using `ClientGateway` in service class via `ClientAwareInterface` and corresponding trait
|
||||
- Using `ClientGateway` in tool method via method argument injection
|
||||
|
||||
## HTTP Examples
|
||||
|
||||
### Discovery User Profile
|
||||
|
||||
**File**: `examples/http-discovery-userprofile/`
|
||||
**File**: `examples/discovery-userprofile/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- HTTP transport with StreamableHttpTransport
|
||||
|
|
@ -205,7 +202,7 @@ public function generateBio(string $userId, string $tone = 'professional'): arra
|
|||
**Usage:**
|
||||
```bash
|
||||
# Start the HTTP server
|
||||
php -S localhost:8000 examples/http-discovery-userprofile/server.php
|
||||
php -S localhost:8000 examples/discovery-userprofile/server.php
|
||||
|
||||
# Test with MCP Inspector
|
||||
npx @modelcontextprotocol/inspector http://localhost:8000
|
||||
|
|
@ -215,7 +212,7 @@ npx @modelcontextprotocol/inspector http://localhost:8000
|
|||
|
||||
### Combined Registration
|
||||
|
||||
**File**: `examples/http-combined-registration/`
|
||||
**File**: `examples/combined-registration/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Mixing attribute discovery with manual registration
|
||||
|
|
@ -232,7 +229,7 @@ $server = Server::builder()
|
|||
|
||||
### Complex Tool Schema
|
||||
|
||||
**File**: `examples/http-complex-tool-schema/`
|
||||
**File**: `examples/complex-tool-schema/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Advanced JSON schema definitions
|
||||
|
|
@ -255,7 +252,7 @@ public function scheduleEvent(array $eventData): array
|
|||
|
||||
### Schema Showcase
|
||||
|
||||
**File**: `examples/http-schema-showcase/`
|
||||
**File**: `examples/schema-showcase/`
|
||||
|
||||
**What it demonstrates:**
|
||||
- Comprehensive JSON schema features
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@
|
|||
This directory contains various examples of how to use the PHP MCP SDK.
|
||||
|
||||
You can run the examples with the dependencies already installed in the root directory of the SDK.
|
||||
The bootstrapping of the example will choose the used transport based on the SAPI you use.
|
||||
|
||||
For running an example, you execute the `server.php` like this:
|
||||
```bash
|
||||
# For examples using STDIO transport
|
||||
php examples/stdio-discovery-calculator/server.php
|
||||
# For using the STDIO transport:
|
||||
php examples/discovery-calculator/server.php
|
||||
|
||||
# For examples using Streamable HTTP transport
|
||||
php -S localhost:8000 examples/http-discovery-userprofile/server.php
|
||||
# For using the Streamable HTTP transport:
|
||||
php -S localhost:8000 examples/discovery-userprofile/server.php
|
||||
```
|
||||
|
||||
You will see debug outputs to help you understand what is happening.
|
||||
|
|
@ -18,7 +19,7 @@ You will see debug outputs to help you understand what is happening.
|
|||
Run with Inspector:
|
||||
|
||||
```bash
|
||||
npx @modelcontextprotocol/inspector php examples/stdio-discovery-calculator/server.php
|
||||
npx @modelcontextprotocol/inspector php examples/discovery-calculator/server.php
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
|
@ -29,5 +30,5 @@ directory.
|
|||
|
||||
With the Inspector you can set the environment variables like this:
|
||||
```bash
|
||||
npx @modelcontextprotocol/inspector -e DEBUG=1 -e FILE_LOG=1 php examples/stdio-discovery-calculator/server.php
|
||||
npx @modelcontextprotocol/inspector -e DEBUG=1 -e FILE_LOG=1 php examples/discovery-calculator/server.php
|
||||
```
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Http\Discovery\Psr17Factory;
|
||||
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||
use Mcp\Capability\Registry\Container;
|
||||
use Mcp\Server\Transport\StdioTransport;
|
||||
use Mcp\Server\Transport\StreamableHttpTransport;
|
||||
use Mcp\Server\Transport\TransportInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
|
@ -21,6 +27,31 @@ set_exception_handler(function (Throwable $t): never {
|
|||
exit(1);
|
||||
});
|
||||
|
||||
/**
|
||||
* @return TransportInterface<int>|TransportInterface<ResponseInterface>
|
||||
*/
|
||||
function transport(): TransportInterface
|
||||
{
|
||||
if ('cli' === \PHP_SAPI) {
|
||||
return new StdioTransport(logger: logger());
|
||||
}
|
||||
|
||||
return new StreamableHttpTransport(
|
||||
(new Psr17Factory())->createServerRequestFromGlobals(),
|
||||
logger: logger(),
|
||||
);
|
||||
}
|
||||
|
||||
function shutdown(ResponseInterface|int $result): never
|
||||
{
|
||||
if ('cli' === \PHP_SAPI) {
|
||||
exit($result);
|
||||
}
|
||||
|
||||
(new SapiEmitter())->emit($result);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function logger(): LoggerInterface
|
||||
{
|
||||
return new class extends AbstractLogger {
|
||||
|
|
|
|||
54
examples/cached-discovery/CachedCalculatorElements.php
Normal file
54
examples/cached-discovery/CachedCalculatorElements.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\CachedDiscovery;
|
||||
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Exception\ToolCallException;
|
||||
|
||||
/**
|
||||
* Example MCP elements for demonstrating cached discovery.
|
||||
*
|
||||
* This class contains simple calculator tools that will be discovered
|
||||
* and cached for improved performance on subsequent server starts.
|
||||
*/
|
||||
class CachedCalculatorElements
|
||||
{
|
||||
#[McpTool(name: 'add_numbers')]
|
||||
public function add(int $a, int $b): int
|
||||
{
|
||||
return $a + $b;
|
||||
}
|
||||
|
||||
#[McpTool(name: 'multiply_numbers')]
|
||||
public function multiply(int $a, int $b): int
|
||||
{
|
||||
return $a * $b;
|
||||
}
|
||||
|
||||
#[McpTool(name: 'divide_numbers')]
|
||||
public function divide(int $a, int $b): float
|
||||
{
|
||||
if (0 === $b) {
|
||||
throw new ToolCallException('Division by zero is not allowed');
|
||||
}
|
||||
|
||||
return $a / $b;
|
||||
}
|
||||
|
||||
#[McpTool(name: 'power')]
|
||||
public function power(int $base, int $exponent): int
|
||||
{
|
||||
return (int) $base ** $exponent;
|
||||
}
|
||||
}
|
||||
37
examples/cached-discovery/server.php
Normal file
37
examples/cached-discovery/server.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
|
||||
logger()->info('Starting MCP Cached Discovery Calculator Server...');
|
||||
|
||||
$server = Server::builder()
|
||||
->setServerInfo('Cached Discovery Calculator', '1.0.0', 'Calculator with cached discovery for better performance.')
|
||||
->setContainer(container())
|
||||
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
||||
->setLogger(logger())
|
||||
->setDiscovery(__DIR__, cache: new Psr16Cache(new PhpFilesAdapter(directory: __DIR__.'/cache')))
|
||||
->build();
|
||||
|
||||
$result = $server->run(transport());
|
||||
|
||||
logger()->info('Server listener stopped gracefully.', ['result' => $result]);
|
||||
|
||||
shutdown($result);
|
||||
71
examples/client-communication/ClientAwareService.php
Normal file
71
examples/client-communication/ClientAwareService.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?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\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 Psr\Log\LoggerInterface;
|
||||
|
||||
final class ClientAwareService implements ClientAwareInterface
|
||||
{
|
||||
use ClientAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
$this->logger->info('SamplingTool instantiated for sampling example.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
{
|
||||
$this->log(LoggingLevel::Warning, \sprintf('Incident triage started: %s', $incidentTitle));
|
||||
|
||||
$steps = [
|
||||
'Collecting telemetry',
|
||||
'Assessing scope',
|
||||
'Coordinating responders',
|
||||
];
|
||||
|
||||
foreach ($steps as $index => $step) {
|
||||
$progress = ($index + 1) / \count($steps);
|
||||
|
||||
$this->progress($progress, 1, $step);
|
||||
|
||||
usleep(180_000); // Simulate work being done
|
||||
}
|
||||
|
||||
$prompt = \sprintf(
|
||||
'Provide a concise response strategy for incident "%s" based on the steps completed: %s.',
|
||||
$incidentTitle,
|
||||
implode(', ', $steps)
|
||||
);
|
||||
|
||||
$result = $this->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));
|
||||
|
||||
return [
|
||||
'incident' => $incidentTitle,
|
||||
'recommended_actions' => $recommendation,
|
||||
'model' => $result->model,
|
||||
];
|
||||
}
|
||||
}
|
||||
62
examples/client-communication/server.php
Normal file
62
examples/client-communication/server.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#!/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\Schema\Enum\LoggingLevel;
|
||||
use Mcp\Schema\ServerCapabilities;
|
||||
use Mcp\Server;
|
||||
use Mcp\Server\ClientGateway;
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
|
||||
$server = Server::builder()
|
||||
->setServerInfo('Client Communication Demo', '1.0.0')
|
||||
->setLogger(logger())
|
||||
->setContainer(container())
|
||||
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
||||
->setCapabilities(new ServerCapabilities(logging: true, tools: true))
|
||||
->setDiscovery(__DIR__)
|
||||
->addTool(
|
||||
function (string $dataset, ClientGateway $client): array {
|
||||
$client->log(LoggingLevel::Info, sprintf('Running quality checks on dataset "%s"', $dataset));
|
||||
|
||||
$tasks = [
|
||||
'Validating schema',
|
||||
'Scanning for anomalies',
|
||||
'Reviewing statistical summary',
|
||||
];
|
||||
|
||||
foreach ($tasks as $index => $task) {
|
||||
$progress = ($index + 1) / count($tasks);
|
||||
|
||||
$client->progress(progress: $progress, total: 1, message: $task);
|
||||
|
||||
usleep(140_000); // Simulate work being done
|
||||
}
|
||||
|
||||
$client->log(LoggingLevel::Info, sprintf('Dataset "%s" passed automated checks.', $dataset));
|
||||
|
||||
return [
|
||||
'dataset' => $dataset,
|
||||
'status' => 'passed',
|
||||
'notes' => 'No significant integrity issues detected during automated checks.',
|
||||
];
|
||||
},
|
||||
name: 'run_dataset_quality_checks',
|
||||
description: 'Perform dataset quality checks with progress updates and logging.'
|
||||
)
|
||||
->build();
|
||||
|
||||
$result = $server->run(transport());
|
||||
|
||||
shutdown($result);
|
||||
41
examples/combined-registration/DiscoveredElements.php
Normal file
41
examples/combined-registration/DiscoveredElements.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?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\CombinedRegistration;
|
||||
|
||||
use Mcp\Capability\Attribute\McpResource;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
|
||||
final class DiscoveredElements
|
||||
{
|
||||
/**
|
||||
* A tool discovered via attributes.
|
||||
*
|
||||
* @return string a status message
|
||||
*/
|
||||
#[McpTool(name: 'discovered_status_check')]
|
||||
public function checkSystemStatus(): string
|
||||
{
|
||||
return 'System status: OK (discovered)';
|
||||
}
|
||||
|
||||
/**
|
||||
* A resource discovered via attributes.
|
||||
* This will be overridden by a manual registration with the same URI.
|
||||
*
|
||||
* @return string content
|
||||
*/
|
||||
#[McpResource(uri: 'config://priority', name: 'priority_config_discovered')]
|
||||
public function getPriorityConfigDiscovered(): string
|
||||
{
|
||||
return 'Discovered Priority Config: Low';
|
||||
}
|
||||
}
|
||||
48
examples/combined-registration/ManualHandlers.php
Normal file
48
examples/combined-registration/ManualHandlers.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?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\CombinedRegistration;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
final class ManualHandlers
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A manually registered tool.
|
||||
*
|
||||
* @param string $user the user to greet
|
||||
*
|
||||
* @return string greeting
|
||||
*/
|
||||
public function manualGreeter(string $user): string
|
||||
{
|
||||
$this->logger->info("Manual tool 'manual_greeter' called for {$user}");
|
||||
|
||||
return "Hello {$user}, from manual registration!";
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually registered resource that overrides a discovered one.
|
||||
*
|
||||
* @return string content
|
||||
*/
|
||||
public function getPriorityConfigManual(): string
|
||||
{
|
||||
$this->logger->info("Manual resource 'config://priority' read.");
|
||||
|
||||
return 'Manual Priority Config: HIGH (overrides discovered)';
|
||||
}
|
||||
}
|
||||
36
examples/combined-registration/server.php
Normal file
36
examples/combined-registration/server.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#!/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\Example\CombinedRegistration\ManualHandlers;
|
||||
use Mcp\Server;
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
|
||||
$server = Server::builder()
|
||||
->setServerInfo('Combined HTTP Server', '1.0.0')
|
||||
->setLogger(logger())
|
||||
->setContainer(container())
|
||||
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
||||
->setDiscovery(__DIR__)
|
||||
->addTool([ManualHandlers::class, 'manualGreeter'])
|
||||
->addResource(
|
||||
[ManualHandlers::class, 'getPriorityConfigManual'],
|
||||
'config://priority',
|
||||
'priority_config_manual',
|
||||
)
|
||||
->build();
|
||||
|
||||
$response = $server->run(transport());
|
||||
|
||||
shutdown($response);
|
||||
72
examples/complex-tool-schema/McpEventScheduler.php
Normal file
72
examples/complex-tool-schema/McpEventScheduler.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?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\ComplexToolSchema;
|
||||
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Example\ComplexToolSchema\Model\EventPriority;
|
||||
use Mcp\Example\ComplexToolSchema\Model\EventType;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
final class McpEventScheduler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a new event.
|
||||
* The inputSchema for this tool will reflect all parameter types and defaults.
|
||||
*
|
||||
* @param string $title the title of the event
|
||||
* @param string $date the date of the event (YYYY-MM-DD)
|
||||
* @param EventType $type the type of event
|
||||
* @param string|null $time the time of the event (HH:MM), optional
|
||||
* @param EventPriority $priority The priority of the event. Defaults to Normal.
|
||||
* @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
|
||||
*
|
||||
* @return array<string, mixed> confirmation of the scheduled event
|
||||
*/
|
||||
#[McpTool(name: 'schedule_event')]
|
||||
public function scheduleEvent(
|
||||
string $title,
|
||||
string $date,
|
||||
EventType $type,
|
||||
?string $time = null,
|
||||
EventPriority $priority = EventPriority::Normal,
|
||||
?array $attendees = null,
|
||||
bool $sendInvites = true,
|
||||
): array {
|
||||
$this->logger->info("Tool 'schedule_event' called", compact('title', 'date', 'type', 'time', 'priority', 'attendees', 'sendInvites'));
|
||||
|
||||
// Simulate scheduling logic
|
||||
$eventDetails = [
|
||||
'title' => $title,
|
||||
'date' => $date,
|
||||
'type' => $type->value, // Use enum value
|
||||
'time' => $time ?? 'All day',
|
||||
'priority' => $priority->name, // Use enum name
|
||||
'attendees' => $attendees ?? [],
|
||||
'invites_will_be_sent' => ($attendees && $sendInvites),
|
||||
];
|
||||
|
||||
// In a real app, this would interact with a calendar service
|
||||
$this->logger->info('Event scheduled', ['details' => $eventDetails]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => \sprintf('Event "%s" scheduled successfully for "%s".', $title, $date),
|
||||
'event_details' => $eventDetails,
|
||||
];
|
||||
}
|
||||
}
|
||||
19
examples/complex-tool-schema/Model/EventPriority.php
Normal file
19
examples/complex-tool-schema/Model/EventPriority.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?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\ComplexToolSchema\Model;
|
||||
|
||||
enum EventPriority: int
|
||||
{
|
||||
case Low = 0;
|
||||
case Normal = 1;
|
||||
case High = 2;
|
||||
}
|
||||
20
examples/complex-tool-schema/Model/EventType.php
Normal file
20
examples/complex-tool-schema/Model/EventType.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?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\ComplexToolSchema\Model;
|
||||
|
||||
enum EventType: string
|
||||
{
|
||||
case Meeting = 'meeting';
|
||||
case Reminder = 'reminder';
|
||||
case Call = 'call';
|
||||
case Other = 'other';
|
||||
}
|
||||
29
examples/complex-tool-schema/server.php
Normal file
29
examples/complex-tool-schema/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;
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
|
||||
$server = Server::builder()
|
||||
->setServerInfo('Event Scheduler Server', '1.0.0')
|
||||
->setLogger(logger())
|
||||
->setContainer(container())
|
||||
->setSession(new FileSessionStore(__DIR__.'/sessions'))
|
||||
->setDiscovery(__DIR__)
|
||||
->build();
|
||||
|
||||
$response = $server->run(transport());
|
||||
|
||||
shutdown($response);
|
||||
92
examples/custom-dependencies/McpTaskHandlers.php
Normal file
92
examples/custom-dependencies/McpTaskHandlers.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?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\CustomDependencies;
|
||||
|
||||
use Mcp\Capability\Attribute\McpResource;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Mcp\Example\CustomDependencies\Service\StatsServiceInterface;
|
||||
use Mcp\Example\CustomDependencies\Service\TaskRepositoryInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Task from TaskRepositoryInterface
|
||||
*/
|
||||
final class McpTaskHandlers
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TaskRepositoryInterface $taskRepo,
|
||||
private readonly StatsServiceInterface $statsService,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
$this->logger->info('McpTaskHandlers instantiated with dependencies.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new task for a given user.
|
||||
*
|
||||
* @param string $userId the ID of the user
|
||||
* @param string $description the task description
|
||||
*
|
||||
* @return Task the created task details
|
||||
*/
|
||||
#[McpTool(name: 'add_task')]
|
||||
public function addTask(string $userId, string $description): array
|
||||
{
|
||||
$this->logger->info("Tool 'add_task' invoked", ['userId' => $userId]);
|
||||
|
||||
return $this->taskRepo->addTask($userId, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists pending tasks for a specific user.
|
||||
*
|
||||
* @param string $userId the ID of the user
|
||||
*
|
||||
* @return Task[] a list of tasks
|
||||
*/
|
||||
#[McpTool(name: 'list_user_tasks')]
|
||||
public function listUserTasks(string $userId): array
|
||||
{
|
||||
$this->logger->info("Tool 'list_user_tasks' invoked", ['userId' => $userId]);
|
||||
|
||||
return $this->taskRepo->getTasksForUser($userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a task as complete.
|
||||
*
|
||||
* @param int $taskId the ID of the task to complete
|
||||
*
|
||||
* @return array<string, mixed> status of the operation
|
||||
*/
|
||||
#[McpTool(name: 'complete_task')]
|
||||
public function completeTask(int $taskId): array
|
||||
{
|
||||
$this->logger->info("Tool 'complete_task' invoked", ['taskId' => $taskId]);
|
||||
$success = $this->taskRepo->completeTask($taskId);
|
||||
|
||||
return ['success' => $success, 'message' => $success ? "Task {$taskId} completed." : "Task {$taskId} not found."];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides current system statistics.
|
||||
*
|
||||
* @return array<string, int> system statistics
|
||||
*/
|
||||
#[McpResource(uri: 'stats://system/overview', name: 'system_stats', mimeType: 'application/json')]
|
||||
public function getSystemStatistics(): array
|
||||
{
|
||||
$this->logger->info("Resource 'stats://system/overview' invoked");
|
||||
|
||||
return $this->statsService->getSystemStats();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?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\CustomDependencies\Service;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Task from TaskRepositoryInterface
|
||||
*/
|
||||
final class InMemoryTaskRepository implements TaskRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var array<int, Task>
|
||||
*/
|
||||
private array $tasks = [];
|
||||
private int $nextTaskId = 1;
|
||||
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
// Add some initial tasks
|
||||
$this->addTask('user1', 'Buy groceries');
|
||||
$this->addTask('user1', 'Write MCP example');
|
||||
$this->addTask('user2', 'Review PR');
|
||||
}
|
||||
|
||||
public function addTask(string $userId, string $description): array
|
||||
{
|
||||
$task = [
|
||||
'id' => $this->nextTaskId++,
|
||||
'userId' => $userId,
|
||||
'description' => $description,
|
||||
'completed' => false,
|
||||
'createdAt' => date('c'),
|
||||
];
|
||||
$this->tasks[$task['id']] = $task;
|
||||
$this->logger->info('Task added', ['id' => $task['id'], 'user' => $userId]);
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
public function getTasksForUser(string $userId): array
|
||||
{
|
||||
return array_values(array_filter($this->tasks, fn ($task) => $task['userId'] === $userId && !$task['completed']));
|
||||
}
|
||||
|
||||
public function getAllTasks(): array
|
||||
{
|
||||
return array_values($this->tasks);
|
||||
}
|
||||
|
||||
public function completeTask(int $taskId): bool
|
||||
{
|
||||
if (isset($this->tasks[$taskId])) {
|
||||
$this->tasks[$taskId]['completed'] = true;
|
||||
$this->logger->info('Task completed', ['id' => $taskId]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?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\CustomDependencies\Service;
|
||||
|
||||
interface StatsServiceInterface
|
||||
{
|
||||
/**
|
||||
* @return array<string, int>
|
||||
*/
|
||||
public function getSystemStats(): array;
|
||||
}
|
||||
34
examples/custom-dependencies/Service/SystemStatsService.php
Normal file
34
examples/custom-dependencies/Service/SystemStatsService.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?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\CustomDependencies\Service;
|
||||
|
||||
final class SystemStatsService implements StatsServiceInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TaskRepositoryInterface $taskRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSystemStats(): array
|
||||
{
|
||||
$allTasks = $this->taskRepository->getAllTasks();
|
||||
$completed = \count(array_filter($allTasks, fn ($task) => $task['completed']));
|
||||
$pending = \count($allTasks) - $completed;
|
||||
|
||||
return [
|
||||
'total_tasks' => \count($allTasks),
|
||||
'completed_tasks' => $completed,
|
||||
'pending_tasks' => $pending,
|
||||
'server_uptime_seconds' => time() - $_SERVER['REQUEST_TIME_FLOAT'], // Approx uptime for CLI script
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?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\CustomDependencies\Service;
|
||||
|
||||
/**
|
||||
* @phpstan-type Task array{id: int, userId: string, description: string, completed: bool, createdAt: string}
|
||||
*/
|
||||
interface TaskRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @return Task
|
||||
*/
|
||||
public function addTask(string $userId, string $description): array;
|
||||
|
||||
/**
|
||||
* @return Task[]
|
||||
*/
|
||||
public function getTasksForUser(string $userId): array;
|
||||
|
||||
/**
|
||||
* @return Task[]
|
||||
*/
|
||||
public function getAllTasks(): array;
|
||||
|
||||
public function completeTask(int $taskId): bool;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue