A Drupal module that exposes JSON-RPC method plugins as MCP (Model Context Protocol) tools, enabling seamless integration between Drupal and MCP-compatible AI assistants like Claude Desktop.
The Model Context Protocol (MCP) specification (2025-06-18) is an open standard introduced by Anthropic that enables AI systems to discover and interact with external tools and data sources. This module bridges Drupal's JSON-RPC infrastructure with MCP, allowing Drupal sites to be discovered and used as MCP servers.
- π Automatic Tool Discovery: Expose existing JSON-RPC methods as MCP tools using a simple PHP attribute
- π MCP-Compliant Endpoints: Provides
/mcp/tools/list
endpoint following MCP specification (2025-06-18) - π Security Built-in: Inherits access control from JSON-RPC method permissions
- π JSON Schema Validation: Automatic conversion of JSON-RPC schemas to MCP inputSchema/outputSchema
- Drupal 10.2+ or 11.x
- PHP 8.1+
- JSON-RPC module (version 3.0.0-beta1 or higher)
Drupal JSON-RPC Method β #[McpTool] Attribute β MCP Tool Metadata β MCP Client (Claude, etc.)
The module uses PHP 8 attributes to mark JSON-RPC methods for MCP exposure. When an MCP client queries the discovery endpoint, the module:
- Discovers all JSON-RPC methods marked with
#[McpTool]
- Converts JSON-RPC metadata to MCP tool schema format
- Returns MCP-compliant tool definitions with proper JSON Schema
The module automatically maps JSON-RPC method metadata to MCP tool schema:
JSON-RPC Field | MCP Field | Description |
---|---|---|
id |
name |
Unique tool identifier |
usage |
description |
Human-readable description |
params |
inputSchema |
JSON Schema for parameters |
output |
outputSchema |
JSON Schema for return value |
(via #[McpTool] ) |
title |
Display name for the tool |
(via #[McpTool] ) |
annotations |
MCP-specific metadata |
Add the #[McpTool]
attribute to any JSON-RPC method class:
<?php
namespace Drupal\mymodule\Plugin\jsonrpc\Method;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\jsonrpc\Attribute\JsonRpcMethod;
use Drupal\jsonrpc\Attribute\JsonRpcParameterDefinition;
use Drupal\jsonrpc_mcp\Attribute\McpTool;
use Drupal\jsonrpc\Plugin\JsonRpcMethodBase;
use Drupal\jsonrpc\JsonRpcObject\ParameterBag;
#[JsonRpcMethod(
id: "cache.rebuild",
usage: new TranslatableMarkup("Rebuilds the Drupal system cache."),
access: ["administer site configuration"]
)]
#[McpTool(
title: "Rebuild Drupal Cache",
annotations: [
'category' => 'system',
'destructive' => false,
]
)]
class CacheRebuild extends JsonRpcMethodBase {
public function execute(ParameterBag $params): bool {
drupal_flush_all_caches();
return true;
}
public static function outputSchema(): array {
return ['type' => 'boolean'];
}
}
#[JsonRpcMethod(
id: "node.create",
usage: new TranslatableMarkup("Creates a new content node."),
access: ["create content"],
params: [
'title' => new JsonRpcParameterDefinition(
'title',
["type" => "string"],
null,
new TranslatableMarkup("The node title"),
true
),
'type' => new JsonRpcParameterDefinition(
'type',
["type" => "string"],
null,
new TranslatableMarkup("The content type machine name"),
true
),
]
)]
#[McpTool(
title: "Create Content Node"
)]
class NodeCreate extends JsonRpcMethodBase {
// Implementation...
}
This automatically generates the MCP tool schema:
{
"name": "node.create",
"title": "Create Content Node",
"description": "Creates a new content node.",
"inputSchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "The node title"
},
"type": {
"type": "string",
"description": "The content type machine name"
}
},
"required": ["title", "type"]
}
}
The module provides three complementary endpoints for MCP tool discovery and invocation following a standard workflow:
-
List Tools β Query
/mcp/tools/list
to discover all accessible tools- Supports pagination for sites with many tools
- Returns tool names, descriptions, and input schemas
-
Describe Tool (Optional) β Query
/mcp/tools/describe?name=X
for detailed schema- Useful for dynamic form generation or validation
- Returns complete input/output schemas and annotations
-
Invoke Tool β POST to
/mcp/tools/invoke
to execute the tool- Requires tool name and arguments
- Returns results or error information
Use /mcp/tools/list
when:
- Discovering what tools are available
- Building a tool catalog
- The basic metadata (name, title, description) is sufficient
Use /mcp/tools/describe
when:
- You need complete schema details
- Building dynamic forms or validation logic
- Generating client code or documentation
Use /mcp/tools/invoke
when:
- Executing a tool with prepared arguments
- User/system is ready to perform the action
List available tools:
curl https://your-site.com/mcp/tools/list | jq
Response:
{
"tools": [
{
"name": "cache.rebuild",
"title": "Rebuild Drupal Cache",
"description": "Rebuilds the Drupal system cache.",
"inputSchema": {
"type": "object",
"properties": {}
}
}
],
"nextCursor": null
}
Describe a specific tool:
curl "https://your-site.com/mcp/tools/describe?name=cache.rebuild" | jq
Invoke a tool:
curl -X POST https://your-site.com/mcp/tools/invoke \
-H "Content-Type: application/json" \
-d '{"name": "cache.rebuild", "arguments": {}}'
Response:
{
"result": true
}
When dealing with many tools, use cursor-based pagination:
# First request
curl https://your-site.com/mcp/tools/list
# Response includes nextCursor
{
"tools": [...],
"nextCursor": "NTA="
}
# Follow nextCursor for more results
curl https://your-site.com/mcp/tools/list?cursor=NTA=
# Continue until nextCursor is null
{
"tools": [...],
"nextCursor": null
}
π‘ For complete API documentation including all parameters, status codes, error formats, and security details, see the API Reference section below.
All MCP endpoints inherit access control from the underlying JSON-RPC methods:
- Authentication uses standard Drupal mechanisms (session cookies, OAuth, HTTP Basic)
- Permissions are inherited from the
access
parameter in#[JsonRpcMethod]
- All permissions in the
access
array must be satisfied (AND logic) - Users must have appropriate permissions to discover or invoke tools
Lists all available MCP tools with pagination support.
Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
cursor |
string | No | Base64-encoded pagination cursor from previous response |
Response (200 OK):
{
"tools": [
{
"name": "string",
"description": "string",
"inputSchema": {},
"title": "string",
"outputSchema": {}",
"annotations": {}"
}
],
"nextCursor": "string|null"
}
Fields name
, description
, and inputSchema
are not optional and they will always be present.
Pagination:
- Page size: 50 tools per request
- Cursor format: Base64-encoded integer offset
nextCursor
isnull
when no more results exist
Status Codes:
Code | Description |
---|---|
200 | Success |
400 | Invalid cursor format |
401 | Authentication required |
403 | Access denied |
500 | Server error |
Returns detailed schema information for a specific tool.
Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
name |
string | Yes | Tool identifier (query parameter) |
Response (200 OK):
{
"tool": {
"name": "string",
"description": "string",
"inputSchema": {},
"outputSchema": {},
"title": "string",
"annotations": {}"
}
}
Fields name
, description
, inputSchema
, and outputSchema
are not optional and they will always be present.
Error Response (400/404):
{
"error": {
"code": "missing_parameter|tool_not_found",
"message": "Error description"
}
}
Status Codes:
Code | Description |
---|---|
200 | Success |
400 | Missing or invalid name parameter |
404 | Tool not found or access denied |
500 | Server error |
Invokes a tool with the provided arguments.
Request Body:
{
"name": "string",
"arguments": {}
}
Response (200 OK):
{
"result": "any type matching tool's outputSchema"
}
Error Response:
{
"error": {
"code": "invalid_json|missing_parameter|tool_not_found|execution_error",
"message": "Error description"
}
}
Status Codes:
Code | Description |
---|---|
200 | Success |
400 | Invalid JSON, missing fields, or invalid arguments |
404 | Tool not found or access denied |
500 | Execution error |
-
Create a JSON-RPC Method Plugin
mkdir -p src/Plugin/jsonrpc/Method
-
Add the Method Class
namespace Drupal\mymodule\Plugin\jsonrpc\Method; use Drupal\jsonrpc\Attribute\JsonRpcMethod; use Drupal\jsonrpc_mcp\Attribute\McpTool; // ... implementation
-
Clear Cache
drush cache:rebuild
-
Verify Discovery
curl https://your-site.com/mcp/tools/list | jq '.tools[] | select(.name == "your.method")'
- Model Context Protocol Specification (2025-06-18) - Official MCP specification
- MCP Server Tools - Server-side tool implementation guide
- MCP Tool Discovery - Tool discovery protocol
- JSON Schema Draft 7 - Schema specification used by MCP
- Drupal JSON-RPC Module - Base JSON-RPC infrastructure