MCP Servers

A collection of Model Context Protocol servers, templates, tools and more.

P
Php MCP Tool Definition

Fluent PHP builder for MCP tool definitions

Created 5/22/2026
Updated about 6 hours ago
Repository documentation and setup instructions

php-mcp-tool-definition

PHP >=8.2 License: MIT Version

Zero-dependency PHP library for describing Model Context Protocol (MCP) tool definitions via typed PHP classes.

Produces the exact JSON structure that MCP clients and servers expect, with full support for all four official protocol versions.


Table of Contents


Requirements

  • PHP >= 8.2

No runtime dependencies. PHPUnit 11 is required for running tests.


Installation

composer require sw9t/php-mcp-tool-definition

Protocol Version Support

The library ships one namespace per official MCP protocol version. Each version is a class that extends the previous one — fields are strictly additive, so you always get a superset of the older version's output.

| Namespace | Protocol date | New fields | |--------------------------------------|---------------|------------------------------------------| | McpToolDefinition\V20241105 | 2024-11-05 | name, description, inputSchema | | McpToolDefinition\V20250326 | 2025-03-26 | annotations (title + behaviour hints) | | McpToolDefinition\V20250618 | 2025-06-18 | title (top-level), outputSchema | | McpToolDefinition\V20251125 | 2025-11-25 | execution (task support mode) | | McpToolDefinition\Latest | always latest | alias — points to the most recent above |

McpSchema and McpProperty are shared across all versions — import them from the root namespace.


Quick Start

Use McpToolDefinition\Latest to always stay on the most recent protocol version, or pick a specific versioned namespace if you need to pin to a particular protocol date.

use McpToolDefinition\McpProperty;
use McpToolDefinition\McpSchema;
use McpToolDefinition\PropertyType;
use McpToolDefinition\Latest\McpToolDefinition;
use McpToolDefinition\Latest\McpToolAnnotations;
use McpToolDefinition\Latest\McpToolExecution;
use McpToolDefinition\V20251125\TaskSupport;  // enum — import from version namespace

$tool = new McpToolDefinition(
    name:        'search_products',
    description: 'Searches the product catalogue and returns matching items',
    inputSchema: new McpSchema([
        McpProperty::string('query', 'Search term', required: true),
        McpProperty::integer('limit', 'Maximum number of results (default 20)'),
        McpProperty::string('sort', 'Sort order', enum: ['asc', 'desc']),
    ]),
    annotations: new McpToolAnnotations(readOnlyHint: true),
    title:       'Search Products',
    execution:   new McpToolExecution(TaskSupport::Optional),
);

$payload = $tool->toArray();   // pass to json_encode() or your MCP server

Class Reference

Latest — always current version

The McpToolDefinition\Latest namespace is a stable alias that always points to the most recent protocol version. Use this if you don't need to pin to a specific protocol version.

When a new MCP protocol version is released and added to the library, the Latest files are updated to point to it — your use statements stay untouched.

use McpToolDefinition\Latest\McpToolDefinition;   // → V20251125\McpToolDefinition
use McpToolDefinition\Latest\McpToolAnnotations;  // → V20250326\McpToolAnnotations
use McpToolDefinition\Latest\McpToolExecution;    // → V20251125\McpToolExecution
use McpToolDefinition\V20251125\TaskSupport;      // enum — PHP cannot extend enums,
                                                  // import directly from version namespace

Why is TaskSupport not in Latest? PHP does not support extending enums, so it is impossible to create a Latest\TaskSupport that is a subtype of V20251125\TaskSupport. Import it directly from the version namespace — it is a simple backed enum and unlikely to change between versions.


McpSchema

Represents a JSON Schema object. Wraps an array of McpProperty instances and builds the properties map and required array automatically.

use McpToolDefinition\McpSchema;
use McpToolDefinition\McpProperty;

$schema = new McpSchema([
    McpProperty::string('name', 'Full name', required: true),
    McpProperty::integer('age', 'Age in years'),
]);

When constructed with no arguments it produces {"type":"object","properties":{}} — a valid empty schema for tools that accept no input.


McpProperty

Represents one property inside a schema. All factory methods accept $name, $description, and $required. The string factory additionally accepts $enum.

| Factory | JSON type | Extra parameters | |---|---|---| | McpProperty::string($name, $desc, $req, $enum, $maxLength) | string | enum: list<string>, maxLength: int | | McpProperty::integer($name, $desc, $req, $min, $max, $enum) | integer | minimum, maximum: int\|float, enum: list<int> | | McpProperty::number($name, $desc, $req, $min, $max) | number | minimum, maximum: int\|float | | McpProperty::boolean($name, $desc, $req) | boolean | — | | McpProperty::object($name, McpSchema, $desc, $req) | object | — | | McpProperty::array($name, McpSchema\|PropertyType, $desc, $req, $minItems, $maxItems) | array | minItems, maxItems: int |

