mcp-php

MCP.Pizza Chef: garyblankenship

mcp-php is a Model Context Protocol (MCP) server implementation built on Laravel and PHP, designed to facilitate communication between PHP applications and Large Language Models (LLMs) such as Claude. It supports multiple transport layers including STDIO and Server-Sent Events (SSE), enabling real-time, structured context exchange. This server leverages Laravel 10.x and PHP 8.1+, providing a robust, scalable foundation for developers to integrate advanced AI capabilities into their PHP projects. With clear interfaces and extensible architecture, mcp-php simplifies building AI-enhanced workflows and agents within the PHP ecosystem.

Use This MCP server To

Integrate LLMs into Laravel PHP applications Enable real-time AI context exchange via SSE Build AI-powered chatbots with PHP backend Create custom MCP servers for PHP environments Support multi-transport communication with LLMs Develop AI-enhanced workflows in Laravel projects

README

Setting Up a Model Context Protocol (MCP) Server in Laravel

Overview

This tutorial will guide you through creating a Laravel-based MCP server that can communicate with Large Language Models (LLMs) like Claude. The server will support both STDIO and SSE transport layers.

Prerequisites

  • Laravel 10.x
  • PHP 8.1+
  • Composer

Step 1: Project Setup

composer create-project laravel/laravel mcp-server
cd mcp-server

Step 2: Create Core Interfaces

First, create the basic interfaces that define our MCP components:

mkdir -p app/Mcp/Interfaces

Create these interface files:

  1. app/Mcp/Interfaces/ServerInterface.php:
<?php

namespace App\Mcp\Interfaces;

interface ServerInterface
{
    public function setCapabilities(array $capabilities): void;
    public function setRequestHandler(string $type, callable $handler): void;
    public function connect(TransportInterface $transport): void;
    public function close(): void;
    public function onError(\Throwable $error): void;
}
  1. app/Mcp/Interfaces/TransportInterface.php:
<?php

namespace App\Mcp\Interfaces;

interface TransportInterface
{
    public function readMessage(): ?array;
    public function writeMessage(array $message): void;
    public function close(): void;
}
  1. app/Mcp/Interfaces/ResourceInterface.php:
<?php

namespace App\Mcp\Interfaces;

interface ResourceInterface
{
    public function getUri(): string;
    public function getName(): string;
    public function getMimeType(): string;
    public function getDescription(): string;
    public function getContents(): array;
}
  1. app/Mcp/Interfaces/ToolInterface.php:
<?php

namespace App\Mcp\Interfaces;

interface ToolInterface
{
    public function getName(): string;
    public function getDescription(): string;
    public function getInputSchema(): array;
    public function execute(array $arguments): array;
}

Step 3: Implement Transport Layer

Create transport implementations:

  1. app/Mcp/Transport/StdioTransport.php:
<?php

namespace App\Mcp\Transport;

use App\Mcp\Interfaces\TransportInterface;

class StdioTransport implements TransportInterface
{
    private $stdin;
    private $stdout;

    public function __construct()
    {
        $this->stdin = fopen('php://stdin', 'rb');
        $this->stdout = fopen('php://stdout', 'wb');
        while (ob_get_level()) ob_end_clean();
    }

    public function readMessage(): ?array
    {
        $line = fgets($this->stdin);
        if ($line === false || $line === '') {
            return null;
        }

        $message = json_decode($line, true);
        if (!$message && json_last_error() !== JSON_ERROR_NONE) {
            throw new \Exception('Invalid JSON message');
        }

        return $message;
    }

    public function writeMessage(array $message): void
    {
        $json = json_encode($message);
        fwrite($this->stdout, $json . "\n");
        fflush($this->stdout);
    }

    public function close(): void
    {
        if ($this->stdin) fclose($this->stdin);
        if ($this->stdout) fclose($this->stdout);
    }
}
  1. Create a transport factory:
<?php

namespace App\Mcp\Transport;

