PHPackages                             sw9t/php-mcp-tool-definition - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sw9t/php-mcp-tool-definition

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sw9t/php-mcp-tool-definition
============================

Zero-dependency PHP library for describing MCP tool definitions via typed PHP classes

1.0.1(2w ago)243↓33.3%MITPHPPHP &gt;=8.3

Since May 22Pushed 2w agoCompare

[ Source](https://github.com/sw9t/php-mcp-tool-definition)[ Packagist](https://packagist.org/packages/sw9t/php-mcp-tool-definition)[ RSS](/packages/sw9t-php-mcp-tool-definition/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (1)Versions (3)Used By (0)

php-mcp-tool-definition
=======================

[](#php-mcp-tool-definition)

[![PHP >=8.2](https://camo.githubusercontent.com/f2a8ce481f9787833e7d3330d6cdf3f1494f984301cbeaf6bc14fcfc34efc316/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344382e322d626c7565)](https://camo.githubusercontent.com/f2a8ce481f9787833e7d3330d6cdf3f1494f984301cbeaf6bc14fcfc34efc316/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344382e322d626c7565)[![License: MIT](https://camo.githubusercontent.com/784362b26e4b3546254f1893e778ba64616e362bd6ac791991d2c9e880a3a64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e2e737667)](LICENSE)[![Version](https://camo.githubusercontent.com/a2842c9918fd6939281a110177266bf79d97ae73318199100be18393a34edd70/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d312e302e312d626c7565)](https://camo.githubusercontent.com/a2842c9918fd6939281a110177266bf79d97ae73318199100be18393a34edd70/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d312e302e312d626c7565)

Zero-dependency PHP library for describing [Model Context Protocol (MCP)](https://modelcontextprotocol.io) 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
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Protocol Version Support](#protocol-version-support)
- [Quick Start](#quick-start)
- [Class Reference](#class-reference)
    - [McpSchema](#mcpschema)
    - [McpProperty](#mcpproperty)
    - [Latest — always current version](#latest--always-current-version)
    - [V20241105 — McpToolDefinition](#v20241105--mcptooldefinition)
    - [V20250326 — McpToolDefinition + McpToolAnnotations](#v20250326--mcptooldefinition--mcptoolannotations)
    - [V20250618 — McpToolDefinition](#v20250618--mcptooldefinition)
    - [V20251125 — McpToolDefinition + McpToolExecution + TaskSupport](#v20251125--mcptooldefinition--mcptoolexecution--tasksupport)
- [Usage Examples](#usage-examples)
    - [Tool without parameters](#tool-without-parameters)
    - [Tool with typed parameters](#tool-with-typed-parameters)
    - [Enum constraint](#enum-constraint)
    - [Nested object](#nested-object)
    - [Array of objects](#array-of-objects)
    - [Annotations and hints (2025-03-26+)](#annotations-and-hints-2025-03-26)
    - [Output schema (2025-06-18+)](#output-schema-2025-06-18)
    - [Long-running task execution (2025-11-25+)](#long-running-task-execution-2025-11-25)
    - [Full example — latest version](#full-example--latest-version)
- [Development](#development)
- [License](#license)

---

Requirements
------------

[](#requirements)

- PHP &gt;= 8.2

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

---

Installation
------------

[](#installation)

```
composer require sw9t/php-mcp-tool-definition
```

---

Protocol Version Support
------------------------

[](#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.

NamespaceProtocol dateNew 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 latestalias — points to the most recent above`McpSchema` and `McpProperty` are shared across all versions — import them from the root namespace.

---

Quick Start
-----------

[](#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
---------------

[](#class-reference)

### Latest — always current version

[](#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

[](#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

[](#mcpproperty)

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

FactoryJSON typeExtra parameters`McpProperty::string($name, $desc, $req, $enum, $maxLength)``string``enum: list`, `maxLength: int``McpProperty::integer($name, $desc, $req, $min, $max, $enum)``integer``minimum`, `maximum: int|float`, `enum: list``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

[](#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

[](#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

[](#v20250618--mcptooldefinition)

Adds a top-level `title` field and `outputSchema`.

Display name precedence (highest to lowest): `title` → `annotations.title` → `name`.

```
use McpToolDefinition\V20250618\McpToolDefinition;

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

---

### V20251125 — McpToolDefinition + McpToolExecution + TaskSupport

[](#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
--------------

[](#usage-examples)

### Tool without parameters

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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+)

[](#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+)

[](#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+)

[](#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

[](#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
-----------

[](#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
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance96

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

18d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6356518a4a99872c8fb9b9544964acee585532e3c349574f8cdf6508fa463b59?d=identicon)[sw9t](/maintainers/sw9t)

---

Top Contributors

[![sw9t](https://avatars.githubusercontent.com/u/22070487?v=4)](https://github.com/sw9t "sw9t (3 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/sw9t-php-mcp-tool-definition/health.svg)

```
[![Health](https://phpackages.com/badges/sw9t-php-mcp-tool-definition/health.svg)](https://phpackages.com/packages/sw9t-php-mcp-tool-definition)
```

###  Alternatives

[calderawp/dismissible-notice

Creates a dismissible--via AJAX--admin nag.

151.3k](/packages/calderawp-dismissible-notice)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
