ecourty / mcp-server-bundle
A Symfony Bundle to create MCP servers
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- symfony/console: ^7.3
- symfony/framework-bundle: ^7.3
- symfony/http-kernel: ^7.3
- symfony/runtime: ^7.3
- symfony/serializer-pack: ^1.3
- symfony/validator: ^7.3
- zircote/swagger-php: ^5.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.75
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.1
- symfony/browser-kit: ^7.3
- symfony/yaml: ^7.3
This package is auto-updated.
Last update: 2025-06-13 22:21:26 UTC
README
A powerful Symfony bundle for handling MCP (Message Control Protocol) server implementations, providing tools for JSON-RPC request handling and tool management.
Read the official MCP specification.
Warning
The specification of the Model Context Protocol (MCP) changes frequently.
This bundle will evolve along with the specification, so please ensure you are using the latest version of the bundle.
The CHANGELOG can be found here.
Table of Contents
Getting Started
The MCP Server Bundle provides a structured way to create and manage tools that can be used by clients via JSON-RPC requests.
It includes features for MCP tool management, and JSON-RPC method handling.
This bundle is designed to be flexible and extensible, allowing developers to create custom tool handlers and method handlers as needed.
MethodHandlers and ToolHandlers are registered and autowired using attributes, making it easy to define and manage your own tools.
Installation
- Install the MCP Server Bundle via Composer:
composer require ecourty/mcp-server-bundle
- Add the bundle to your
config/bundles.php
(if not using Symfony Flex):
return [ // ... Ecourty\McpServerBundle\McpServerBundle::class => ['all' => true], ];
- Configure the routes in
config/routes/mcp.yaml
:
mcp_controller: resource: '@McpServerBundle/Controller'
Tools
Tools are the core components of the MCP Server Bundle. They allow you to define and manage custom logic that can be triggered by clients.
Creating a Tool
- Create a new class that will handle your tool logic
- Use the
#[AsTool]
attribute to register your tool - Define the input schema for your tool using a class with validation constraints and OpenAPI attributes (examples below)
- Implement the
__invoke
method to handle the tool logic and return aToolResponse
As Tool classes are services within the Symfony application, any dependency can be injected in it, using the constructor, like any other service.
Example:
- Tool input schema class:
#[OA\Schema(required: ['emailAddress', 'username'])] class CreateUserSchema { #[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; }
- Tool class
<?php use App\Schema\CreateUserSchema; // Your input schema class use Ecourty\McpServerBundle\Attribute\AsTool; use Ecourty\McpServerBundle\Attribute\ToolAnnotations; use Ecourty\McpServerBundle\IO\ToolResponse; #[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): ToolResponse { // Your logic here... // $user = new User(); return new ToolResponse(data: $user); } }
Tool Attributes
The #[AsTool]
attribute supports the following properties:
name
(string, required): The unique identifier for your tool, which can be called by clientsdescription
(string, optional): A human-readable description of the tool, useful for LLMs to understand its purposeannotations
(ToolAnnotations, optional): Additional metadata about the tool's behavior
The ToolAnnotations
class provides the following properties:
title
(string): A human-readable title for the toolreadOnlyHint
(bool): Indicates if the tool only reads datadestructiveHint
(bool): Indicates if the tool performs destructive operationsidempotentHint
(bool): Indicates if the tool can be safely repeatedopenWorldHint
(bool): Indicates if the tool interacts with external systems
Input Schema Management
The bundle provides robust input validation and sanitization through schema-based deserialization.
Input schemas are extracted from the __invoke
method of classes with the #[AsTool]
attribute, allowing you to define the expected input structure and validation rules.
- Define your input schema class:
<?php 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... }
- The bundle will automatically:
- Understand the OA attributes for OpenAPI-based documentation in
tools/list
- Deserialize incoming JSON data into your schema class
- Validate all constraints defined in your schema
- Sanitize input data
- Understand the OA attributes for OpenAPI-based documentation in
This ensures that your tool handlers always receive properly validated and sanitized data.
JSON-RPC Method Handlers
The bundle provides a robust system for handling JSON-RPC requests.
Two requests handlers are bundled by default:
ListToolsMethodHandler
: Lists all available tools (tools/list
)ToolMethodHandler
: Handles tool execution requests (tools/call
)
Creating a custom Method Handler
- Create a new class that extends the
MethodHandlerInterface
- Use the
#[AsMethodHandler]
attribute to register your handler
Example:
<?php use Ecourty\McpServerBundle\Attribute\AsMethodHandler; use Ecourty\McpServerBundle\HttpFoundation\JsonRpcRequest; use Ecourty\McpServerBundle\Contract\MethodHandlerInterface; #[AsMethodHandler( method: 'my_method', )] class MyMethodHandler implements MethodHandlerInterface { public function handle(JsonRpcRequest $params): array { // Your request handling logic here // ... return ['result' => 'success']; } }
Method Handler Attributes
The #[AsMethodHandler]
attribute supports:
method
(string, required): The JSON-RPC method name
Developer Experience
The bundle provides several tools to help you during development:
Debug Command
The debug:mcp-tools
command helps you inspect and debug your MCP tools:
# List all registered tools php bin/console debug:mcp-tools # Get detailed information about a specific tool php bin/console debug:mcp-tools my_tool_name
This command is particularly useful for:
- Verifying tool registration
- Checking input schemas
- Validating tool annotations
Contributing
Contributions to the MCP Server Bundle are welcome! Here's how you can help:
- Fork the repository
- Create a new branch for your feature
- Make your changes
- Submit a pull request
Please ensure your code follows our coding standards and includes appropriate tests.
Development Setup
- Fork and clone the repository
- Install dependencies
composer install
-
Make your chages
-
Fix the code style and run PHPStan
composer fix-cs composer phpstan
- Run the tests
composer test
License
This bundle is licensed under the MIT License. See the LICENSE file for details.