PHP SDK
Создание MCP серверов на PHP с использованием php-mcp/server
php-mcp/server — рекомендуемый PHP SDK с attribute-based конфигурацией, PSR-11 dependency injection и полной поддержкой MCP спецификации.
Установка
Заголовок раздела «Установка»composer require php-mcp/serverТребования:
- PHP 8.1+
- Composer
Базовый сервер
Заголовок раздела «Базовый сервер»<?php
use PhpMcp\Server\McpServer;
$server = McpServer::create('my-server', '1.0.0') ->withDescription('Мой MCP сервер на PHP');
// Запуск$server->run();Инструменты через атрибуты
Заголовок раздела «Инструменты через атрибуты»Самый удобный способ — использовать 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; }}Регистрация класса
Заголовок раздела «Регистрация класса»<?php
use PhpMcp\Server\McpServer;
$calculator = new Calculator();
$server = McpServer::create('calculator-server', '1.0.0') ->withTools($calculator) ->run();Ресурсы через атрибуты
Заголовок раздела «Ресурсы через атрибуты»<?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); }}Промпты через атрибуты
Заголовок раздела «Промпты через атрибуты»<?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 practicesPROMPT ), ]; }
#[McpPrompt( name: 'sql_helper', description: 'Помощник по SQL' )] public function sqlHelper( #[PromptParameter(description: 'Вопрос о SQL')] string $question ): array { return [ Message::assistant('Я SQL эксперт. Помогу с запросами и оптимизацией.'), Message::user($question), ]; }}Dependency Injection
Заголовок раздела «Dependency Injection»php-mcp/server поддерживает PSR-11 контейнеры:
<?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();Пример с сервисом БД
Заголовок раздела «Пример с сервисом БД»<?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(); }}Batch Processing
Заголовок раздела «Batch Processing»SDK поддерживает пакетную обработку JSON-RPC запросов:
<?php
$server = McpServer::create('batch-server', '1.0.0') ->withBatchProcessing(true) ->withMaxBatchSize(100) ->run();Кэширование
Заголовок раздела «Кэширование»Интеллектуальное кэширование схем:
<?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();Обработка ошибок
Заголовок раздела «Обработка ошибок»<?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/'); }}Логирование
Заголовок раздела «Логирование»<?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();Интеграция с Laravel
Заголовок раздела «Интеграция с Laravel»Сервис-провайдер
Заголовок раздела «Сервис-провайдер»<?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); }); }}Artisan команда
Заголовок раздела «Artisan команда»<?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.mdbin/server.php
Заголовок раздела «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
Заголовок раздела «Конфигурация Claude Desktop»{ "mcpServers": { "php-server": { "command": "php", "args": ["/path/to/bin/server.php"] } }}Альтернативные SDK
Заголовок раздела «Альтернативные SDK»- logiscape/mcp-sdk-php — полная реализация с поддержкой stdio и HTTP
- mcp-framework — фреймворк с routing и middleware