1. Go to this page and download the library: Download ecourty/mcp-server-bundle library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
#[OA\Schema(eUserSchema
{
#[Assert\Email]
#[Assert\NotBlank]
#[Assert\Length(min: 5, max: 255)]
#[OA\Property(description: 'The email address of the user', type: 'string', maxLength: 255, minLength: 5, nullable: false)]
public string $emailAddress;
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 50)]
#[OA\Property(description: 'The username of the user', type: 'string', maxLength: 50, minLength: 3, nullable: false)]
public string $username;
}
use App\Schema\CreateUserSchema;
use Ecourty\McpServerBundle\Attribute\AsTool;
use Ecourty\McpServerBundle\Attribute\ToolAnnotations;
use Ecourty\McpServerBundle\IO\TextToolResult;
use Ecourty\McpServerBundle\IO\ToolResult;
#[AsTool(
name: 'create_user', # Unique identifier for the tool, used by clients to call it
description: 'Creates a new user in the system', # This description is used by LLMs to understand the tool's purpose
annotations: new ToolAnnotations(
title: 'Create a user', // A human-readable title for the tool, useful for documentation
readOnlyHint: false, // Defines the request is not read-only (creates a user)
destructiveHint: false, // Defines the request is not destructive (does not delete data)
idempotentHint: false, // Defines the request cannot be repeated without changing the state
openWorldHint: false, // The tool does not interact with external systems
)
)]
class CreateUserTool
{
public function __invoke(CreateUserSchema $createUserSchema): ToolResult
{
// Your logic here...
return new ToolResult([new TextToolResult('User created successfully!')]);
}
}
use App\Schema\ReadFileSchema;
use Ecourty\McpServerBundle\Attribute\AsTool;
use Ecourty\McpServerBundle\IO\TextToolResult;
use Ecourty\McpServerBundle\IO\ToolResult;
#[AsTool(name: 'read_file', description: 'Reads a file and returns its content')]
class MyTool
{
public function __invoke(ReadFileSchema $payload): ToolResult
{
$fileContent = file_get_contents($payload->filePath);
$anotherFileContent = file_get_contents($payload->anotherFilePath);
// Create individual results
$textResult = new TextToolResult($fileContent);
$anotherTextResult = new TextToolResult($anotherFileContent);
// Combine them in a ToolResult
return new ToolResult([
$textResult,
$anotherTextResult,
]);
}
}
use Ecourty\McpServerBundle\IO\TextToolResult;
use Ecourty\McpServerBundle\IO\ToolResult;
class MyTool
{
public function __invoke(): ToolResult
{
try {
// Your logic here...
return new ToolResult([
new TextToolResult('Success!')
]);
} catch (\Exception $e) {
return new ToolResult(
[new TextToolResult($e->getMessage())],
isError: true
);
}
}
}
use Ecourty\McpServerBundle\Event\ToolCallEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: ToolCallEvent::class)]
class ToolCallListener
{
public function __invoke(ToolCallEvent $event): void
{
// Your logic here...
}
}
use OpenApi\Attributes as OA;
use Symfony\Component\Validator\Constraints as Assert;
class CreateUser
{
#[Assert\NotBlank]
#[Assert\Length(min: 2, max: 50)]
#[OA\Property(type: 'string', description: 'The name of the user', nullable: false)]
private string $name;
#[Assert\NotBlank]
#[Assert\Email]
#[OA\Property(type: 'string', description: 'The email address of the user', nullable: false)]
private string $email;
// Getters and setters...
}
use Ecourty\McpServerBundle\Attribute\AsResource;
use Ecourty\McpServerBundle\IO\Resource\ResourceResult;
use Ecourty\McpServerBundle\IO\Resource\TextResource;
#[AsResource(
uri: 'file://robots.txt',
name: 'robots_txt',
title: 'Get the Robots.txt file',
description: 'This resource returns the content of the robots.txt file.',
mimeType: 'text/plain',
)]
class RobotsFileResource
{
private const string FILE_PATH = __DIR__ . '/../Resources/robots.txt';
public function __invoke(): ResourceResult
{
$fileContent = (string) file_get_contents(self::FILE_PATH);
$encodedFileContent = base64_encode($fileContent);
return new ResourceResult([
new BinaryResource('file://robots.txt', 'text/plain', $encodedFileContent),
]);
}
}
use Ecourty\McpServerBundle\Attribute\AsResource;
use Ecourty\McpServerBundle\IO\Resource\ResourceResult;
use Ecourty\McpServerBundle\IO\Resource\TextResource;
#[AsResource(
uri: 'database://user/{id}',
name: 'user_data',
title: 'Get User Data',
description: 'Gathers the data of a user by their ID.',
mimeType: 'application/json',
)]
class UserResource
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly SerializerInterface $serializer,
) {
}
public function __invoke(int $id): ResourceResult
{
$user = $this->entityManager->find(User::class, $id);
if ($user === null) {
throw new \RuntimeException('User not found');
}
$stringifiedUserData = $this->serializer->serialize($user, 'json');
return new ResourceResult([
new TextResource(
uri: 'database://user/' . $id,
mimeType: 'application/json',
text: $stringifiedUserData,
),
]);
}
}
#[AsResource(
uri: 'api://users/{userId}/posts/{postId}',
name: 'user_post',
title: 'Get User Post',
description: 'Retrieves a specific post by a user.',
mimeType: 'application/json',
)]
class UserPostResource
{
public function __invoke(int $userId, int $postId): ResourceResult
{
// Your logic here...
$post = $this->postRepository->findByUserAndPost($userId, $postId);
return new ResourceResult([
new TextResource(
uri: "api://users/{$userId}/posts/{$postId}",
mimeType: 'application/json',
text: json_encode($post),
),
]);
}
}
use Ecourty\McpServerBundle\IO\Resource\ResourceResult;
use Ecourty\McpServerBundle\IO\Resource\TextResource;
use Ecourty\McpServerBundle\IO\Resource\BinaryResource;
#[AsResource(
// ...
)]
class MyResource
{
public function __invoke(): ResourceResult
{
$jsonData = json_encode(['status' => 'success']);
$imageData = base64_encode(file_get_contents('image.jpg'));
return new ResourceResult([
new TextResource(
uri: 'api://data/status',
mimeType: 'application/json',
text: $jsonData,
),
new BinaryResource(
uri: 'file://image.jpg',
mimeType: 'image/jpeg',
blob: $imageData,
),
]);
}
}
use Ecourty\McpServerBundle\Event\ResourceReadEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: ResourceReadEvent::class)]
class ResourceReadListener
{
public function __invoke(ResourceReadEvent $event): void
{
// Your logic here...
// Log the resource access, add caching, etc.
}
}
namespace App\Prompt;
use Ecourty\McpServerBundle\Attribute\AsPrompt;
use Ecourty\McpServerBundle\Enum\PromptRole;
use Ecourty\McpServerBundle\IO\Prompt\Content\TextContent;
use Ecourty\McpServerBundle\Prompt\Argument;
use Ecourty\McpServerBundle\IO\Prompt\PromptResult;
use Ecourty\McpServerBundle\IO\Prompt\PromptMessage;
use Ecourty\McpServerBundle\Prompt\ArgumentCollection;
#[AsPrompt(
name: 'code_review', // Unique identifier for the prompt,
description: 'Ask for a code review on a provided piece of code', // Description of the prompt
arguments: [
new Argument(name: 'code', description: 'The code snippets to review', with a piece of code in $language.
Your task is to review the code and provide feedback on its quality, readability, and any potential issues.
PROMPT;
$userMessage = <<<PROMPT
Review the following code snippet: $code
PROMPT;
return new PromptResult(
description: 'Code Review Prompt',
messages: [
new PromptMessage(
role: PromptRole::SYSTEM,
content: new TextContent($systemMessage),
),
new PromptMessage(
role: PromptRole::USER,
content: new TextContent($userMessage),
),
]
);
}
}
return new PromptResult(
description: 'Greeting',
messages: [
new PromptMessage(role: PromptRole::SYSTEM, content: new TextContent('You are a friendly assistant.')),
new PromptMessage(role: PromptRole::USER, content: new TextContent('Hello, how are you?')),
]
);
use Ecourty\McpServerBundle\Event\Prompt\PromptExceptionEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: PromptExceptionEvent::class)]
class PromptGetListener
{
public function __invoke(PromptExceptionEvent $event): void
{
// Your logic here...
}
}
use Ecourty\McpServerBundle\Attribute\AsMethodHandler;
use Ecourty\McpServerBundle\MethodHandler\MethodHandlerInterface;
#[AsMethodHandler(
method: 'my_method',
)]
class MyMethodHandler implements MethodHandlerInterface
{
public function handle(JsonRpcRequest $params): array
{
// Your request handling logic here
// ...
return ['result' => 'success'];
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.