Build an MCP Server
The Model Context Protocol (MCP) lets AI assistants like Claude Desktop discover and call tools exposed by your application. In this guide you will install the MCP Bundle, create a tool, a prompt, and a resource, then test them with a client.
Prerequisites
- A Symfony application
- Symfony AI MCP Bundle
Step 1: Install the MCP Bundle
The MCP Bundle integrates the official mcp/sdk PHP package into your Symfony application:
1
composer require symfony/mcp-bundle
Step 2: Configure Routing
Add the MCP route to your routing configuration. This exposes the HTTP endpoint that MCP clients connect to:
1 2 3 4
# config/routes.yaml
mcp:
resource: .
type: mcp
Step 3: Create a Tool
Use the #[McpTool] attribute on a method to expose it as a callable tool. MCP clients see the
tool name and can invoke it with parameters:
1 2 3 4 5 6 7 8 9 10 11 12
namespace App\Mcp;
use Mcp\Capability\Attribute\McpTool;
class CurrentTimeTool
{
#[McpTool(name: 'current-time')]
public function getCurrentTime(string $format = 'Y-m-d H:i:s'): string
{
return (new \DateTime('now', new \DateTimeZone('UTC')))->format($format);
}
}
Tip
You can place multiple #[McpTool] methods in the same class to group related tools
together.
Step 4: Configure Transport
Enable STDIO and/or HTTP transport in the bundle configuration. The STDIO transport is used by command-line clients; HTTP is used by web-based clients and the MCP Inspector:
1 2 3 4 5 6 7 8 9 10 11 12
# config/packages/mcp.yaml
mcp:
app: 'my-app'
version: '1.0.0'
description: 'My Symfony MCP server'
client_transports:
stdio: true
http: true
http:
path: /_mcp
Step 5: Create a Prompt
Prompts provide system instructions that AI clients can request. Use the #[McpPrompt]
attribute and return an array of messages:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
namespace App\Mcp;
use Mcp\Capability\Attribute\McpPrompt;
class TimePrompts
{
#[McpPrompt(name: 'time-analysis')]
public function getTimeAnalysisPrompt(): array
{
return [
['role' => 'user', 'content' => 'You are a time management expert.'],
];
}
}
Step 6: Create a Resource
Resources expose static data that AI clients can read. Use the #[McpResource] attribute with
a URI and a name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
namespace App\Mcp;
use Mcp\Capability\Attribute\McpResource;
class TimeResource
{
#[McpResource(uri: 'time://current', name: 'current-time')]
public function getCurrentTimeResource(): array
{
return [
'uri' => 'time://current',
'mimeType' => 'text/plain',
'text' => (new \DateTime('now'))->format('Y-m-d H:i:s'),
];
}
}
Step 7: Test with an MCP Client
To connect Claude Desktop (or any MCP-compatible client) to your server, add an entry to the client's configuration file pointing at your Symfony console command for STDIO transport:
1 2 3 4 5 6 7
{
"mcpServers": {
"my-app": {
"command": "php /path/to/project/bin/console mcp:server"
}
}
}
For the HTTP transport, point the client at your application's MCP endpoint instead:
1 2 3 4 5 6 7
{
"mcpServers": {
"my-app": {
"url": "http://localhost:8000/_mcp"
}
}
}
Tip
Run symfony console mcp:server to start the STDIO server manually. This is useful for
debugging before connecting a client.
Learn More
- MCP Bundle - Full configuration, session storage, and event system
- Model Context Protocol Specification - The official MCP standard
- MCP PHP SDK - Documentation for the official MCP SDK for PHP