Pass PropertyType::StringType (or any other PropertyType) as $items to produce a primitive item schema (e.g. "items": {"type": "string"}). Pass a McpSchema for arrays of objects.


V20241105 — McpToolDefinition

Minimal tool definition. Suitable for servers running the initial 2024-11-05 protocol.

use McpToolDefinition\V20241105\McpToolDefinition;

new McpToolDefinition(
    name:        string,      // required — programmatic identifier
    description: string,      // required — shown to the LLM
    inputSchema: McpSchema,   // optional — defaults to empty schema
)

V20250326 — McpToolDefinition + McpToolAnnotations

Adds annotations with a display title and four behavioural hints.

use McpToolDefinition\V20250326\McpToolDefinition;
use McpToolDefinition\V20250326\McpToolAnnotations;

new McpToolDefinition(/* ... */, annotations: McpToolAnnotations)

new McpToolAnnotations(
    title:           ?string,  // display name shown in UIs
    readOnlyHint:    ?bool,    // true → tool never modifies state
    destructiveHint: ?bool,    // true → tool may make irreversible changes
    idempotentHint:  ?bool,    // true → repeated calls with same args are safe
    openWorldHint:   ?bool,    // true → tool may call external systems
)

All annotation fields are optional; null values are omitted from the output.


V20250618 — McpToolDefinition

Adds a top-level title field and outputSchema.

Display name precedence (highest to lowest): titleannotations.titlename.

use McpToolDefinition\V20250618\McpToolDefinition;

new McpToolDefinition(/* ... */, title: ?string, outputSchema: ?McpSchema)

V20251125 — McpToolDefinition + McpToolExecution + TaskSupport

Adds execution to support long-running tools via the MCP task polling mechanism.

use McpToolDefinition\V20251125\McpToolDefinition;
use McpToolDefinition\V20251125\McpToolExecution;
use McpToolDefinition\V20251125\TaskSupport;

new McpToolDefinition(/* ... */, execution: ?McpToolExecution)

new McpToolExecution(taskSupport: TaskSupport)

TaskSupport::Forbidden  // synchronous only (default)
TaskSupport::Optional   // client chooses sync or task
TaskSupport::Required   // task polling required

Usage Examples

Tool without parameters

use McpToolDefinition\V20241105\McpToolDefinition;

$tool = new McpToolDefinition(
    name:        'ping',
    description: 'Returns server uptime and current timestamp',
);

// toArray() output:
// {
//   "name":        "ping",
//   "description": "Returns server uptime and current timestamp",
//   "inputSchema": { "type": "object", "properties": {} }
// }

Tool with typed parameters

use McpToolDefinition\McpProperty;
use McpToolDefinition\McpSchema;
use McpToolDefinition\V20241105\McpToolDefinition;

$tool = new McpToolDefinition(
    name:        'get_user',
    description: 'Retrieves a user by ID',
    inputSchema: new McpSchema([
        McpProperty::string('id',     'User UUID',             required: true),
        McpProperty::boolean('full',  'Include full profile'),
    ]),
);

Enum constraint

// String enum
McpProperty::string(
    name:        'status',
    description: 'Filter by order status',
    enum:        ['pending', 'processing', 'shipped', 'delivered', 'cancelled'],
)

// Integer enum
McpProperty::integer(
    name:        'mode',
    description: '0 = include keywords containing the phrase, 1 = exclude them',
    enum:        [0, 1],
)

Numeric constraints

McpProperty::integer('limit',   'Results per page',        minimum: 1,   maximum: 100)
McpProperty::integer('offset',  'Pagination offset',       minimum: 0)
McpProperty::number('score',    'Relevance score (0–1)',   minimum: 0.0, maximum: 1.0)
McpProperty::string('slug',     'URL-friendly identifier', maxLength: 100)

Array of primitives

// Simple array of strings — emits "items": {"type": "string"}
McpProperty::array('tags', PropertyType::StringType, 'List of tags')

// Array of integers with length constraints
McpProperty::array('ids', PropertyType::IntegerType, 'Selected IDs', minItems: 1, maxItems: 50)

Nested object

use McpToolDefinition\McpProperty;
use McpToolDefinition\McpSchema;

McpProperty::object(
    name:       'address',
    properties: new McpSchema([
        McpProperty::string('street', 'Street and house number', required: true),
        McpProperty::string('city',   'City name',               required: true),
        McpProperty::string('zip',    'ZIP / postal code',       required: true),
        McpProperty::string('country','ISO 3166-1 alpha-2 code'),
    ]),
    description: 'Shipping address',
    required:    true,
)

