Skip to content

Architecture Overview

The MCP Client module uses a clean, object-oriented architecture centered around immutable Value Objects (DTOs) that represent MCP protocol entities.

Value Object Pattern

The module implements the Value Object pattern for representing MCP tools and their related data. Value Objects are:

  • Immutable: Once created, their state cannot be modified
  • Self-validating: Enforce business rules in their constructors
  • Type-safe: Use PHP type hints throughout
  • Protocol-compliant: Follow the MCP protocol specification

Core Components

Value Objects (src/ValueObject/)

The heart of the architecture consists of immutable Value Objects that represent MCP protocol entities:

ValueObject/
├── Tool.php                    # Represents a single MCP tool
├── ToolInterface.php           # Tool contract
├── ToolBuilder.php             # Builder for Tool creation/modification
├── ToolCollection.php          # Collection of tools
├── ToolCollectionInterface.php # Collection contract
├── InputSchema.php             # JSON Schema for tool inputs
├── InputSchemaInterface.php    # Schema contract
├── LockedDefinition.php        # Snapshot of locked tool state
└── LockedDefinitionInterface.php # Locked definition contract

Config Entity (src/Entity/)

The McpServer config entity stores MCP server configurations and uses Value Objects internally:

  • Stores server connection details (endpoint, transport type, credentials)
  • Manages tool collections via ToolCollectionInterface
  • Provides getters/setters for tool access

Plugin System

  • McpToolDeriver: Discovers tools from MCP servers and creates Tool API plugins
  • McpToolBase: Base plugin class for executing MCP tools

Design Principles

1. Immutability with Builder Pattern

All Value Objects are immutable. To modify them, use the Builder pattern:

use Drupal\mcp_client\ValueObject\ToolBuilder;

$tool = new Tool('my_tool', 'Description', $inputSchema);

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

// $tool remains unchanged, $enabledTool is a new instance

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

// Create new tool with builder (required fields enforced)
$newTool = ToolBuilder::create('my_tool', 'Description', $inputSchema)
  ->setEnabled(TRUE)
  ->build();

Why Builder Pattern? - Memory efficient: Creates only one object vs multiple intermediate objects - Clear intent: Explicitly shows object construction - Fail-fast: Required fields validated at creation time, not build time - Easy to extend: Add properties without updating multiple methods - Type-safe validation: Enforced by constructor and type hints

2. Type Safety

Strong typing throughout prevents runtime errors:

public function getTools(): ToolCollectionInterface;
public function getTool(string $name): ?ToolInterface;

3. Protocol Compliance

Value Objects follow MCP protocol naming conventions (camelCase) while supporting Drupal conventions (snake_case) for backward compatibility:

// Both work for backward compatibility
$data = ['inputSchema' => [...]] // MCP standard
$data = ['input_schema' => [...]] // Legacy Drupal

4. Separation of Concerns

  • Value Objects: Pure data representation
  • Entities: Persistence and Drupal integration
  • Plugins: Business logic and tool execution
  • Services: Infrastructure and communication

Data Flow

MCP Server → McpClient Service → Value Objects → Config Entity → Tool Plugins → AI Agent
  1. MCP server returns tool definitions
  2. Service creates Value Objects from raw data
  3. Config entity stores Value Objects
  4. Tool deriver creates plugins from Value Objects
  5. AI agents call tools via plugins

Next Steps