PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 3.4.0
AI Engine – The Chatbot, AI Framework & MCP for WordPress v3.4.0
3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / labs / mcp-rest.php
ai-engine / labs Last commit date
mcp-core.php 4 months ago mcp-rest.php 4 months ago mcp.conf 1 year ago mcp.js 8 months ago mcp.md 8 months ago mcp.php 4 months ago
mcp-rest.php
243 lines
1 <?php
2
3 class Meow_MWAI_Labs_MCP_Rest {
4 private $cache_key = 'mwai_mcp_tools_cache';
5 private $allowed = [ 'posts', 'pages', 'media' ];
6
7 public function __construct() {
8 add_action( 'rest_api_init', [ $this, 'rest_api_init' ] );
9 }
10
11 public function rest_api_init() {
12 add_filter( 'mwai_mcp_tools', [ $this, 'register_rest_tools' ] );
13 add_filter( 'mwai_mcp_callback', [ $this, 'handle_call' ], 10, 4 );
14 }
15
16 public function register_rest_tools( $prevTools ) {
17 $cached = get_transient( $this->cache_key );
18
19 if ( !$cached ) {
20 $tools = [];
21 $server = rest_get_server();
22 $routes = $server->get_routes();
23
24 foreach ( $this->allowed as $resource ) {
25 $base = "/wp/v2/{$resource}";
26 $item = "{$base}/(?P<id>[\d]+)";
27
28 if ( isset( $routes[ $base ] ) ) {
29 foreach ( $routes[ $base ] as $endpoint ) {
30 if ( !empty( $endpoint['methods']['GET'] ) ) {
31 $tools[ "list_{$resource}" ] = [
32 'name' => "list_{$resource}",
33 'description' => "List {$resource}",
34 'category' => 'Dynamic REST',
35 'inputSchema' => $this->build_schema_from_args( $endpoint['args'] ),
36 'outputSchema' => $this->build_output_schema(),
37 'accessLevel' => 'read',
38 ];
39 break;
40 }
41 }
42 }
43
44 if ( isset( $routes[ $item ] ) ) {
45 foreach ( $routes[ $item ] as $endpoint ) {
46 if ( !empty( $endpoint['methods']['GET'] ) ) {
47 $tools[ "get_{$resource}" ] = [
48 'name' => "get_{$resource}",
49 'description' => "Get single {$resource} by ID",
50 'category' => 'Dynamic REST',
51 'inputSchema' => $this->build_schema_from_args( $endpoint['args'] ),
52 'outputSchema' => $this->build_output_schema(),
53 'accessLevel' => 'read',
54 ];
55 break;
56 }
57 }
58 }
59
60 if ( isset( $routes[ $base ] ) ) {
61 foreach ( $routes[ $base ] as $endpoint ) {
62 if ( !empty( $endpoint['methods']['POST'] ) ) {
63 $tools[ "create_{$resource}" ] = [
64 'name' => "create_{$resource}",
65 'description' => "Create {$resource}",
66 'category' => 'Dynamic REST',
67 'inputSchema' => $this->build_schema_from_args( $endpoint['args'] ),
68 'outputSchema' => $this->build_output_schema(),
69 'accessLevel' => 'write',
70 ];
71 break;
72 }
73 }
74 }
75
76 if ( isset( $routes[ $item ] ) ) {
77 foreach ( $routes[ $item ] as $endpoint ) {
78 $methods = array_keys( $endpoint['methods'] );
79 if ( array_intersect( [ 'POST', 'PUT', 'PATCH' ], $methods ) ) {
80 $tools[ "update_{$resource}" ] = [
81 'name' => "update_{$resource}",
82 'description' => "Update {$resource}",
83 'category' => 'Dynamic REST',
84 'inputSchema' => $this->build_schema_from_args( $endpoint['args'] ),
85 'outputSchema' => $this->build_output_schema(),
86 'accessLevel' => 'write',
87 ];
88 break;
89 }
90 }
91 }
92
93 if ( isset( $routes[ $item ] ) ) {
94 foreach ( $routes[ $item ] as $endpoint ) {
95 if ( !empty( $endpoint['methods']['DELETE'] ) ) {
96 $tools[ "delete_{$resource}" ] = [
97 'name' => "delete_{$resource}",
98 'description' => "Delete {$resource}",
99 'category' => 'Dynamic REST',
100 'inputSchema' => $this->build_schema_from_args( $endpoint['args'] ),
101 'outputSchema' => $this->build_output_schema(),
102 'accessLevel' => 'admin',
103 ];
104 break;
105 }
106 }
107 }
108 }
109
110 set_transient( $this->cache_key, $tools, DAY_IN_SECONDS );
111 $cached = $tools;
112 }
113
114 return array_merge( array_values( $cached ), $prevTools );
115 }
116
117 private function build_schema_from_args( $args ) {
118 $schema = [
119 'type' => 'object',
120 'properties' => [],
121 'required' => [],
122 ];
123
124 foreach ( $args as $name => $def ) {
125 $schema['properties'][ $name ] = [
126 'type' => $def['type'] ?? 'string',
127 'description' => $def['description'] ?? '',
128 ];
129
130 if ( !empty( $def['required'] ) ) {
131 $schema['required'][] = $name;
132 }
133 }
134
135 return $schema;
136 }
137
138 private function build_output_schema() {
139 return [
140 'type' => 'object',
141 'properties' => [
142 'content' => [
143 'type' => 'array',
144 'items' => [
145 'type' => 'object',
146 'properties' => [
147 'type' => [
148 'type' => 'string',
149 'description' => 'Block type, e.g. text or image',
150 ],
151 'text' => [
152 'type' => 'string',
153 'description' => 'Human-readable content',
154 ],
155 ],
156 'required' => [ 'type', 'text' ],
157 ],
158 ],
159 ],
160 'required' => [ 'content' ],
161 ];
162 }
163
164 public function handle_call( $existing, $tool, $args, $id ) {
165 if ( !empty( $existing ) ) {
166 return $existing;
167 }
168
169 $tools = get_transient( $this->cache_key );
170 if ( !isset( $tools[ $tool ] ) ) {
171 return $existing;
172 }
173
174 // Security check is already done in the MCP auth layer
175 // If we reach here, the user is authorized to use MCP
176
177 list( $action, $resource ) = explode( '_', $tool, 2 );
178 $path = "/wp/v2/{$resource}";
179 $method = 'GET';
180
181 if ( in_array( $action, [ 'get', 'update', 'delete' ], true ) ) {
182 if ( empty( $args['id'] ) ) {
183 return [
184 'jsonrpc' => '2.0',
185 'id' => $id,
186 'error' => [
187 'code' => -32602,
188 'message' => 'Missing parameter: id',
189 ],
190 ];
191 }
192 $path .= '/' . intval( $args['id'] );
193 }
194
195 switch ( $action ) {
196 case 'create':
197 case 'update':
198 $method = 'POST';
199 break;
200 case 'delete':
201 $method = 'DELETE';
202 break;
203 default:
204 $method = 'GET';
205 break;
206 }
207
208 $request = new WP_REST_Request( $method, $path );
209
210 if ( $method === 'GET' ) {
211 foreach ( $args as $key => $value ) {
212 $request->set_param( $key, $value );
213 }
214 }
215 else {
216 $request->set_body_params( $args );
217 }
218
219 $response = rest_do_request( $request );
220
221 if ( is_wp_error( $response ) || $response->get_status() >= 400 ) {
222 $error_obj = is_wp_error( $response ) ? $response : $response->as_error();
223
224 // Return error in old format for backward compatibility
225 // The execute_tool method will detect this and not re-wrap it
226 return [
227 'jsonrpc' => '2.0',
228 'id' => $id,
229 'error' => [
230 'code' => (int) ( $error_obj->get_error_code() ?: $response->get_status() ),
231 'message' => $error_obj->get_error_message(),
232 'data' => $error_obj->get_error_data() ?: null,
233 ],
234 ];
235 }
236
237 $data = $response->get_data();
238
239 // Return just the data - execute_tool will wrap it properly
240 return $data;
241 }
242 }
243