Array of objects

McpProperty::array(
    name:       'line_items',
    items:      new McpSchema([
        McpProperty::string('sku', 'Product SKU', required: true),
        McpProperty::integer('qty', 'Quantity',   required: true),
        McpProperty::number('unit_price', 'Price per unit'),
    ]),
    description: 'Items in the order',
    required:    true,
)

Annotations and hints (2025-03-26+)

use McpToolDefinition\V20250326\McpToolAnnotations;
use McpToolDefinition\V20250326\McpToolDefinition;

// Read-only search — safe to call at any time
$tool = new McpToolDefinition(
    name:        'search_logs',
    description: 'Searches application logs',
    annotations: new McpToolAnnotations(
        title:        'Search Logs',
        readOnlyHint: true,
    ),
);

// Dangerous delete — client should warn the user
$tool = new McpToolDefinition(
    name:        'delete_account',
    description: 'Permanently deletes a user account and all associated data',
    annotations: new McpToolAnnotations(
        title:           'Delete Account',
        destructiveHint: true,
        idempotentHint:  false,
    ),
);

Output schema (2025-06-18+)

use McpToolDefinition\McpProperty;
use McpToolDefinition\McpSchema;
use McpToolDefinition\V20250618\McpToolDefinition;

$tool = new McpToolDefinition(
    name:        'create_invoice',
    description: 'Creates and returns a new invoice',
    title:       'Create Invoice',
    inputSchema: new McpSchema([
        McpProperty::string('customer_id', 'Customer ID',      required: true),
        McpProperty::number('amount',      'Invoice amount',   required: true),
    ]),
    outputSchema: new McpSchema([
        McpProperty::string('invoice_id',  'Created invoice ID', required: true),
        McpProperty::string('pdf_url',     'Download URL',       required: true),
        McpProperty::string('status',      'Invoice status',     required: true),
    ]),
);

Long-running task execution (2025-11-25+)

use McpToolDefinition\V20251125\McpToolDefinition;
use McpToolDefinition\V20251125\McpToolExecution;
use McpToolDefinition\V20251125\TaskSupport;

// Tool that always needs task polling (e.g. a 30-second data export)
$tool = new McpToolDefinition(
    name:        'export_report',
    description: 'Generates and exports a full sales report — may take up to 2 minutes',
    execution:   new McpToolExecution(TaskSupport::Required),
);

// Tool that supports both sync and task modes
$tool = new McpToolDefinition(
    name:        'send_email',
    description: 'Sends an email via the configured SMTP provider',
    execution:   new McpToolExecution(TaskSupport::Optional),
);

Full example — latest version

use McpToolDefinition\McpProperty;
use McpToolDefinition\McpSchema;
use McpToolDefinition\Latest\McpToolAnnotations;
use McpToolDefinition\Latest\McpToolDefinition;
use McpToolDefinition\Latest\McpToolExecution;
use McpToolDefinition\V20251125\TaskSupport;

$tool = new McpToolDefinition(
    name:        'process_order',
    description: 'Validates, charges, and fulfils an order. May take 10–30 seconds.',
    inputSchema: new McpSchema([
        McpProperty::string('order_id',    'Order identifier',      required: true),
        McpProperty::string('coupon_code', 'Optional discount code'),
        McpProperty::boolean('notify',     'Send confirmation email'),
    ]),
    annotations: new McpToolAnnotations(
        title:           'Process Order',
        destructiveHint: true,
        idempotentHint:  false,
    ),
    title: 'Process Order',
    outputSchema: new McpSchema([
        McpProperty::string('status',      'Fulfilment status',     required: true),
        McpProperty::string('tracking_id', 'Shipment tracking ID'),
    ]),
    execution: new McpToolExecution(TaskSupport::Optional),
);

echo json_encode($tool->toArray(), JSON_PRETTY_PRINT);

Development

make install   # install dependencies (vendor lands on host for IDE support)
make test      # run the PHPUnit test suite inside Docker
make shell     # open bash inside the container
make build     # rebuild the Docker image

No local PHP installation required — all commands run inside Docker.


License

MIT — see LICENSE.

Quick Setup
Installation guide for this server

Installation Command (package not published)

git clone https://github.com/sw9t/php-mcp-tool-definition
Manual Installation: Please check the README for detailed setup instructions and any additional dependencies required.

Cursor configuration (mcp.json)

{ "mcpServers": { "sw9t-php-mcp-tool-definition": { "command": "git", "args": [ "clone", "https://github.com/sw9t/php-mcp-tool-definition" ] } } }