Перейти к содержимому

PHP SDK

Создание MCP серверов на PHP с использованием php-mcp/server

php-mcp/server — рекомендуемый PHP SDK с attribute-based конфигурацией, PSR-11 dependency injection и полной поддержкой MCP спецификации.

Terminal
composer require php-mcp/server

Требования:

  • PHP 8.1+
  • Composer
server.php
<?php
use PhpMcp\Server\McpServer;
$server = McpServer::create('my-server', '1.0.0')
->withDescription('Мой MCP сервер на PHP');
// Запуск
$server->run();

Самый удобный способ — использовать PHP атрибуты:

Calculator.php
<?php
use PhpMcp\Server\Attributes\McpTool;
use PhpMcp\Server\Attributes\ToolParameter;
class Calculator
{
#[McpTool(
name: 'add',
description: 'Сложение двух чисел'
)]
public function add(
#[ToolParameter(description: 'Первое число')]
float $a,
#[ToolParameter(description: 'Второе число')]
float $b
): float {
return $a + $b;
}
#[McpTool(
name: 'divide',
description: 'Деление чисел'
)]
public function divide(
#[ToolParameter(description: 'Делимое')]
float $a,
#[ToolParameter(description: 'Делитель')]
float $b
): float {
if ($b === 0.0) {
throw new \InvalidArgumentException('Деление на ноль');
}
return $a / $b;
}
}
server.php
<?php
use PhpMcp\Server\McpServer;
$calculator = new Calculator();
$server = McpServer::create('calculator-server', '1.0.0')
->withTools($calculator)
->run();
ConfigProvider.php
<?php
use PhpMcp\Server\Attributes\McpResource;
use PhpMcp\Server\Attributes\ResourceParameter;
class ConfigProvider
{
#[McpResource(
uri: 'config://app',
name: 'App Configuration',
description: 'Конфигурация приложения',
mimeType: 'application/json'
)]
public function getAppConfig(): string
{
return json_encode([
'version' => '1.0.0',
'environment' => 'production',
'debug' => false,
]);
}
#[McpResource(
uri: 'file://{path}',
name: 'File Reader',
description: 'Чтение файла'
)]
public function readFile(
#[ResourceParameter(description: 'Путь к файлу')]
string $path
): string {
if (!file_exists($path)) {
throw new \RuntimeException("Файл не найден: $path");
}
return file_get_contents($path);
}
}
PromptTemplates.php
<?php
use PhpMcp\Server\Attributes\McpPrompt;
use PhpMcp\Server\Attributes\PromptParameter;
use PhpMcp\Server\Message;
class PromptTemplates
{
#[McpPrompt(
name: 'code_review',
description: 'Промпт для код-ревью'
)]
public function codeReview(
#[PromptParameter(description: 'Язык программирования')]
string $language,
#[PromptParameter(description: 'Код для ревью')]
string $code
): array {
return [
Message::user(<<<PROMPT
Проведи код-ревью следующего $language кода:
```$language
$code
```
Обрати внимание на:
1. Потенциальные баги
2. Производительность
3. Безопасность
4. Best practices
PROMPT
),
];
}
#[McpPrompt(
name: 'sql_helper',
description: 'Помощник по SQL'
)]
public function sqlHelper(
#[PromptParameter(description: 'Вопрос о SQL')]
string $question
): array {
return [
Message::assistant('Я SQL эксперт. Помогу с запросами и оптимизацией.'),
Message::user($question),
];
}
}

php-mcp/server поддерживает PSR-11 контейнеры:

