PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.5.23
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.5.23
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / wp-mcp-server / class-mcp-json-rpc-handler.php

class-mcp-json-rpc-handler.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.5.23, at wp-mcp-server/class-mcp-json-rpc-handler.php

208 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP JSON-RPC 2.0 Handler
4 *
5 * Handles parsing, validation, and routing of JSON-RPC 2.0 requests
6 * according to the Model Context Protocol specification.
7 *
8 * @package MetaSync
9 * @subpackage MCP_Server
10 */
11
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 class MCP_JSON_RPC_Handler {
17
18 /**
19 * JSON-RPC version
20 */
21 const JSONRPC_VERSION = '2.0';
22
23 /**
24 * Error codes (JSON-RPC 2.0 standard + custom)
25 */
26 const ERROR_PARSE_ERROR = -32700;
27 const ERROR_INVALID_REQUEST = -32600;
28 const ERROR_METHOD_NOT_FOUND = -32601;
29 const ERROR_INVALID_PARAMS = -32602;
30 const ERROR_INTERNAL_ERROR = -32603;
31 const ERROR_SERVER_ERROR = -32000;
32
33 /**
34 * Method handlers
35 *
36 * @var array
37 */
38 private $handlers = [];
39
40 /**
41 * Constructor
42 */
43 public function __construct() {
44 // Register default handlers
45 $this->register_handler('initialize', [$this, 'handle_initialize']);
46 $this->register_handler('ping', [$this, 'handle_ping']);
47 }
48
49 /**
50 * Register a method handler
51 *
52 * @param string $method Method name
53 * @param callable $callback Handler callback
54 */
55 public function register_handler($method, $callback) {
56 if (!is_callable($callback)) {
57 throw new InvalidArgumentException("Handler for method '{$method}' must be callable");
58 }
59 $this->handlers[$method] = $callback;
60 }
61
62 /**
63 * Handle incoming JSON-RPC request
64 *
65 * @param string $request_body Raw request body
66 * @return array Response array
67 */
68 public function handle_request($request_body) {
69 // Parse JSON
70 $request = json_decode($request_body, true);
71
72 if (json_last_error() !== JSON_ERROR_NONE) {
73 return $this->error_response(null, self::ERROR_PARSE_ERROR, 'Parse error');
74 }
75
76 // Validate request structure
77 if (!$this->validate_request($request)) {
78 return $this->error_response(
79 isset($request['id']) ? $request['id'] : null,
80 self::ERROR_INVALID_REQUEST,
81 'Invalid Request'
82 );
83 }
84
85 $method = $request['method'];
86 $params = isset($request['params']) ? $request['params'] : [];
87 $id = isset($request['id']) ? $request['id'] : null;
88
89 // Check if handler exists
90 if (!isset($this->handlers[$method])) {
91 return $this->error_response($id, self::ERROR_METHOD_NOT_FOUND, "Method not found: {$method}");
92 }
93
94 try {
95 // Call handler
96 $result = call_user_func($this->handlers[$method], $params);
97 return $this->success_response($id, $result);
98 } catch (InvalidArgumentException $e) {
99 return $this->error_response($id, self::ERROR_INVALID_PARAMS, $e->getMessage());
100 } catch (Exception $e) {
101 // Log error
102 error_log('MCP JSON-RPC Error: ' . $e->getMessage());
103 return $this->error_response($id, self::ERROR_INTERNAL_ERROR, 'Internal error');
104 }
105 }
106
107 /**
108 * Validate JSON-RPC request structure
109 *
110 * @param mixed $request Request data
111 * @return bool
112 */
113 private function validate_request($request) {
114 if (!is_array($request)) {
115 return false;
116 }
117
118 // Must have jsonrpc, method
119 if (!isset($request['jsonrpc']) || $request['jsonrpc'] !== self::JSONRPC_VERSION) {
120 return false;
121 }
122
123 if (!isset($request['method']) || !is_string($request['method'])) {
124 return false;
125 }
126
127 // Params are optional but must be array or object if present
128 if (isset($request['params']) && !is_array($request['params'])) {
129 return false;
130 }
131
132 return true;
133 }
134
135 /**
136 * Create success response
137 *
138 * @param mixed $id Request ID
139 * @param mixed $result Result data
140 * @return array
141 */
142 public function success_response($id, $result) {
143 return [
144 'jsonrpc' => self::JSONRPC_VERSION,
145 'id' => $id,
146 'result' => $result
147 ];
148 }
149
150 /**
151 * Create error response
152 *
153 * @param mixed $id Request ID
154 * @param int $code Error code
155 * @param string $message Error message
156 * @param mixed $data Optional error data
157 * @return array
158 */
159 public function error_response($id, $code, $message, $data = null) {
160 $error = [
161 'code' => $code,
162 'message' => $message
163 ];
164
165 if ($data !== null) {
166 $error['data'] = $data;
167 }
168
169 return [
170 'jsonrpc' => self::JSONRPC_VERSION,
171 'id' => $id,
172 'error' => $error
173 ];
174 }
175
176 /**
177 * Handle initialize method
178 *
179 * @param array $params Request parameters
180 * @return array
181 */
182 private function handle_initialize($params) {
183 return [
184 'protocolVersion' => '2024-11-05',
185 'capabilities' => [
186 'tools' => [
187 'list' => true,
188 'call' => true
189 ]
190 ],
191 'serverInfo' => [
192 'name' => 'metasync-wordpress-mcp',
193 'version' => METASYNC_VERSION
194 ]
195 ];
196 }
197
198 /**
199 * Handle ping method
200 *
201 * @param array $params Request parameters
202 * @return array
203 */
204 private function handle_ping($params) {
205 return ['status' => 'ok'];
206 }
207 }
208