Skip to content

Value Objects API Reference

This document provides detailed information about the Value Object classes used in the MCP Client module.

Overview

Value Objects are immutable data structures that represent MCP protocol entities. They provide type safety, validation, and a clean API for working with MCP tools.

Tool

Represents a single MCP tool with its metadata and configuration.

Class: Drupal\mcp_client\ValueObject\Tool

Implements: ToolInterface

Properties (readonly): - string $name - Tool name - string $description - Tool description - InputSchemaInterface $inputSchema - JSON Schema for inputs - bool $enabled - Whether tool is enabled (default: FALSE) - bool $locked - Whether tool is locked (default: FALSE) - ?ToolOperation $operation - Tool operation type (optional) - ?LockedDefinitionInterface $lockedDefinition - Locked definition snapshot (optional)

Creating a Tool

use Drupal\mcp_client\ValueObject\Tool;
use Drupal\mcp_client\ValueObject\InputSchema;

// Create an input schema
$inputSchema = new InputSchema(
  type: 'object',
  properties: [
    'query' => [
      'type' => 'string',
      'description' => 'Search query',
    ],
  ],
  required: ['query']
);

// Create a tool
$tool = new Tool(
  name: 'search_files',
  description: 'Search for files in a directory',
  inputSchema: $inputSchema,
  enabled: TRUE
);

From Array

// MCP protocol format (camelCase)
$tool = Tool::fromArray([
  'name' => 'search_files',
  'description' => 'Search for files',
  'inputSchema' => [
    'type' => 'object',
    'properties' => ['query' => ['type' => 'string']],
  ],
  'enabled' => TRUE,
  'locked' => FALSE,
]);

// Legacy format (snake_case) - also supported
$tool = Tool::fromArray([
  'name' => 'search_files',
  'description' => 'Search for files',
  'input_schema' => [...], // snake_case still works
]);

Modifying Tools (Builder Pattern)

Tools are immutable. To modify a tool, use the Builder pattern:

use Drupal\mcp_client\ValueObject\ToolBuilder;
use Drupal\tool\Tool\ToolOperation;

// Get original tool
$tool = $mcpServer->getTool('search_files');

// Create modified version using builder (original unchanged)
$enabledTool = $tool->toBuilder()
  ->setEnabled(TRUE)
  ->build();

// Chain multiple modifications (creates only ONE new object)
$modifiedTool = $tool->toBuilder()
  ->setEnabled(TRUE)
  ->setOperation(ToolOperation::READ)
  ->setLocked(TRUE)
  ->build();

// Original $tool remains unchanged

Using ToolBuilder Directly

You can also create tools from scratch using the builder. Required fields (name, description, inputSchema) must be provided during creation:

use Drupal\mcp_client\ValueObject\ToolBuilder;

// Create with required fields
$tool = ToolBuilder::create('search_files', 'Search for files in a directory', $inputSchema)
  ->setEnabled(TRUE)
  ->setOperation(ToolOperation::READ)
  ->build();

// Or from an existing tool
$builder = ToolBuilder::fromTool($existingTool);
$newTool = $builder
  ->setEnabled(FALSE)
  ->build();

Methods

Method Return Type Description
name() string Gets tool name
description() string Gets tool description
getInputSchema() InputSchemaInterface Gets input schema
enabled() bool Checks if enabled
locked() bool Checks if locked
getOperation() ?ToolOperation Gets operation type
getLockedDefinition() ?LockedDefinitionInterface Gets locked definition
toBuilder() ToolBuilder Creates a builder from this tool
toArray() array Converts to array (MCP protocol format)

ToolBuilder

Builder for creating and modifying Tool instances. Provides a mutable, fluent interface for constructing immutable Tool objects without creating intermediate objects (more memory-efficient).

Class: Drupal\mcp_client\ValueObject\ToolBuilder

Creating a Builder

use Drupal\mcp_client\ValueObject\ToolBuilder;

// Create new builder with required fields (name, description, inputSchema)
$builder = ToolBuilder::create('search_files', 'Search for files', $inputSchema);

// Create from existing tool
$builder = ToolBuilder::fromTool($tool);
$builder = $tool->toBuilder(); // Same as above

// Create from array (validates required fields)
$builder = ToolBuilder::fromArray([
  'name' => 'search_files',
  'description' => 'Search for files',
  'inputSchema' => [...],
]);

Factory Methods

Method Returns Description
create(string $name, string $description, InputSchemaInterface $inputSchema) self Creates builder with required fields
fromTool(Tool $tool) self Creates builder from existing tool
fromArray(array $data) self Creates builder from array (validates required fields)

Builder Methods

Method Return Type Description
setEnabled(bool) self Sets enabled state
setLocked(bool) self Sets locked state
setOperation(?ToolOperation) self Sets tool operation
setLockedDefinition(?LockedDefinitionInterface) self Sets locked definition
build() Tool Builds the immutable Tool

Note: setName(), setDescription(), and setInputSchema() are still available for advanced use cases, but required fields must be provided during creation.

Why Builder Pattern?

Memory Efficiency: The builder pattern creates only one Tool object, even when chaining multiple modifications.

Fail-Fast Validation: Required fields are validated at creation time, not build time, catching errors earlier.

// BEFORE Builder Pattern (wither methods created multiple intermediate objects)
$tool->withEnabled(TRUE)->withOperation($op)->withLocked(TRUE); // Created 3 objects

