php-mcp-server-generator

Generate a complete PHP Model Context Protocol server project with tools, resources, prompts, and tests using the official PHP SDK

INSTALLATION
npx skills add https://github.com/github/awesome-copilot --skill php-mcp-server-generator
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

PHP MCP Server Generator

You are a PHP MCP server generator. Create a complete, production-ready PHP MCP server project using the official PHP SDK.

Project Requirements

Ask the user for:

  • Project name (e.g., "my-mcp-server")
  • Server description (e.g., "A file management MCP server")
  • Transport type (stdio, http, or both)
  • Tools to include (e.g., "file read", "file write", "list directory")
  • Whether to include resources and prompts
  • PHP version (8.2+ required)

Project Structure

{project-name}/

├── composer.json

├── .gitignore

├── README.md

├── server.php

├── src/

│   ├── Tools/

│   │   └── {ToolClass}.php

│   ├── Resources/

│   │   └── {ResourceClass}.php

│   ├── Prompts/

│   │   └── {PromptClass}.php

│   └── Providers/

│       └── {CompletionProvider}.php

└── tests/

    └── ToolsTest.php

File Templates

composer.json

{

    "name": "your-org/{project-name}",

    "description": "{Server description}",

    "type": "project",

    "require": {

        "php": "^8.2",

        "mcp/sdk": "^0.1"

    },

    "require-dev": {

        "phpunit/phpunit": "^10.0",

        "symfony/cache": "^6.4"

    },

    "autoload": {

        "psr-4": {

            "App\\\\": "src/"

        }

    },

    "autoload-dev": {

        "psr-4": {

            "Tests\\\\": "tests/"

        }

    },

    "config": {

        "optimize-autoloader": true,

        "preferred-install": "dist",

        "sort-packages": true

    }

}

.gitignore

/vendor

/cache

composer.lock

.phpunit.cache

phpstan.neon

README.md

# {Project Name}

{Server description}

## Requirements

- PHP 8.2 or higher

- Composer

## Installation

composer install


## Usage

### Start Server (Stdio)

php server.php


### Configure in Claude Desktop

{

"mcpServers": {

"{project-name}": {

"command": "php",

"args": ["/absolute/path/to/server.php"]

}

}

}


## Testing

vendor/bin/phpunit


## Tools

- **{tool_name}**: {Tool description}

## Development

Test with MCP Inspector:

npx @modelcontextprotocol/inspector php server.php

server.php


#!/usr/bin/env php

<?php

declare(strict_types=1);

require_once __DIR__ . '/vendor/autoload.php';

use Mcp\Server;

use Mcp\Server\Transport\StdioTransport;

use Symfony\Component\Cache\Adapter\FilesystemAdapter;

use Symfony\Component\Cache\Psr16Cache;

// Setup cache for discovery

$cache = new Psr16Cache(new FilesystemAdapter('mcp-discovery', 3600, __DIR__ . '/cache'));

// Build server with discovery

$server = Server::builder()

    ->setServerInfo('{Project Name}', '1.0.0')

    ->setDiscovery(

        basePath: __DIR__,

        scanDirs: ['src'],

        excludeDirs: ['vendor', 'tests', 'cache'],

        cache: $cache

    )

    ->build();

// Run with stdio transport

$transport = new StdioTransport();

$server->run($transport);

src/Tools/ExampleTool.php

<?php

declare(strict_types=1);

namespace App\Tools;

use Mcp\Capability\Attribute\McpTool;

use Mcp\Capability\Attribute\Schema;

class ExampleTool

{

    /**

     * Performs a greeting with the provided name.

     *

     * @param string $name The name to greet

     * @return string A greeting message

     */

    #[McpTool]

    public function greet(string $name): string

    {

        return "Hello, {$name}!";

    }

    /**

     * Performs arithmetic calculations.

     */

    #[McpTool(name: 'calculate')]

    public function performCalculation(

        float $a,

        float $b,

        #[Schema(pattern: '^(add|subtract|multiply|divide)$')]

        string $operation

    ): float {

        return match($operation) {

            'add' => $a + $b,

            'subtract' => $a - $b,

            'multiply' => $a * $b,

            'divide' => $b != 0 ? $a / $b :

                throw new \InvalidArgumentException('Division by zero'),

            default => throw new \InvalidArgumentException('Invalid operation')

        };

    }

}

src/Resources/ConfigResource.php

<?php

declare(strict_types=1);

namespace App\Resources;

use Mcp\Capability\Attribute\McpResource;

class ConfigResource

{

    /**

     * Provides application configuration.

     */

    #[McpResource(

        uri: 'config://app/settings',

        name: 'app_config',

        mimeType: 'application/json'

    )]

    public function getConfiguration(): array

    {

        return [

            'version' => '1.0.0',

            'environment' => 'production',

            'features' => [

                'logging' => true,

                'caching' => true

            ]

        ];

    }

}

src/Resources/DataProvider.php

<?php

declare(strict_types=1);

namespace App\Resources;

use Mcp\Capability\Attribute\McpResourceTemplate;

class DataProvider

{

    /**

     * Provides data by category and ID.

     */

    #[McpResourceTemplate(

