Skip to content

Getting Started with PHP MCP SDK โ€‹

Welcome to the PHP MCP SDK! This guide will help you understand what MCP is, why it's useful, and how to get started building with it.

What is MCP? โ€‹

The Model Context Protocol (MCP) is an open protocol that enables seamless integration between Large Language Models (LLMs) and external data sources, tools, and services. Think of it as a standardized way for AI models to interact with the world beyond their training data.

Why Use MCP? โ€‹

๐Ÿ”Œ Universal Integration โ€‹

  • Connect any LLM to any data source or tool
  • Standardized protocol means write once, use everywhere
  • Growing ecosystem of compatible tools and services

๐Ÿ›ก๏ธ Secure & Controlled โ€‹

  • Fine-grained access control
  • OAuth 2.0 authentication support
  • Input validation and sanitization

โšก High Performance โ€‹

  • Async-first architecture
  • Multiple transport options (STDIO, HTTP, WebSocket)
  • Built-in caching and connection pooling

๐Ÿ—๏ธ Production Ready โ€‹

  • Comprehensive error handling
  • Monitoring and observability
  • Docker and cloud deployment support

Key Concepts โ€‹

Before diving into code, let's understand the core MCP concepts:

Architecture Overview โ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      LLM        โ”‚โ—„โ”€โ”€โ–บโ”‚   MCP Client    โ”‚โ—„โ”€โ”€โ–บโ”‚   MCP Server    โ”‚
โ”‚   (ChatGPT,     โ”‚    โ”‚                 โ”‚    โ”‚                 โ”‚
โ”‚    Claude, etc) โ”‚    โ”‚                 โ”‚    โ”‚ Your PHP App    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  • MCP Server (what you'll build): Provides tools, resources, and capabilities
  • MCP Client: Connects servers to LLMs (like Claude Desktop)
  • LLM: The AI model that uses your server's capabilities

Core Capabilities โ€‹

MCP servers can provide four types of capabilities:

1. ๐Ÿ”ง Tools โ€‹

Callable functions that perform actions:

  • Database queries
  • API calls
  • File operations
  • Calculations

2. ๐Ÿ“ฆ Resources โ€‹

Data sources that can be read:

  • Configuration files
  • Documentation
  • Database records
  • API responses

3. ๐Ÿ’ญ Prompts โ€‹

Templates that guide LLM behavior:

  • Instructions and context
  • Response formatting
  • Domain-specific guidelines

4. ๐ŸŽฏ Sampling โ€‹

Request LLM completions from within your server:

  • Content generation
  • Analysis and summarization
  • Translation

Your First MCP Server โ€‹

Let's create a simple "Hello World" server to see MCP in action:

Installation โ€‹

bash
composer require dalehurley/php-mcp-sdk

Create the Server โ€‹

Create hello-server.php:

php
#!/usr/bin/env php
<?php
require_once __DIR__ . '/vendor/autoload.php';

use MCP\Server\McpServer;
use MCP\Server\Transport\StdioServerTransport;
use MCP\Types\Implementation;
use function Amp\async;

// Create server with basic info
$server = new McpServer(
    new Implementation(
        'hello-world-server',
        '1.0.0',
        'A simple greeting server'
    )
);

// Add a tool that says hello
$server->tool(
    'say_hello',
    'Says hello to someone',
    [
        'type' => 'object',
        'properties' => [
            'name' => [
                'type' => 'string',
                'description' => 'Name of the person to greet'
            ]
        ],
        'required' => ['name']
    ],
    function (array $args): array {
        $name = $args['name'] ?? 'World';

        return [
            'content' => [
                [
                    'type' => 'text',
                    'text' => "Hello, {$name}! ๐Ÿ‘‹ Welcome to MCP!"
                ]
            ]
        ];
    }
);

// Start the server
async(function () use ($server) {
    echo "๐Ÿš€ Hello World MCP Server starting...\n";

    $transport = new StdioServerTransport();
    $server->connect($transport)->await();
})->await();

Make it Executable โ€‹

bash
chmod +x hello-server.php

Test with MCP Inspector โ€‹

The MCP Inspector is a great tool for testing servers:

bash
# Install MCP Inspector (requires Node.js)
npm install -g @modelcontextprotocol/inspector

# Test your server
mcp-inspector ./hello-server.php

This opens a web interface where you can:

  • View available tools and resources
  • Test tool calls with different parameters
  • Inspect JSON-RPC messages
  • Debug issues

Test with Claude Desktop โ€‹

Add your server to Claude Desktop's configuration:

json
{
  "mcpServers": {
    "hello-world": {
      "command": "php",
      "args": ["/path/to/your/hello-server.php"]
    }
  }
}

Now you can ask Claude to use your greeting tool!

Understanding the Code โ€‹

Let's break down what's happening:

1. Server Creation โ€‹

php
$server = new McpServer(
    new Implementation('hello-world-server', '1.0.0', 'Description')
);

Creates a new MCP server with identifying information.

2. Tool Registration โ€‹

php
$server->tool($name, $description, $schema, $handler);
  • Name: Unique identifier for the tool
  • Description: Human-readable description
  • Schema: JSON Schema defining expected parameters
  • Handler: Function that processes tool calls

3. Transport Setup โ€‹

php
$transport = new StdioServerTransport();
$server->connect($transport)->await();

Sets up communication via STDIO (standard input/output).

4. Async Execution โ€‹

php
async(function () use ($server) {
    // Server logic here
})->await();

Uses ReactPHP's async system for non-blocking operations.

Real-World Example โ€‹

Let's build something more practical - a weather server:

php
#!/usr/bin/env php
<?php
require_once __DIR__ . '/vendor/autoload.php';

use MCP\Server\McpServer;
use MCP\Server\Transport\StdioServerTransport;
use MCP\Types\Implementation;
use function Amp\async;

$server = new McpServer(
    new Implementation('weather-server', '1.0.0')
);

// Weather tool with input validation
$server->tool(
    'get_weather',
    'Get current weather for a location',
    [
        'type' => 'object',
        'properties' => [
            'location' => [
                'type' => 'string',
                'description' => 'City name or coordinates'
            ],
            'units' => [
                'type' => 'string',
                'enum' => ['celsius', 'fahrenheit'],
                'default' => 'celsius'
            ]
        ],
        'required' => ['location']
    ],
    function (array $args): array {
        $location = $args['location'];
        $units = $args['units'] ?? 'celsius';

        // Simulate API call (replace with real weather API)
        $weather = [
            'location' => $location,
            'temperature' => rand(15, 30),
            'condition' => ['sunny', 'cloudy', 'rainy'][rand(0, 2)],
            'humidity' => rand(40, 80) . '%',
            'units' => $units
        ];

        if ($units === 'fahrenheit') {
            $weather['temperature'] = round($weather['temperature'] * 9/5 + 32);
        }

        return [
            'content' => [
                [
                    'type' => 'text',
                    'text' => "Weather in {$location}:\n" .
                             "Temperature: {$weather['temperature']}ยฐ" .
                             ($units === 'celsius' ? 'C' : 'F') . "\n" .
                             "Condition: {$weather['condition']}\n" .
                             "Humidity: {$weather['humidity']}"
                ]
            ]
        ];
    }
);

// Weather resource for current conditions
$server->resource(
    'weather://current/{location}',
    'Current weather conditions',
    'application/json',
    function (string $uri): array {
        preg_match('/weather:\/\/current\/(.+)/', $uri, $matches);
        $location = urldecode($matches[1] ?? 'Unknown');

        $weather = [
            'location' => $location,
            'temperature' => rand(15, 30),
            'condition' => ['sunny', 'cloudy', 'rainy'][rand(0, 2)],
            'timestamp' => date('c')
        ];

        return [
            'contents' => [
                [
                    'uri' => $uri,
                    'mimeType' => 'application/json',
                    'text' => json_encode($weather, JSON_PRETTY_PRINT)
                ]
            ]
        ];
    }
);

async(function () use ($server) {
    echo "๐ŸŒค๏ธ  Weather MCP Server starting...\n";

    $transport = new StdioServerTransport();
    $server->connect($transport)->await();
})->await();

This server provides:

  • A tool for getting weather data with parameters
  • A resource for accessing weather data via URI
  • Input validation and error handling
  • Realistic data structure

What's Next? โ€‹

Now that you've created your first MCP server, here are the next steps:

๐Ÿ“š Learn More โ€‹

๐Ÿ› ๏ธ Build Advanced Features โ€‹

๐Ÿ—๏ธ Framework Integration โ€‹

๐Ÿค– Agentic AI โ€‹

๐ŸŽฏ Examples โ€‹

Getting Help โ€‹

Welcome to the world of MCP! Let's build something amazing together. ๐Ÿš€