PHP code example of ecourty / mcp-server-bundle

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/ */

    

ecourty / mcp-server-bundle example snippets


return [
    // ...
    Ecourty\McpServerBundle\McpServerBundle::class => ['all' => true],
];

#[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'];
    }
}