server.php
<?php
use PhpMcp\Server\McpServer;
use Psr\Container\ContainerInterface;
// С Laravel
$container = app();
// С Symfony
$container = $kernel->getContainer();
// С PHP-DI
$container = \DI\ContainerBuilder::buildDevContainer();
$server = McpServer::create('my-server', '1.0.0')
->withContainer($container)
->withTools(Calculator::class) // Резолвится через контейнер
->run();
DatabaseTools.php
<?php
use PhpMcp\Server\Attributes\McpTool;
use PDO;
class DatabaseTools
{
public function __construct(
private PDO $db
) {}
#[McpTool(
name: 'query',
description: 'Выполнение SQL запроса'
)]
public function query(string $sql): array
{
$stmt = $this->db->query($sql);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
#[McpTool(
name: 'insert',
description: 'Вставка данных'
)]
public function insert(string $table, array $data): int
{
$columns = implode(', ', array_keys($data));
$placeholders = implode(', ', array_fill(0, count($data), '?'));
$stmt = $this->db->prepare(
"INSERT INTO $table ($columns) VALUES ($placeholders)"
);
$stmt->execute(array_values($data));
return (int) $this->db->lastInsertId();
}
}

SDK поддерживает пакетную обработку JSON-RPC запросов:

server.php
<?php
$server = McpServer::create('batch-server', '1.0.0')
->withBatchProcessing(true)
->withMaxBatchSize(100)
->run();

Интеллектуальное кэширование схем:

server.php
<?php
use PhpMcp\Server\Cache\FileCache;
$cache = new FileCache('/tmp/mcp-cache');
$server = McpServer::create('cached-server', '1.0.0')
->withCache($cache)
->withCacheTtl(3600) // 1 час
->run();
SecureTools.php
<?php
use PhpMcp\Server\Attributes\McpTool;
use PhpMcp\Server\Exceptions\McpError;
class SecureTools
{
#[McpTool(name: 'read_secret')]
public function readSecret(string $path): string
{
if (!$this->isAllowed($path)) {
throw McpError::forbidden('Доступ запрещён');
}
if (!file_exists($path)) {
throw McpError::notFound("Файл не найден: $path");
}
return file_get_contents($path);
}
#[McpTool(name: 'validate')]
public function validate(array $data): bool
{
if (empty($data['required_field'])) {
throw McpError::invalidParams('Отсутствует обязательное поле');
}
return true;
}
private function isAllowed(string $path): bool
{
return str_starts_with($path, '/allowed/');
}
}
server.php
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use PhpMcp\Server\McpServer;
$logger = new Logger('mcp');
$logger->pushHandler(new StreamHandler('/var/log/mcp.log'));
$server = McpServer::create('logged-server', '1.0.0')
->withLogger($logger)
->run();
app/Providers/McpServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use PhpMcp\Server\McpServer;
use App\Mcp\Tools\LaravelTools;
use App\Mcp\Resources\LaravelResources;
class McpServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(McpServer::class, function ($app) {
return McpServer::create('laravel-mcp', '1.0.0')
->withContainer($app)
->withTools(LaravelTools::class)
->withResources(LaravelResources::class);
});
}
}
app/Console/Commands/McpServe.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpMcp\Server\McpServer;
class McpServe extends Command
{
protected $signature = 'mcp:serve';
protected $description = 'Запуск MCP сервера';
public function handle(McpServer $server)
{
$this->info('Запуск MCP сервера...');
$server->run();
}
}
my-mcp-server/
├── src/
│ ├── Server.php
│ ├── Tools/
│ │ ├── Calculator.php
│ │ └── Filesystem.php
│ ├── Resources/
│ │ └── ConfigProvider.php
│ └── Prompts/
│ └── Templates.php
├── bin/
│ └── server.php
├── composer.json
└── README.md
bin/server.php
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use PhpMcp\Server\McpServer;
use App\Tools\Calculator;
use App\Tools\Filesystem;
use App\Resources\ConfigProvider;
use App\Prompts\Templates;
$server = McpServer::create('my-server', '1.0.0')
->withTools(new Calculator())
->withTools(new Filesystem())
->withResources(new ConfigProvider())
->withPrompts(new Templates())
->run();
claude_desktop_config.json
{
"mcpServers": {
"php-server": {
"command": "php",
"args": ["/path/to/bin/server.php"]
}
}
}
  • logiscape/mcp-sdk-php — полная реализация с поддержкой stdio и HTTP
  • mcp-framework — фреймворк с routing и middleware