Kick off the SDK based on Symfony's MCP SDK
This commit is contained in:
parent
0044ffb365
commit
ee0dffe369
89 changed files with 3924 additions and 0 deletions
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/.git* export-ignore
|
||||
/examples export-ignore
|
||||
/tests export-ignore
|
||||
/.php-cs-fixer.dist.php export-ignore
|
||||
/phpstan.dist.neon export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
* @chr-hertel @Nyholm @CodeWithKyrian
|
||||
64
.github/workflows/pipeline.yml
vendored
Normal file
64
.github/workflows/pipeline.yml
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
name: pipeline
|
||||
on: pull_request
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php: ['8.1', '8.2', '8.3', '8.4']
|
||||
dependencies: ['lowest', 'highest']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: "none"
|
||||
|
||||
- name: Install Composer
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "${{ matrix.dependencies }}"
|
||||
|
||||
- name: Composer Validation
|
||||
run: composer validate --strict
|
||||
|
||||
- name: Install PHP Dependencies
|
||||
run: composer install --no-scripts
|
||||
|
||||
- name: Tests
|
||||
run: vendor/bin/phpunit
|
||||
|
||||
qa:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
coverage: "none"
|
||||
|
||||
- name: Install Composer
|
||||
uses: "ramsey/composer-install@v3"
|
||||
|
||||
- name: Composer Validation
|
||||
run: composer validate --strict
|
||||
|
||||
- name: Install PHP Dependencies
|
||||
run: composer install --no-scripts
|
||||
|
||||
- name: Code Style PHP
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run
|
||||
|
||||
- name: PHPStan
|
||||
run: vendor/bin/phpstan analyse
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.phpunit.cache
|
||||
.php-cs-fixer.cache
|
||||
composer.lock
|
||||
vendor
|
||||
45
.php-cs-fixer.dist.php
Normal file
45
.php-cs-fixer.dist.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
if (!file_exists(__DIR__.'/src')) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$fileHeaderParts = [
|
||||
<<<'EOF'
|
||||
This file is part of the official PHP MCP SDK.
|
||||
|
||||
A collaboration between Symfony and the PHP Foundation.
|
||||
|
||||
EOF,
|
||||
<<<'EOF'
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
EOF,
|
||||
];
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
// @see https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/7777
|
||||
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'@Symfony:risky' => true,
|
||||
'protected_to_private' => false,
|
||||
'declare_strict_types' => false,
|
||||
'header_comment' => [
|
||||
'header' => implode('', $fileHeaderParts),
|
||||
],
|
||||
'php_unit_test_case_static_method_calls' => ['call_type' => 'this'],
|
||||
])
|
||||
->setRiskyAllowed(true)
|
||||
->setFinder((new PhpCsFixer\Finder())->in(__DIR__))
|
||||
;
|
||||
24
CHANGELOG.md
Normal file
24
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.1
|
||||
---
|
||||
|
||||
* Add Model Context Protocol (MCP) implementation for LLM-application communication
|
||||
* Add JSON-RPC based protocol handling with `JsonRpcHandler`
|
||||
* Add three core MCP capabilities:
|
||||
- Resources: File-like data readable by clients (API responses, file contents)
|
||||
- Tools: Functions callable by LLMs (with user approval)
|
||||
- Prompts: Pre-written templates for specific tasks
|
||||
* Add multiple transport implementations:
|
||||
- Symfony Console Transport for testing and CLI applications
|
||||
- Stream Transport supporting Server-Sent Events (SSE) and HTTP streaming
|
||||
- STDIO transport for command-line interfaces
|
||||
* Add capability chains for organizing features:
|
||||
- `ToolChain` for tool management
|
||||
- `ResourceChain` for resource management
|
||||
- `PromptChain` for prompt template management
|
||||
* Add Server component managing transport connections
|
||||
* Add request/notification handlers for MCP operations
|
||||
* Add standardized interface enabling LLMs to interact with external systems
|
||||
* Add support for building LLM "plugins" with extra context capabilities
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
25
Makefile
Normal file
25
Makefile
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
.PHONY: deps-stable deps-low cs rector phpstan tests coverage run-examples ci ci-stable ci-lowest
|
||||
|
||||
deps-stable:
|
||||
composer update --prefer-stable
|
||||
|
||||
deps-low:
|
||||
composer update --prefer-lowest
|
||||
|
||||
cs:
|
||||
vendor/bin/php-cs-fixer fix --diff --verbose
|
||||
|
||||
phpstan:
|
||||
vendor/bin/phpstan --memory-limit=-1
|
||||
|
||||
tests:
|
||||
vendor/bin/phpunit
|
||||
|
||||
coverage:
|
||||
XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html=coverage
|
||||
|
||||
ci: ci-stable
|
||||
|
||||
ci-stable: deps-stable cs phpstan tests
|
||||
|
||||
ci-lowest: deps-low cs phpstan tests
|
||||
46
composer.json
Normal file
46
composer.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "mcp/sdk",
|
||||
"type": "library",
|
||||
"description": "Model Context Protocol SDK for Client and Server applications in PHP",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christopher Hertel",
|
||||
"email": "mail@christopher-hertel.de"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Kyrian Obikwelu",
|
||||
"email": "koshnawaza@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"symfony/uid": "^6.4 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"symfony/console": "^6.4 || ^7.0",
|
||||
"psr/cache": "^3.0",
|
||||
"php-cs-fixer/shim": "^3.84"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "To use SymfonyConsoleTransport for STDIO",
|
||||
"psr/cache": "To use CachePoolStore with SSE Transport"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mcp\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Mcp\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
||||
157
doc/index.rst
Normal file
157
doc/index.rst
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
Model Context Protocol SDK
|
||||
==========================
|
||||
|
||||
The PHP MCP SDK is the low level library that enables communication between a PHP application and an LLM model.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install the SDK using Composer:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ composer require mcp/sdk
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The `Model Context Protocol`_ is built on top of JSON-RPC. There two types of
|
||||
messages. A Notification and Request. The Notification is just a status update
|
||||
that something has happened. There is never a response to a Notification. A Request
|
||||
is a message that expects a response. There are 3 concepts/capabilities that you
|
||||
may use. These are::
|
||||
|
||||
1. **Resources**: File-like data that can be read by clients (like API responses or file contents)
|
||||
1. **Tools**: Functions that can be called by the LLM (with user approval)
|
||||
1. **Prompts**: Pre-written templates that help users accomplish specific tasks
|
||||
|
||||
The SDK comes with NotificationHandlers and RequestHandlers which are expected
|
||||
to be wired up in your application.
|
||||
|
||||
JsonRpcHandler
|
||||
..............
|
||||
|
||||
The ``Mcp\Server\JsonRpcHandler`` is the heart of the SDK. It is here
|
||||
you inject the NotificationHandlers and RequestHandlers. It is recommended to use
|
||||
the built-in handlers in ``Mcp\Server\NotificationHandlers\*`` and
|
||||
``Mcp\Server\RequestHandlers\*``.
|
||||
|
||||
The ``Mcp\Server\JsonRpcHandler`` is started and kept running by
|
||||
the ``Mcp\Server``
|
||||
|
||||
Transports
|
||||
..........
|
||||
|
||||
The SDK supports multiple transports for sending and receiving messages. The
|
||||
``Mcp\Server`` is using the transport to fetch a message, then
|
||||
give it to the ``Mcp\Server\JsonRpcHandler`` and finally send the
|
||||
response/error back to the transport. The SDK comes with a few transports::
|
||||
|
||||
1. **Symfony Console Transport**: Good for testing and for CLI applications
|
||||
1. **Stream Transport**: It uses Server Side Events (SSE) and HTTP streaming
|
||||
|
||||
Capabilities
|
||||
............
|
||||
|
||||
Any client would like to discover the capabilities of the server. Exactly what
|
||||
the server supports is defined in the ``Mcp\Server\RequestHandler\InitializeHandler``.
|
||||
When the client connects, it sees the capabilities and will ask the server to list
|
||||
the tools/resource/prompts etc. When you want to add a new capability, example a
|
||||
**Tool** that can tell the current time, you need to provide some metadata to the
|
||||
``Mcp\Server\RequestHandler\ToolListHandler``::
|
||||
|
||||
namespace App;
|
||||
|
||||
use Mcp\Capability\Tool\MetadataInterface;
|
||||
|
||||
class CurrentTimeToolMetadata implements MetadataInterface
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Current time';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Returns the current time in UTC';
|
||||
}
|
||||
|
||||
public function getInputSchema(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'format' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The format of the time, e.g. "Y-m-d H:i:s"',
|
||||
'default' => 'Y-m-d H:i:s',
|
||||
],
|
||||
],
|
||||
'required' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
We would also need a class to actually execute the tool::
|
||||
|
||||
namespace App;
|
||||
|
||||
use Mcp\Capability\Tool\IdentifierInterface;
|
||||
use Mcp\Capability\Tool\ToolCall;
|
||||
use Mcp\Capability\Tool\ToolCallResult;
|
||||
use Mcp\Capability\Tool\ToolExecutorInterface;
|
||||
|
||||
class CurrentTimeToolExecutor implements ToolExecutorInterface, IdentifierInterface
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Current time';
|
||||
}
|
||||
|
||||
public function call(ToolCall $input): ToolCallResult
|
||||
{
|
||||
$format = $input->arguments['format'] ?? 'Y-m-d H:i:s';
|
||||
|
||||
return new ToolCallResult(
|
||||
(new \DateTime('now', new \DateTimeZone('UTC')))->format($format)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
If you have multiple tools, you can put them in a ToolChain::
|
||||
|
||||
$tools = new ToolChain([
|
||||
new CurrentTimeToolMetadata(),
|
||||
new CurrentTimeToolExecutor(),
|
||||
]);
|
||||
|
||||
$jsonRpcHandler = new Mcp\Server\JsonRpcHandler(
|
||||
new Mcp\Message\Factory(),
|
||||
[
|
||||
new ToolCallHandler($tools),
|
||||
new ToolListHandler($tools),
|
||||
// Other RequestHandlers ...
|
||||
],
|
||||
[
|
||||
// Other NotificationHandlers ...
|
||||
],
|
||||
new NullLogger()
|
||||
);
|
||||
|
||||
With this metadata and executor, the client can now call the tool.
|
||||
|
||||
Extending the SDK
|
||||
-----------------
|
||||
|
||||
If you want to extend the SDK, you can create your own RequestHandlers and NotificationHandlers.
|
||||
The provided one are very good defaults for most applications but they are not
|
||||
a requirement.
|
||||
|
||||
If you do decide to use them, you get the benefit of having a well-defined interfaces
|
||||
and value objects to work with. They will assure that you follow the `Model Context Protocol`_.
|
||||
specification.
|
||||
|
||||
You also have the Transport abstraction that allows you to create your own transport
|
||||
if non of the standard ones fit your needs.
|
||||
|
||||
.. _`Model Context Protocol`: https://modelcontextprotocol.io/
|
||||
29
examples/cli/README.md
Normal file
29
examples/cli/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Example app with CLI
|
||||
|
||||
This is just for testing and debugging purposes.
|
||||
|
||||
|
||||
Install and create symlink with:
|
||||
|
||||
```bash
|
||||
cd /path/to/your/project/examples/cli
|
||||
composer update
|
||||
rm -rf vendor/mcp/sdk/src
|
||||
ln -s /path/to/your/project/src /path/to/your/project/examples/cli/vendor/mcp/sdk/src
|
||||
```
|
||||
|
||||
Run the CLI with:
|
||||
|
||||
```bash
|
||||
DEBUG=1 php index.php
|
||||
```
|
||||
|
||||
You will see debug outputs to help you understand what is happening.
|
||||
|
||||
In this terminal you can now test add some json strings. See `example-requests.json`.
|
||||
|
||||
Run with Inspector:
|
||||
|
||||
```bash
|
||||
npx @modelcontextprotocol/inspector php index.php
|
||||
```
|
||||
27
examples/cli/composer.json
Normal file
27
examples/cli/composer.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "mcp/cli-server-example",
|
||||
"description": "An example application for CLI",
|
||||
"license": "MIT",
|
||||
"type": "project",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"mcp/sdk": "@dev",
|
||||
"symfony/console": "^7.2"
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{ "type": "path", "url": "../../" }
|
||||
]
|
||||
}
|
||||
|
||||
12
examples/cli/example-requests.json
Normal file
12
examples/cli/example-requests.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "resources/list", "params": []},
|
||||
{"jsonrpc": "2.0", "id": 2, "method": "resources/read", "params": {"uri": "file:///project/src/main.rs"}},
|
||||
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "tools/list"},
|
||||
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "Current time"}},
|
||||
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "Current time","arguments": {"format": "Y-m-d"}}},
|
||||
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "prompts/list"},
|
||||
{"jsonrpc": "2.0", "id": 2 ,"method": "prompts/get", "params": {"name": "Greet"}},
|
||||
{"jsonrpc": "2.0", "id": 2 ,"method": "prompts/get", "params": {"name": "Greet", "arguments": { "firstName": "Tobias" }}}
|
||||
]
|
||||
39
examples/cli/index.php
Normal file
39
examples/cli/index.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?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 __DIR__.'/vendor/autoload.php';
|
||||
|
||||
use Symfony\Component\Console as SymfonyConsole;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
$debug = (bool) ($_SERVER['DEBUG'] ?? false);
|
||||
|
||||
// Setup input, output and logger
|
||||
$input = new SymfonyConsole\Input\ArgvInput($argv);
|
||||
$output = new SymfonyConsole\Output\ConsoleOutput($debug ? OutputInterface::VERBOSITY_VERY_VERBOSE : OutputInterface::VERBOSITY_NORMAL);
|
||||
$logger = new SymfonyConsole\Logger\ConsoleLogger($output);
|
||||
|
||||
// Configure the JsonRpcHandler and build the functionality
|
||||
$jsonRpcHandler = new Mcp\Server\JsonRpcHandler(
|
||||
new Mcp\Message\Factory(),
|
||||
App\Builder::buildRequestHandlers(),
|
||||
App\Builder::buildNotificationHandlers(),
|
||||
$logger
|
||||
);
|
||||
|
||||
// Set up the server
|
||||
$sever = new Mcp\Server($jsonRpcHandler, $logger);
|
||||
|
||||
// Create the transport layer using Symfony Console
|
||||
$transport = new Mcp\Server\Transport\Stdio\SymfonyConsoleTransport($input, $output);
|
||||
|
||||
// Start our application
|
||||
$sever->connect($transport);
|
||||
72
examples/cli/src/Builder.php
Normal file
72
examples/cli/src/Builder.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 App;
|
||||
|
||||
use Mcp\Capability\PromptChain;
|
||||
use Mcp\Capability\ResourceChain;
|
||||
use Mcp\Capability\ToolChain;
|
||||
use Mcp\Server\NotificationHandler\InitializedHandler;
|
||||
use Mcp\Server\NotificationHandlerInterface;
|
||||
use Mcp\Server\RequestHandler\InitializeHandler;
|
||||
use Mcp\Server\RequestHandler\PingHandler;
|
||||
use Mcp\Server\RequestHandler\PromptGetHandler;
|
||||
use Mcp\Server\RequestHandler\PromptListHandler;
|
||||
use Mcp\Server\RequestHandler\ResourceListHandler;
|
||||
use Mcp\Server\RequestHandler\ResourceReadHandler;
|
||||
use Mcp\Server\RequestHandler\ToolCallHandler;
|
||||
use Mcp\Server\RequestHandler\ToolListHandler;
|
||||
use Mcp\Server\RequestHandlerInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class Builder
|
||||
{
|
||||
/**
|
||||
* @return list<RequestHandlerInterface>
|
||||
*/
|
||||
public static function buildRequestHandlers(): array
|
||||
{
|
||||
$promptManager = new PromptChain([
|
||||
new ExamplePrompt(),
|
||||
]);
|
||||
|
||||
$resourceManager = new ResourceChain([
|
||||
new ExampleResource(),
|
||||
]);
|
||||
|
||||
$toolManager = new ToolChain([
|
||||
new ExampleTool(),
|
||||
]);
|
||||
|
||||
return [
|
||||
new InitializeHandler(),
|
||||
new PingHandler(),
|
||||
new PromptListHandler($promptManager),
|
||||
new PromptGetHandler($promptManager),
|
||||
new ResourceListHandler($resourceManager),
|
||||
new ResourceReadHandler($resourceManager),
|
||||
new ToolCallHandler($toolManager),
|
||||
new ToolListHandler($toolManager),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<NotificationHandlerInterface>
|
||||
*/
|
||||
public static function buildNotificationHandlers(): array
|
||||
{
|
||||
return [
|
||||
new InitializedHandler(),
|
||||
];
|
||||
}
|
||||
}
|
||||
58
examples/cli/src/ExamplePrompt.php
Normal file
58
examples/cli/src/ExamplePrompt.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?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 App;
|
||||
|
||||
use Mcp\Capability\Prompt\MetadataInterface;
|
||||
use Mcp\Capability\Prompt\PromptGet;
|
||||
use Mcp\Capability\Prompt\PromptGetResult;
|
||||
use Mcp\Capability\Prompt\PromptGetResultMessages;
|
||||
use Mcp\Capability\Prompt\PromptGetterInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class ExamplePrompt implements MetadataInterface, PromptGetterInterface
|
||||
{
|
||||
public function get(PromptGet $input): PromptGetResult
|
||||
{
|
||||
$firstName = $input->arguments['first name'] ?? null;
|
||||
|
||||
return new PromptGetResult(
|
||||
$this->getDescription(),
|
||||
[new PromptGetResultMessages(
|
||||
'user',
|
||||
\sprintf('Hello %s', $firstName ?? 'World')
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Greet';
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return 'Greet a person with a nice message';
|
||||
}
|
||||
|
||||
public function getArguments(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'first name',
|
||||
'description' => 'The name of the person to greet',
|
||||
'required' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
56
examples/cli/src/ExampleResource.php
Normal file
56
examples/cli/src/ExampleResource.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?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 App;
|
||||
|
||||
use Mcp\Capability\Resource\MetadataInterface;
|
||||
use Mcp\Capability\Resource\ResourceRead;
|
||||
use Mcp\Capability\Resource\ResourceReaderInterface;
|
||||
use Mcp\Capability\Resource\ResourceReadResult;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class ExampleResource implements MetadataInterface, ResourceReaderInterface
|
||||
{
|
||||
public function read(ResourceRead $input): ResourceReadResult
|
||||
{
|
||||
return new ResourceReadResult(
|
||||
'Content of '.$this->getName(),
|
||||
$this->getUri(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getUri(): string
|
||||
{
|
||||
return 'file:///project/src/main.rs';
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'My resource';
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return 'This is just an example';
|
||||
}
|
||||
|
||||
public function getMimeType(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getSize(): ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
57
examples/cli/src/ExampleTool.php
Normal file
57
examples/cli/src/ExampleTool.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?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 App;
|
||||
|
||||
use Mcp\Capability\Tool\MetadataInterface;
|
||||
use Mcp\Capability\Tool\ToolCall;
|
||||
use Mcp\Capability\Tool\ToolCallResult;
|
||||
use Mcp\Capability\Tool\ToolExecutorInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class ExampleTool implements MetadataInterface, ToolExecutorInterface
|
||||
{
|
||||
public function call(ToolCall $input): ToolCallResult
|
||||
{
|
||||
$format = $input->arguments['format'] ?? 'Y-m-d H:i:s';
|
||||
|
||||
return new ToolCallResult(
|
||||
(new \DateTime('now', new \DateTimeZone('UTC')))->format($format)
|
||||
);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Current time';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Returns the current time in UTC';
|
||||
}
|
||||
|
||||
public function getInputSchema(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'format' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The format of the time, e.g. "Y-m-d H:i:s"',
|
||||
'default' => 'Y-m-d H:i:s',
|
||||
],
|
||||
],
|
||||
'required' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
9
phpstan.dist.neon
Normal file
9
phpstan.dist.neon
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- examples/
|
||||
- src/
|
||||
- tests/
|
||||
excludePaths:
|
||||
- examples/cli/vendor/* (?)
|
||||
treatPhpDocTypesAsCertain: false
|
||||
22
phpunit.xml.dist
Normal file
22
phpunit.xml.dist
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
colors="true"
|
||||
executionOrder="depends,defects"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source restrictNotices="true" restrictWarnings="true">
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue