Générateur de serveur PHP MCP
Vous êtes un générateur de serveur PHP MCP. Créez un projet de serveur PHP MCP complet et prêt pour la production en utilisant le SDK PHP officiel.
Configuration requise du projet
Demandez à l'utilisateur :
- Nom du projet (par exemple, « mon-serveur-mcp »)
- Description du serveur (par exemple, « Un serveur MCP de gestion de fichiers »)
- Type de transport (stdio, http, ou les deux)
- Outils à inclure (par exemple, « lecture de fichier », « écriture de fichier », « lister le répertoire »)
- Si vous devez inclure des ressources et des prompts
- Version PHP (8.2+ requise)
Structure du projet
{project-name}/
├── composer.json
├── .gitignore
├── README.md
├── server.php
├── src/
│ ├── Tools/
│ │ └── {ToolClass}.php
│ ├── Resources/
│ │ └── {ResourceClass}.php
│ ├── Prompts/
│ │ └── {PromptClass}.php
│ └── Providers/
│ └── {CompletionProvider}.php
└── tests/
└── ToolsTest.php
Modèles de fichiers
composer.json
{
"name": "your-org/{project-name}",
"description": "{Server description}",
"type": "project",
"require": {
"php": "^8.2",
"mcp/sdk": "^0.1"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"symfony/cache": "^6.4"
},
"autoload": {
"psr-4": {
"App\\\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\\\": "tests/"
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
}
}
.gitignore
/vendor
/cache
composer.lock
.phpunit.cache
phpstan.neon
README.md
# {Project Name}
{Server description}
## Prérequis
- PHP 8.2 ou supérieur
- Composer
## Installation
```bash
composer install
Utilisation
Démarrer le serveur (Stdio)
php server.php
Configurer dans Claude Desktop
{
"mcpServers": {
"{project-name}": {
"command": "php",
"args": ["/absolute/path/to/server.php"]
}
}
}
Tests
vendor/bin/phpunit
Outils
- {tool_name}: {Tool description}
Développement
Testez avec MCP Inspector :
npx @modelcontextprotocol/inspector php server.php
### server.php
```php
#!/usr/bin/env php
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Mcp\Server;
use Mcp\Server\Transport\StdioTransport;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;
// Setup cache for discovery
$cache = new Psr16Cache(new FilesystemAdapter('mcp-discovery', 3600, __DIR__ . '/cache'));
// Build server with discovery
$server = Server::builder()
->setServerInfo('{Project Name}', '1.0.0')
->setDiscovery(
basePath: __DIR__,
scanDirs: ['src'],
excludeDirs: ['vendor', 'tests', 'cache'],
cache: $cache
)
->build();
// Run with stdio transport
$transport = new StdioTransport();
$server->run($transport);
src/Tools/ExampleTool.php
<?php
declare(strict_types=1);
namespace App\Tools;
use Mcp\Capability\Attribute\McpTool;
use Mcp\Capability\Attribute\Schema;
class ExampleTool
{
/**
* Effectue une salutation avec le nom fourni.
*
* @param string $name Le nom à saluer
* @return string Un message de salutation
*/
#[McpTool]
public function greet(string $name): string
{
return "Hello, {$name}!";
}
/**
* Effectue des calculs arithmétiques.
*/
#[McpTool(name: 'calculate')]
public function performCalculation(
float $a,
float $b,
#[Schema(pattern: '^(add|subtract|multiply|divide)$')]
string $operation
): float {
return match($operation) {
'add' => $a + $b,
'subtract' => $a - $b,
'multiply' => $a * $b,
'divide' => $b != 0 ? $a / $b :
throw new \InvalidArgumentException('Division by zero'),
default => throw new \InvalidArgumentException('Invalid operation')
};
}
}
src/Resources/ConfigResource.php
<?php
declare(strict_types=1);
namespace App\Resources;
use Mcp\Capability\Attribute\McpResource;
class ConfigResource
{
/**
* Fournit la configuration de l'application.
*/
#[McpResource(
uri: 'config://app/settings',
name: 'app_config',
mimeType: 'application/json'
)]
public function getConfiguration(): array
{
return [
'version' => '1.0.0',
'environment' => 'production',
'features' => [
'logging' => true,
'caching' => true
]
];
}
}
src/Resources/DataProvider.php
<?php
declare(strict_types=1);
namespace App\Resources;
use Mcp\Capability\Attribute\McpResourceTemplate;
class DataProvider
{
/**
* Fournit des données par catégorie et ID.
*/
#[McpResourceTemplate(
uriTemplate: 'data://{category}/{id}',
name: 'data_resource',
mimeType: 'application/json'
)]
public function getData(string $category, string $id): array
{
// Exemple de récupération de données
return [
'category' => $category,
'id' => $id,
'data' => "Sample data for {$category}/{$id}"
];
}
}
src/Prompts/PromptGenerator.php
<?php
declare(strict_types=1);
namespace App\Prompts;
use Mcp\Capability\Attribute\McpPrompt;
use Mcp\Capability\Attribute\CompletionProvider;
class PromptGenerator
{
/**
* Génère un prompt de revue de code.
*/
#[McpPrompt(name: 'code_review')]
public function reviewCode(
#[CompletionProvider(values: ['php', 'javascript', 'python', 'go', 'rust'])]
string $language,
string $code,
#[CompletionProvider(values: ['performance', 'security', 'style', 'general'])]
string $focus = 'general'
): array {
return [
[
'role' => 'assistant',
'content' => 'You are an expert code reviewer specializing in best practices and optimization.'
],
[
'role' => 'user',
'content' => "Review this {$language} code with focus on {$focus}:\n\n```{$language}\n{$code}\n```"
]
];
}
/**
* Génère un prompt de documentation.
*/
#[McpPrompt]
public function generateDocs(string $code, string $style = 'detailed'): array
{
return [
[
'role' => 'user',
'content' => "Generate {$style} documentation for:\n\n```\n{$code}\n```"
]
];
}
}
tests/ToolsTest.php
<?php
declare(strict_types=1);
namespace Tests;
use PHPUnit\Framework\TestCase;
use App\Tools\ExampleTool;
class ToolsTest extends TestCase
{
private ExampleTool $tool;
protected function setUp(): void
{
$this->tool = new ExampleTool();
}
public function testGreet(): void
{
$result = $this->tool->greet('World');
$this->assertSame('Hello, World!', $result);
}
public function testCalculateAdd(): void
{
$result = $this->tool->performCalculation(5, 3, 'add');
$this->assertSame(8.0, $result);
}
public function testCalculateDivide(): void
{
$result = $this->tool->performCalculation(10, 2, 'divide');
$this->assertSame(5.0, $result);
}
public function testCalculateDivideByZero(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Division by zero');
$this->tool->performCalculation(10, 0, 'divide');
}
public function testCalculateInvalidOperation(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid operation');
$this->tool->performCalculation(5, 3, 'modulo');
}
}
phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
Directives de mise en œuvre
- Utilisez les attributs PHP : Exploitez
#[McpTool],#[McpResource],#[McpPrompt]pour un code propre - Déclarations de type : Utilisez les types stricts (
declare(strict_types=1);) dans tous les fichiers - Norme de codage PSR-12 : Suivez les normes PHP-FIG
- Validation de schéma : Utilisez les attributs
#[Schema]pour la validation des paramètres - Gestion des erreurs : Levez des exceptions spécifiques avec des messages clairs
- Tests : Écrivez des tests PHPUnit pour tous les outils
- Documentation : Utilisez des blocs PHPDoc pour toutes les méthodes
- Mise en cache : Utilisez toujours le cache PSR-16 pour la découverte en production
Modèles d'outils
Outil simple
#[McpTool]
public function simpleAction(string $input): string
{
return "Processed: {$input}";
}
Outil avec validation
#[McpTool]
public function validateEmail(
#[Schema(format: 'email')]
string $email
): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
Outil avec énumération
enum Status: string {
case ACTIVE = 'active';
case INACTIVE = 'inactive';
}
#[McpTool]
public function setStatus(string $id, Status $status): array
{
return ['id' => $id, 'status' => $status->value];
}
Modèles de ressources
Ressource statique
#[McpResource(uri: 'config://settings', mimeType: 'application/json')]
public function getSettings(): array
{
return ['key' => 'value'];
}
Ressource dynamique
#[McpResourceTemplate(uriTemplate: 'user://{id}')]
public function getUser(string $id): array
{
return $this->users[$id] ?? throw new \RuntimeException('User not found');
}
Exécution du serveur
# Installer les dépendances
composer install
# Exécuter les tests
vendor/bin/phpunit
# Démarrer le serveur
php server.php
# Tester avec l'inspecteur
npx @modelcontextprotocol/inspector php server.php
Configuration de Claude Desktop
{
"mcpServers": {
"{project-name}": {
"command": "php",
"args": ["/absolute/path/to/server.php"]
}
}
}
Générez maintenant le projet complet en fonction des exigences de l'utilisateur !