        uriTemplate: 'data://{category}/{id}',

        name: 'data_resource',

        mimeType: 'application/json'

    )]

    public function getData(string $category, string $id): array

    {

        // Example data retrieval

        return [

            'category' => $category,

            'id' => $id,

            'data' => "Sample data for {$category}/{$id}"

        ];

    }

}

src/Prompts/PromptGenerator.php

<?php

declare(strict_types=1);

namespace App\Prompts;

use Mcp\Capability\Attribute\McpPrompt;

use Mcp\Capability\Attribute\CompletionProvider;

class PromptGenerator

{

    /**

     * Generates a code review prompt.

     */

    #[McpPrompt(name: 'code_review')]

    public function reviewCode(

        #[CompletionProvider(values: ['php', 'javascript', 'python', 'go', 'rust'])]

        string $language,

        string $code,

        #[CompletionProvider(values: ['performance', 'security', 'style', 'general'])]

        string $focus = 'general'

    ): array {

        return [

            [

                'role' => 'assistant',

                'content' => 'You are an expert code reviewer specializing in best practices and optimization.'

            ],

            [

                'role' => 'user',

                'content' => "Review this {$language} code with focus on {$focus}:\n\n```{$language}\n{$code}\n```"

            ]

        ];

    }

    /**

     * Generates documentation prompt.

     */

    #[McpPrompt]

    public function generateDocs(string $code, string $style = 'detailed'): array

    {

        return [

            [

                'role' => 'user',

                'content' => "Generate {$style} documentation for:\n\n```\n{$code}\n```"

            ]

        ];

    }

}

tests/ToolsTest.php

<?php

declare(strict_types=1);

namespace Tests;

use PHPUnit\Framework\TestCase;

use App\Tools\ExampleTool;

class ToolsTest extends TestCase

{

    private ExampleTool $tool;

    protected function setUp(): void

    {

        $this->tool = new ExampleTool();

    }

    public function testGreet(): void

    {

        $result = $this->tool->greet('World');

        $this->assertSame('Hello, World!', $result);

    }

    public function testCalculateAdd(): void

    {

        $result = $this->tool->performCalculation(5, 3, 'add');

        $this->assertSame(8.0, $result);

    }

    public function testCalculateDivide(): void

    {

        $result = $this->tool->performCalculation(10, 2, 'divide');

        $this->assertSame(5.0, $result);

    }

    public function testCalculateDivideByZero(): void

    {

        $this->expectException(\InvalidArgumentException::class);

        $this->expectExceptionMessage('Division by zero');

        $this->tool->performCalculation(10, 0, 'divide');

    }

    public function testCalculateInvalidOperation(): void

    {

        $this->expectException(\InvalidArgumentException::class);

        $this->expectExceptionMessage('Invalid operation');

        $this->tool->performCalculation(5, 3, 'modulo');

    }

}

phpunit.xml.dist

<?xml version="1.0" encoding="UTF-8"?>

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"

         bootstrap="vendor/autoload.php"

         colors="true">

    <testsuites>

        <testsuite name="Test Suite">

            <directory>tests</directory>

        </testsuite>

    </testsuites>

    <coverage>

        <include>

            <directory suffix=".php">src</directory>

        </include>

    </coverage>

</phpunit>

Implementation Guidelines

  • Use PHP Attributes: Leverage #[McpTool], #[McpResource], #[McpPrompt] for clean code
  • Type Declarations: Use strict types (declare(strict_types=1);) in all files
  • PSR-12 Coding Standard: Follow PHP-FIG standards
  • Schema Validation: Use #[Schema] attributes for parameter validation
  • Error Handling: Throw specific exceptions with clear messages
  • Testing: Write PHPUnit tests for all tools
  • Documentation: Use PHPDoc blocks for all methods
  • Caching: Always use PSR-16 cache for discovery in production

Tool Patterns

Simple Tool

#[McpTool]

public function simpleAction(string $input): string

{

    return "Processed: {$input}";

}

Tool with Validation

#[McpTool]

public function validateEmail(

    #[Schema(format: 'email')]

    string $email

): bool {

    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;

}

Tool with Enum

enum Status: string {

    case ACTIVE = 'active';

    case INACTIVE = 'inactive';

}

#[McpTool]

public function setStatus(string $id, Status $status): array

{

    return ['id' => $id, 'status' => $status->value];

}

Resource Patterns

Static Resource

#[McpResource(uri: 'config://settings', mimeType: 'application/json')]

public function getSettings(): array

{

    return ['key' => 'value'];

}

Dynamic Resource

#[McpResourceTemplate(uriTemplate: 'user://{id}')]

public function getUser(string $id): array

{

    return $this->users[$id] ?? throw new \RuntimeException('User not found');

}

Running the Server

# Install dependencies

composer install

# Run tests

vendor/bin/phpunit

# Start server

php server.php

# Test with inspector

npx @modelcontextprotocol/inspector php server.php

Claude Desktop Configuration

{

  "mcpServers": {

    "{project-name}": {

      "command": "php",

      "args": ["/absolute/path/to/server.php"]

    }

  }

}

Now generate the complete project based on user requirements!

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card