Developer Guide
Welcome to the MCP Client developer documentation. This guide will help you understand the module's architecture and how to work with it programmatically.
Introduction
The MCP Client module provides a clean, type-safe API for working with Model Context Protocol (MCP) tools in Drupal. The module is built around immutable Value Objects that represent MCP protocol entities.
Quick Start for Developers
Basic Tool Access
use Drupal\mcp_client\Entity\McpServer;
// Load an MCP server
$mcpServer = McpServer::load('my_server');
// Get all tools
$tools = $mcpServer->getTools();
// Get a specific tool
$tool = $mcpServer->getTool('search_files');
// Check if tool exists
if ($mcpServer->hasTool('search_files')) {
// Work with the tool
}
Working with Tool Properties
// Access tool information
echo $tool->name();
echo $tool->description();
echo $tool->enabled() ? 'Enabled' : 'Disabled';
// Get input schema
$schema = $tool->getInputSchema();
$properties = $schema->getProperties();
// Check if property is required
if ($schema->isRequired('query')) {
// Handle required field
}
Modifying Tools (Builder Pattern)
Value Objects are immutable. Use the Builder pattern to create modified copies:
use Drupal\mcp_client\ValueObject\ToolBuilder;
use Drupal\tool\Tool\ToolOperation;
// Enable a tool
$enabledTool = $tool->toBuilder()
->setEnabled(TRUE)
->build();
// Lock a tool
$lockedTool = $tool->toBuilder()
->setLocked(TRUE)
->setLockedDefinition($lockedDefinition)
->build();
// Set operation type
$tool = $tool->toBuilder()
->setOperation(ToolOperation::READ)
->build();
// Chain multiple modifications (creates only ONE object)
$modifiedTool = $tool->toBuilder()
->setEnabled(TRUE)
->setOperation(ToolOperation::READ)
->build();
// The original $tool remains unchanged!
Updating Tools in Storage
use Drupal\mcp_client\ValueObject\ToolCollection;
// Get current tools
$tools = $mcpServer->getTools();
// Modify a tool using builder
$tool = $tools->get('search_files');
$enabledTool = $tool->toBuilder()
->setEnabled(TRUE)
->build();
// Create new collection with modified tool
$newCollection = new ToolCollection(...$tools->all());
$newCollection->remove('search_files');
$newCollection->add($enabledTool);
// Update and save
$mcpServer->setTools($newCollection);
$mcpServer->save();
Key Concepts
1. Value Objects
All MCP entities are represented as immutable Value Objects:
- Tool: Represents a single MCP tool
- ToolCollection: A collection of tools
- InputSchema: JSON Schema for tool inputs
- LockedDefinition: Snapshot of a locked tool's definition
2. Immutability
Value Objects cannot be modified after creation. Instead, use the Builder pattern that returns new instances:
// ❌ This won't work (properties are readonly)
$tool->enabled = TRUE;
// ✅ This is the correct way
$tool = $tool->toBuilder()
->setEnabled(TRUE)
->build();
3. Type Safety
The module uses strict typing throughout:
public function getTools(): ToolCollectionInterface;
public function getTool(string $name): ?ToolInterface;
4. Protocol Compliance
Value Objects follow the MCP protocol specification, using camelCase for property names while supporting snake_case for backward compatibility.
Common Tasks
List All Enabled Tools
$tools = $mcpServer->getTools();
$enabledTools = array_filter(
$tools->all(),
fn($tool) => $tool->enabled()
);
Enable All Tools
$tools = $mcpServer->getTools();
$enabledTools = array_map(
fn($tool) => $tool->toBuilder()->setEnabled(TRUE)->build(),
$tools->all()
);
$mcpServer->setTools(new ToolCollection(...$enabledTools));
$mcpServer->save();
Export Tool Definitions
// Single tool
$toolArray = $tool->toArray();
// All tools
$toolsArray = $mcpServer->getTools()->toArray();
Import Tool Definitions
use Drupal\mcp_client\ValueObject\Tool;
use Drupal\mcp_client\ValueObject\ToolCollection;
$tools = array_map(
fn($data) => Tool::fromArray($data),
$externalData
);
$collection = new ToolCollection(...$tools);
$mcpServer->setTools($collection);
$mcpServer->save();
Documentation Structure
- Architecture Overview - Module design and patterns
- Value Objects API - Detailed API reference
- Quick Reference - Cheat sheet for common operations
Best Practices
-
Type hint with interfaces for flexibility:
php function processTools(ToolCollectionInterface $tools): void -
Always save after modifications:
php $mcpServer->setTools($newCollection); $mcpServer->save(); // Don't forget! -
Check existence before access:
php if ($mcpServer->hasTool('my_tool')) { $tool = $mcpServer->getTool('my_tool'); } -
Batch operations efficiently (save once, not in loops): ```php // ✅ Good: Single save $tools = array_map( fn($t) => $t->toBuilder()->setEnabled(TRUE)->build(), $tools->all() ); $mcpServer->setTools(new ToolCollection(...$tools)); $mcpServer->save();
// ❌ Bad: Multiple saves foreach ($tools as $tool) { // ... save in loop } ```
-
Use builder pattern for modifications to improve memory efficiency
-
Trust the type system - if it compiles, it's valid
Need Help?
- Check the API Reference for detailed documentation
- See the Quick Reference for common patterns
- Review the Architecture to understand design decisions
- Visit the Issue Queue for support
Contributing
When extending or contributing to the module:
- Follow Drupal coding standards
- Maintain immutability of Value Objects
- Add comprehensive PHPDoc comments
- Write unit and kernel tests
- Update documentation for new features