Skip to content

Build an MCP Server

Edit this page

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

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version