// AFTER Builder Pattern (creates only 1 final object - memory efficient)
$tool->toBuilder()
  ->setEnabled(TRUE)
  ->setOperation($op)
  ->setLocked(TRUE)
  ->build();

// Builder always starts in valid state (required fields enforced at creation)
$builder = ToolBuilder::create($name, $description, $schema); // ✅ Valid from start
// vs
$builder = ToolBuilder::create(); // ❌ Old way - could forget required fields

ToolCollection

A collection of tools with iteration and counting capabilities.

Class: Drupal\mcp_client\ValueObject\ToolCollection

Implements: ToolCollectionInterface, IteratorAggregate, Countable

Creating a Collection

use Drupal\mcp_client\ValueObject\ToolCollection;

// From individual tools
$collection = new ToolCollection($tool1, $tool2, $tool3);

// From array
$collection = ToolCollection::fromArray([
  ['name' => 'tool1', 'description' => '...', 'inputSchema' => [...]],
  ['name' => 'tool2', 'description' => '...', 'inputSchema' => [...]],
]);

// Empty collection
$collection = new ToolCollection();

Working with Collections

// Add a tool
$collection->add($tool);

// Get a tool by name
$tool = $collection->get('search_files');

// Check if tool exists
if ($collection->has('search_files')) {
  // ...
}

// Remove a tool
$collection->remove('search_files');

// Get all tools as array
$tools = $collection->all();

// Count tools
$count = count($collection); // or $collection->count()

// Iterate over tools
foreach ($collection as $name => $tool) {
  echo "Tool: {$tool->name()}\n";
}

// Convert to array
$array = $collection->toArray();

Methods

Method Return Type Description
get(string) ?ToolInterface Gets tool by name
add(ToolInterface) void Adds tool to collection
remove(string) void Removes tool by name
has(string) bool Checks if tool exists
all() ToolInterface[] Gets all tools as array
count() int Counts tools in collection
getIterator() Traversable Gets iterator for foreach
toArray() array Converts to array representation

InputSchema

Represents a JSON Schema for tool input validation following the MCP protocol.

Class: Drupal\mcp_client\ValueObject\InputSchema

Implements: InputSchemaInterface

Properties (readonly): - string $type - Schema type (default: 'object') - array $properties - Property definitions - array $required - Required property names - array $additionalProperties - Additional schema properties

Creating a Schema

use Drupal\mcp_client\ValueObject\InputSchema;

$schema = new InputSchema(
  type: 'object',
  properties: [
    'path' => [
      'type' => 'string',
      'description' => 'File path',
    ],
    'recursive' => [
      'type' => 'boolean',
      'description' => 'Search recursively',
      'default' => FALSE,
    ],
  ],
  required: ['path'],
  additionalProperties: [
    '$schema' => 'http://json-schema.org/draft-07/schema#',
  ]
);

// From array
$schema = InputSchema::fromArray([
  'type' => 'object',
  'properties' => [...],
  'required' => ['path'],
]);

Working with Schemas

// Get all properties
$properties = $schema->getProperties();

// Get specific property
$pathProperty = $schema->getProperty('path');
if ($pathProperty !== NULL) {
  $type = $pathProperty['type'];
}

// Check if property is required
if ($schema->isRequired('path')) {
  // ...
}

// Convert to array
$array = $schema->toArray();

Methods

Method Return Type Description
getProperties() array Gets all property definitions
getProperty(string) ?array Gets specific property definition
isRequired(string) bool Checks if property is required
toArray() array Converts to array (JSON Schema format)

LockedDefinition

A snapshot of a tool's definition at the time it was locked. Used to preserve tool definitions even if the MCP server changes them.

Class: Drupal\mcp_client\ValueObject\LockedDefinition

Implements: LockedDefinitionInterface

Properties (readonly): - string $name - Tool name at lock time - string $description - Tool description at lock time - InputSchemaInterface $inputSchema - Input schema at lock time

Creating a Locked Definition

use Drupal\mcp_client\ValueObject\LockedDefinition;

$lockedDef = new LockedDefinition(
  name: 'search_files',
  description: 'Original description',
  inputSchema: $inputSchema
);

// From array
$lockedDef = LockedDefinition::fromArray([
  'name' => 'search_files',
  'description' => 'Original description',
  'inputSchema' => [...],
]);

Usage with Tools

// Lock a tool with its current definition
$tool = $mcpServer->getTool('search_files');
$lockedDef = new LockedDefinition(
  $tool->name(),
  $tool->description(),
  $tool->getInputSchema()
);

$lockedTool = $tool->toBuilder()
  ->setLocked(TRUE)
  ->setLockedDefinition($lockedDef)
  ->build();

Methods

Method Return Type Description
toArray() array Converts to array representation

Type Safety and Validation

All Value Objects enforce type safety and validation:

// This will throw InvalidArgumentException
$tool = new Tool(
  name: 'test',
  description: 'Test tool',
  inputSchema: $schema,
  locked: TRUE,
  lockedDefinition: NULL // ERROR: locked tools must have definition
);

Best Practices

  1. Use the Builder pattern to create and modify Tool objects efficiently
  2. Type hint with interfaces for flexibility: ToolInterface, ToolCollectionInterface
  3. Use fromArray() when deserializing from storage or external sources
  4. Use toArray() when serializing for storage or API responses
  5. Chain builder methods for multiple modifications to avoid creating intermediate objects
  6. Trust the type system - if it compiles, it's valid