code-wheel/mcp-schema-builder

JSON Schema builder and validator for MCP tool definitions

Installs: 45

Dependents: 0

Suggesters: 1

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/code-wheel/mcp-schema-builder

v1.1.3 2026-01-10 04:24 UTC

This package is auto-updated.

Last update: 2026-01-10 06:23:31 UTC


README

CI codecov Latest Stable Version License

A fluent JSON Schema builder with validation for MCP (Model Context Protocol) tool definitions. Build type-safe schemas, validate LLM-generated inputs, and use pre-built patterns for common MCP tools.

Installation

composer require code-wheel/mcp-schema-builder

Quick Start

Building Schemas

use CodeWheel\McpSchemaBuilder\SchemaBuilder;

$schema = SchemaBuilder::object()
    ->property('name', SchemaBuilder::string()->minLength(1)->required())
    ->property('email', SchemaBuilder::string()->format('email')->required())
    ->property('age', SchemaBuilder::integer()->minimum(0)->maximum(150))
    ->property('role', SchemaBuilder::string()->enum(['admin', 'user', 'guest'])->default('user'))
    ->build();

Validating Input

use CodeWheel\McpSchemaBuilder\SchemaValidator;

$validator = new SchemaValidator();
$result = $validator->validate($input, $schema);

if (!$result->isValid()) {
    foreach ($result->getErrors() as $error) {
        echo "{$error->path}: {$error->message}\n";
        // "email: Invalid email format"
        // "age: Value must be >= 0"
    }

    // Or convert to ErrorBag for tool responses
    return $result->toErrorBag()->toToolResult();
}

MCP Presets

use CodeWheel\McpSchemaBuilder\McpSchema;

// Common patterns for MCP tools
$schema = SchemaBuilder::object()
    ->property('node_id', McpSchema::entityId('node'))       // Entity ID with description
    ->property('bundle', McpSchema::machineName())           // Machine name pattern
    ->property('query', McpSchema::searchQuery(2))           // Search with min length
    ->merge(McpSchema::pagination(50, 100))                  // limit + offset
    ->merge(McpSchema::sorting(['created', 'title']))        // sort_by + sort_order
    ->build();

// Complete tool schemas
$listSchema = McpSchema::listToolSchema(
    filterFields: ['status', 'author'],
    sortFields: ['created', 'updated', 'title']
);

$getSchema = McpSchema::getToolSchema('node_id', 'node');

$createSchema = McpSchema::createToolSchema(
    requiredFields: ['title' => SchemaBuilder::string(), 'body' => SchemaBuilder::string()],
    optionalFields: ['status' => SchemaBuilder::string()->enum(['draft', 'published'])]
);

$deleteSchema = McpSchema::deleteToolSchema('node_id', includeForce: true);

Schema Composition

// Reusable schema fragments
$timestamps = SchemaBuilder::object()
    ->property('created', SchemaBuilder::string()->format('date-time'))
    ->property('updated', SchemaBuilder::string()->format('date-time'));

$author = SchemaBuilder::object()
    ->property('author_id', SchemaBuilder::string()->required())
    ->property('author_name', SchemaBuilder::string());

// Compose into larger schema
$contentSchema = SchemaBuilder::object()
    ->property('id', SchemaBuilder::string()->required())
    ->property('title', SchemaBuilder::string()->required())
    ->merge($timestamps)
    ->merge($author)
    ->build();

// Extend without modifying original
$extendedSchema = $timestamps->extend()
    ->property('deleted', SchemaBuilder::string()->format('date-time'))
    ->build();

Schema Builder API

String

SchemaBuilder::string()
    ->description('Field description')
    ->minLength(1)
    ->maxLength(255)
    ->pattern('^[a-z]+$')
    ->format('email')  // email, uri, uuid, date, date-time
    ->enum(['a', 'b', 'c'])
    ->default('a')
    ->nullable()
    ->required();

Integer / Number

SchemaBuilder::integer()
    ->minimum(0)
    ->maximum(100)
    ->exclusiveMinimum(0)
    ->exclusiveMaximum(100);

SchemaBuilder::number()
    ->minimum(0.0)
    ->maximum(1.0);

Boolean

SchemaBuilder::boolean()
    ->default(false);

Array

SchemaBuilder::array(SchemaBuilder::string())
    ->minItems(1)
    ->maxItems(10)
    ->uniqueItems();

Object

SchemaBuilder::object()
    ->property('name', SchemaBuilder::string()->required())
    ->property('age', SchemaBuilder::integer())
    ->additionalProperties(false)
    ->minProperties(1)
    ->maxProperties(10);

MCP Presets Reference

Identifiers

Method Description
McpSchema::entityId($type) Entity ID (numeric or UUID)
McpSchema::machineName($desc) Machine name pattern [a-z][a-z0-9_]*
McpSchema::uuid() UUID format
McpSchema::slug() URL-safe slug

Pagination & Filtering

Method Description
McpSchema::pagination($default, $max) limit + offset properties
McpSchema::cursorPagination($default) limit + cursor properties
McpSchema::sorting($fields) sort_by + sort_order properties
McpSchema::searchQuery($minLen) Search query string
McpSchema::statusFilter($statuses) Status enum filter
McpSchema::dateRange() from + to date properties

Content

Method Description
McpSchema::title($maxLen) Title string with length limits
McpSchema::body($allowHtml) Body/content field
McpSchema::tags() Array of tag strings
McpSchema::metadata() Key-value object

Complete Tool Schemas

Method Description
McpSchema::listToolSchema($filters, $sorts) List entities with pagination
McpSchema::getToolSchema($idField, $type) Get single entity by ID
McpSchema::createToolSchema($required, $optional) Create entity
McpSchema::updateToolSchema($idField, $fields) Update entity
McpSchema::deleteToolSchema($idField, $force) Delete entity
McpSchema::confirmation() Destructive operation confirmation

Validation

The SchemaValidator validates:

  • Type checking: string, integer, number, boolean, array, object
  • String constraints: minLength, maxLength, pattern, format
  • Number constraints: minimum, maximum, exclusiveMinimum, exclusiveMaximum
  • Array constraints: minItems, maxItems, uniqueItems, items schema
  • Object constraints: required properties, additionalProperties
  • Enum validation: Value must be in allowed list
  • Format validation: email, uri, uuid, date, date-time, ipv4, ipv6
$validator = new SchemaValidator();
$result = $validator->validate($input, $schema);

$result->isValid();           // bool
$result->getErrors();         // ValidationError[]
$result->toErrorBag();        // ErrorBag (from mcp-error-codes)

Integration with mcp-error-codes

use CodeWheel\McpSchemaBuilder\SchemaValidator;
use CodeWheel\McpErrorCodes\ErrorBag;

$validator = new SchemaValidator();
$result = $validator->validate($input, $schema);

if (!$result->isValid()) {
    // Convert validation errors to ErrorBag
    $errorBag = $result->toErrorBag();

    // Return as MCP tool result
    return $errorBag->toToolResult();
}

Integration with mcp-tool-gateway

use CodeWheel\McpToolGateway\Middleware\ValidatingMiddleware;
use CodeWheel\McpToolGateway\Middleware\MiddlewarePipeline;
use CodeWheel\McpSchemaBuilder\SchemaValidator;

// Automatic validation before tool execution
$validator = new SchemaValidator();
$middleware = new ValidatingMiddleware($provider, $validator);

$pipeline = new MiddlewarePipeline($provider);
$pipeline->add($middleware);

// Invalid inputs are rejected before reaching tools
$result = $pipeline->execute('create_user', $input);

License

MIT License - see LICENSE file.