class TransportFactory
{
    public static function create(string $type, $options = null): TransportInterface
    {
        return match($type) {
            'stdio' => new StdioTransport(),
            'sse' => new SseTransport($options),
            default => throw new \InvalidArgumentException("Unsupported transport type: $type")
        };
    }
}

Step 4: Implement Core Server

Create the main MCP server class:

<?php

namespace App\Mcp;

class Server implements ServerInterface
{
    private array $capabilities = [];
    private array $requestHandlers = [];
    private ?TransportInterface $transport = null;
    private bool $initialized = false;
    
    // ... implementation of interface methods ...
    // (See full Server.php implementation in previous message)
}

Step 5: Create Base Procedure Class

<?php

namespace App\Http\Procedures;

use Sajya\Server\Procedure;

class McpProcedure extends Procedure
{
    public static string $name = 'mcp';

    public function initialize()
    {
        return [
            'protocolVersion' => '2024-11-05',
            'implementation' => [
                'name' => 'laravel-mcp-server',
                'version' => '1.0.0'
            ],
            'capabilities' => [
                'resources' => [
                    'list' => true,
                    'read' => true
                ],
                'tools' => [
                    'list' => true,
                    'call' => true
                ]
            ]
        ];
    }

    // Add other required MCP methods
}

Step 6: Create Console Command

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Mcp\Server;
use App\Mcp\Transport\StdioTransport;

class McpServer extends Command
{
    protected $signature = 'mcp:server';
    protected $description = 'Start MCP server';

    public function handle()
    {
        $server = new Server();
        $procedure = new McpProcedure();
        
        // Register handlers
        $server->setRequestHandler('initialize', [$procedure, 'initialize']);
        // Register other handlers...
        
        $transport = new StdioTransport();
        $server->connect($transport);
    }
}

Step 7: Register Command

In app/Console/Kernel.php:

protected $commands = [
    Commands\McpServer::class,
];

Usage

Run the server:

php artisan mcp:server

Extending the Server

To add new capabilities:

  1. Create a new Resource:
class MyResource implements ResourceInterface
{
    // Implement interface methods
}
  1. Create a new Tool:
class MyTool implements ToolInterface
{
    // Implement interface methods
}
  1. Register them in your procedure class:
class McpProcedure extends Procedure
{
    private MyResource $myResource;
    private MyTool $myTool;

    public function __construct()
    {
        $this->myResource = new MyResource();
        $this->myTool = new MyTool();
    }
    
    // Add corresponding methods to handle the new resource/tool
}

Best Practices

  1. Use dependency injection where possible
  2. Implement proper error handling
  3. Add logging for debugging
  4. Write tests for your resources and tools
  5. Follow Laravel's coding standards
  6. Use type hints and return types
  7. Document your code

This provides a foundation for building MCP servers in Laravel. You can extend it by adding more resources, tools, and capabilities as needed for your specific use case.

mcp-php FAQ

What PHP version is required to run mcp-php?
mcp-php requires PHP 8.1 or higher to ensure compatibility with modern features and Laravel 10.x.
Which transport layers does mcp-php support?
mcp-php supports STDIO and Server-Sent Events (SSE) transport layers for flexible communication with LLMs.
Can mcp-php communicate with LLMs other than Claude?
Yes, while the tutorial highlights Claude, mcp-php can interface with any LLM supporting MCP, including OpenAI and Anthropic models.
How do I set up mcp-php in a Laravel project?
Use Composer to create a Laravel project, then implement the MCP server interfaces as guided in the documentation.
Is mcp-php suitable for production environments?
Yes, built on Laravel and PHP 8.1+, mcp-php is designed for scalable and maintainable production use.
Does mcp-php provide built-in request handling?
Yes, it allows setting custom request handlers for different MCP message types to tailor interactions.
How does mcp-php handle errors during communication?
The server interface includes error handling callbacks to manage and respond to communication issues gracefully.
Can I extend mcp-php to support additional transport protocols?
Yes, the modular design allows adding new transport interfaces beyond STDIO and SSE as needed.