drupal / jsonrpc_mcp
Exposes Drupal JSON-RPC method plugins as MCP (Model Context Protocol) tools, enabling integration with AI assistants like Claude Desktop
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:drupal-module
Requires
- php: >=8.1
- drupal/core: ^10.2 || ^11
- drupal/jsonrpc: ^3@beta
Requires (Dev)
- drupal/coder: ^8
- mglaman/phpstan-drupal: ^2.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
README
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.
Overview
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.
Key Features
- ๐ 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
Requirements
- Drupal 10.2+ or 11.x
- PHP 8.1+
- JSON-RPC module (version 3.0.0-beta1 or higher)
How It Works
Architecture
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
Metadata Mapping
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 |
Usage
Marking Methods for MCP Exposure
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']; } }
Example with Parameters
#[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"] } }
Discovery Endpoints
The module provides three complementary endpoints for MCP tool discovery and invocation following a standard workflow:
Discovery 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
When to Use Each Endpoint
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
Quick Examples
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 }
Pagination
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.
API Reference
Authentication
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
GET /mcp/tools/list
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 |
GET /mcp/tools/describe
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 |
POST /mcp/tools/invoke
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 |
Development
Creating Custom MCP Tools
-
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")'
References
- 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