|
2 | 2 |
|
3 | 3 | namespace WP_CLI\AiCommand; |
4 | 4 |
|
| 5 | +use AiCommand\Tools\FileTools; |
| 6 | +use AiCommand\Tools\URLTools; |
5 | 7 | use WP_CLI; |
6 | 8 | use WP_CLI_Command; |
7 | 9 | use WP_Community_Events; |
@@ -46,19 +48,19 @@ class AiCommand extends WP_CLI_Command { |
46 | 48 | */ |
47 | 49 | public function __invoke( $args, $assoc_args ) { |
48 | 50 | $server = new MCP\Server(); |
49 | | - $client = new MCP\Client($server); |
| 51 | + $client = new MCP\Client( $server ); |
50 | 52 |
|
51 | | - $this->register_tools($server, $client); |
| 53 | + $this->register_tools( $server, $client ); |
52 | 54 |
|
53 | | - $this->register_resources($server); |
| 55 | + $this->register_resources( $server ); |
54 | 56 |
|
55 | 57 | $result = $client->call_ai_service_with_prompt( $args[0] ); |
56 | 58 |
|
57 | 59 | WP_CLI::success( $result ); |
58 | 60 | } |
59 | 61 |
|
60 | 62 | // Register tools for AI processing |
61 | | - private function register_tools($server, $client) { |
| 63 | + private function register_tools( $server, $client ) { |
62 | 64 | $server->register_tool( |
63 | 65 | [ |
64 | 66 | 'name' => 'list_tools', |
@@ -90,250 +92,124 @@ private function register_tools($server, $client) { |
90 | 92 | $map_rest_to_mcp = new MapRESTtoMCP(); |
91 | 93 | $map_rest_to_mcp->map_rest_to_mcp( $server ); |
92 | 94 |
|
93 | | - $server->register_tool( |
94 | | - [ |
95 | | - 'name' => 'create_post', |
96 | | - 'description' => 'Creates a post.', |
97 | | - 'inputSchema' => [ |
98 | | - 'type' => 'object', |
99 | | - 'properties' => [ |
100 | | - 'title' => [ |
101 | | - 'type' => 'string', |
102 | | - 'description' => 'The title of the post.', |
103 | | - ], |
104 | | - 'content' => [ |
105 | | - 'type' => 'string', |
106 | | - 'description' => 'The content of the post.', |
107 | | - ], |
108 | | - 'category' => [ |
109 | | - 'type' => 'string', |
110 | | - 'description' => 'The category of the post.', |
111 | | - ], |
112 | | - ], |
113 | | - 'required' => [ 'title', 'content' ], |
114 | | - ], |
115 | | - 'callable' => function ( $params ) { |
116 | | - $request = new \WP_REST_Request( 'POST', '/wp/v2/posts' ); |
117 | | - $request->set_body_params( [ |
118 | | - 'title' => $params['title'], |
119 | | - 'content' => $params['content'], |
120 | | - 'categories' => [ $params['category'] ], |
121 | | - 'status' => 'publish', |
122 | | - ] ); |
123 | | - $controller = new \WP_REST_Posts_Controller( 'post' ); |
124 | | - $response = $controller->create_item( $request ); |
125 | | - $data = $response->get_data(); |
126 | | - return $data; |
127 | | - }, |
128 | | - ] |
129 | | - ); |
| 95 | + new FileTools( $server ); |
| 96 | + new URLTools( $server ); |
130 | 97 |
|
131 | 98 | $server->register_tool( |
132 | 99 | [ |
133 | | - 'name' => 'calculate_total', |
134 | | - 'description' => 'Calculates the total price.', |
| 100 | + 'name' => 'fetch_wp_community_events', |
| 101 | + 'description' => 'Fetches upcoming WordPress community events near a specified city or the user\'s current location. If no events are found in the exact location, nearby events within a specific radius will be considered.', |
135 | 102 | 'inputSchema' => [ |
136 | 103 | 'type' => 'object', |
137 | 104 | 'properties' => [ |
138 | | - 'price' => [ |
139 | | - 'type' => 'integer', |
140 | | - 'description' => 'The price of the item.', |
141 | | - ], |
142 | | - 'quantity' => [ |
143 | | - 'type' => 'integer', |
144 | | - 'description' => 'The quantity of items.', |
145 | | - ], |
146 | | - ], |
147 | | - 'required' => [ 'price', 'quantity' ], |
148 | | - ], |
149 | | - 'callable' => function ( $params ) { |
150 | | - $price = $params['price'] ?? 0; |
151 | | - $quantity = $params['quantity'] ?? 1; |
152 | | - |
153 | | - return $price * $quantity; |
154 | | - }, |
155 | | - ] |
156 | | - ); |
157 | | - |
158 | | - |
159 | | - |
160 | | - // Register tool to retrieve last N posts in JSON format. |
161 | | - $server->register_tool([ |
162 | | - 'name' => 'list_posts', |
163 | | - 'description' => 'Retrieves the last N posts.', |
164 | | - 'inputSchema' => [ |
165 | | - 'type' => 'object', |
166 | | - 'properties' => [ |
167 | | - 'count' => [ |
168 | | - 'type' => 'integer', |
169 | | - 'description' => 'The number of posts to retrieve.', |
170 | | - ], |
171 | | - ], |
172 | | - 'required' => ['count'], |
173 | | - ], |
174 | | - 'callable' => function ($params) { |
175 | | - $query = new \WP_Query([ |
176 | | - 'posts_per_page' => $params['count'], |
177 | | - 'post_status' => 'publish', |
178 | | - ]); |
179 | | - $posts = []; |
180 | | - while ($query->have_posts()) { |
181 | | - $query->the_post(); |
182 | | - $posts[] = ['title' => get_the_title(), 'content' => get_the_content()]; |
183 | | - } |
184 | | - wp_reset_postdata(); |
185 | | - return $posts; |
186 | | - }, |
187 | | - ]); |
188 | | - |
189 | | - $server->register_tool( |
190 | | - [ |
191 | | - 'name' => 'greet', |
192 | | - 'description' => 'Greets the user.', |
193 | | - 'inputSchema' => [ |
194 | | - 'type' => 'object', |
195 | | - 'properties' => [ |
196 | | - 'name' => [ |
| 105 | + 'location' => [ |
197 | 106 | 'type' => 'string', |
198 | | - 'description' => 'The name of the user.', |
| 107 | + 'description' => 'City name or "near me" for auto-detected location. If no events are found in the exact location, the tool will also consider nearby events within a specified radius (default: 100 km).', |
199 | 108 | ], |
200 | 109 | ], |
201 | | - 'required' => [ 'name' ], |
| 110 | + 'required' => [ 'location' ], // We only require the location |
202 | 111 | ], |
203 | 112 | 'callable' => function ( $params ) { |
204 | | - return 'Hello, ' . $params['name'] . '!'; |
205 | | - }, |
206 | | - ] |
207 | | - ); |
| 113 | + // Default user ID is 0 |
| 114 | + $user_id = 0; |
| 115 | + |
| 116 | + // Get the location from the parameters (already supplied in the prompt) |
| 117 | + $location_input = strtolower( trim( $params['location'] ) ); |
| 118 | + |
| 119 | + // Manually include the WP_Community_Events class if it's not loaded |
| 120 | + if ( ! class_exists( 'WP_Community_Events' ) ) { |
| 121 | + require_once ABSPATH . 'wp-admin/includes/class-wp-community-events.php'; |
| 122 | + } |
| 123 | + |
| 124 | + // Determine location for the WP_Community_Events class |
| 125 | + $location = null; |
| 126 | + if ( $location_input !== 'near me' ) { |
| 127 | + // Provide city name (WP will resolve coordinates) |
| 128 | + $location = [ |
| 129 | + 'description' => $location_input, |
| 130 | + ]; |
| 131 | + } |
208 | 132 |
|
209 | | - $server->register_tool( |
210 | | - [ |
211 | | - 'name' => 'generate_image', |
212 | | - 'description' => 'Generates an image.', |
213 | | - 'inputSchema' => [ |
214 | | - 'type' => 'object', |
215 | | - 'properties' => [ |
216 | | - 'prompt' => [ |
217 | | - 'type' => 'string', |
218 | | - 'description' => 'The prompt for generating the image.', |
219 | | - ], |
220 | | - ], |
221 | | - 'required' => [ 'prompt' ], |
222 | | - ], |
223 | | - 'callable' => function ( $params ) use ( $client ) { |
224 | | - return $client->get_image_from_ai_service( $params['prompt'] ); |
225 | | - }, |
226 | | - ] |
227 | | - ); |
| 133 | + // Instantiate WP_Community_Events with user ID (0) and optional location |
| 134 | + $events_instance = new WP_Community_Events( $user_id, $location ); |
228 | 135 |
|
229 | | - $server->register_tool( |
230 | | - [ |
231 | | - 'name' => 'fetch_wp_community_events', |
232 | | - 'description' => 'Fetches upcoming WordPress community events near a specified city or the user\'s current location. If no events are found in the exact location, nearby events within a specific radius will be considered.', |
233 | | - 'inputSchema' => [ |
234 | | - 'type' => 'object', |
235 | | - 'properties' => [ |
236 | | - 'location' => [ |
237 | | - 'type' => 'string', |
238 | | - 'description' => 'City name or "near me" for auto-detected location. If no events are found in the exact location, the tool will also consider nearby events within a specified radius (default: 100 km).', |
239 | | - ], |
240 | | - ], |
241 | | - 'required' => [ 'location' ], // We only require the location |
242 | | - ], |
243 | | - 'callable' => function ( $params ) { |
244 | | - // Default user ID is 0 |
245 | | - $user_id = 0; |
246 | | - |
247 | | - // Get the location from the parameters (already supplied in the prompt) |
248 | | - $location_input = strtolower( trim( $params['location'] ) ); |
249 | | - |
250 | | - // Manually include the WP_Community_Events class if it's not loaded |
251 | | - if ( ! class_exists( 'WP_Community_Events' ) ) { |
252 | | - require_once ABSPATH . 'wp-admin/includes/class-wp-community-events.php'; |
253 | | - } |
254 | | - |
255 | | - // Determine location for the WP_Community_Events class |
256 | | - $location = null; |
257 | | - if ( $location_input !== 'near me' ) { |
258 | | - // Provide city name (WP will resolve coordinates) |
259 | | - $location = [ |
260 | | - 'description' => $location_input, |
261 | | - ]; |
262 | | - } |
263 | | - |
264 | | - // Instantiate WP_Community_Events with user ID (0) and optional location |
265 | | - $events_instance = new WP_Community_Events( $user_id, $location ); |
266 | | - |
267 | | - // Get events from WP_Community_Events |
268 | | - $events = $events_instance->get_events($location_input); |
269 | | - |
270 | | - // Check for WP_Error |
271 | | - if ( is_wp_error( $events ) ) { |
272 | | - return [ 'error' => $events->get_error_message() ]; |
273 | | - } |
| 136 | + // Get events from WP_Community_Events |
| 137 | + $events = $events_instance->get_events( $location_input ); |
| 138 | + |
| 139 | + // Check for WP_Error |
| 140 | + if ( is_wp_error( $events ) ) { |
| 141 | + return [ 'error' => $events->get_error_message() ]; |
| 142 | + } |
274 | 143 |
|
275 | 144 | // If no events found |
276 | | - if ( empty( $events['events'] ) ) { |
277 | | - return [ 'message' => 'No events found near ' . ( $location_input === 'near me' ? 'your location' : $location_input ) ]; |
278 | | - } |
| 145 | + if ( empty( $events['events'] ) ) { |
| 146 | + return [ 'message' => 'No events found near ' . ( $location_input === 'near me' ? 'your location' : $location_input ) ]; |
| 147 | + } |
279 | 148 |
|
280 | 149 | // Format and return the events correctly |
281 | | - $formatted_events = array_map( function ( $event ) { |
282 | | - // Log event details to ensure properties are accessible |
283 | | - error_log( 'Event details: ' . print_r( $event, true ) ); |
| 150 | + $formatted_events = array_map( |
| 151 | + function ( $event ) { |
| 152 | + // Log event details to ensure properties are accessible |
| 153 | + error_log( 'Event details: ' . print_r( $event, true ) ); |
284 | 154 |
|
285 | | - // Initialize a formatted event string |
286 | | - $formatted_event = ''; |
| 155 | + // Initialize a formatted event string |
| 156 | + $formatted_event = ''; |
287 | 157 |
|
288 | | - // Format event title |
289 | | - if ( isset( $event['title'] ) ) { |
| 158 | + // Format event title |
| 159 | + if ( isset( $event['title'] ) ) { |
290 | 160 | $formatted_event .= $event['title'] . "\n"; |
291 | | - } |
| 161 | + } |
292 | 162 |
|
293 | | - // Format the date nicely |
294 | | - $formatted_event .= ' - Date: ' . ( isset( $event['date'] ) ? date( 'F j, Y g:i A', strtotime( $event['date'] ) ) : 'No date available' ) . "\n"; |
| 163 | + // Format the date nicely |
| 164 | + $formatted_event .= ' - Date: ' . ( isset( $event['date'] ) ? date( 'F j, Y g:i A', strtotime( $event['date'] ) ) : 'No date available' ) . "\n"; |
295 | 165 |
|
296 | | - // Format the location |
297 | | - if ( isset( $event['location']['location'] ) ) { |
298 | | - $formatted_event .= ' - Location: ' . $event['location']['location'] . "\n"; |
299 | | - } |
| 166 | + // Format the location |
| 167 | + if ( isset( $event['location']['location'] ) ) { |
| 168 | + $formatted_event .= ' - Location: ' . $event['location']['location'] . "\n"; |
| 169 | + } |
300 | 170 |
|
301 | | - // Format the event URL |
302 | | - $formatted_event .= isset( $event['url'] ) ? ' - URL: ' . $event['url'] . "\n" : ''; |
| 171 | + // Format the event URL |
| 172 | + $formatted_event .= isset( $event['url'] ) ? ' - URL: ' . $event['url'] . "\n" : ''; |
303 | 173 |
|
304 | | - return $formatted_event; |
305 | | - }, $events['events'] ); |
| 174 | + return $formatted_event; |
| 175 | + }, |
| 176 | + $events['events'] |
| 177 | + ); |
306 | 178 |
|
307 | 179 | // Combine the formatted events into a single string |
308 | | - $formatted_events_output = implode("\n", $formatted_events); |
| 180 | + $formatted_events_output = implode( "\n", $formatted_events ); |
309 | 181 |
|
310 | 182 | // Return the formatted events string |
311 | 183 | return [ |
312 | | - 'message' => "OK. I found " . count($formatted_events) . " WordPress events near " . ( $location_input === 'near me' ? 'your location' : $location_input ) . ":\n\n" . $formatted_events_output |
| 184 | + 'message' => 'OK. I found ' . count( $formatted_events ) . ' WordPress events near ' . ( $location_input === 'near me' ? 'your location' : $location_input ) . ":\n\n" . $formatted_events_output, |
313 | 185 | ]; |
314 | | - }, |
| 186 | + }, |
315 | 187 | ] |
316 | 188 | ); |
317 | 189 | } |
318 | 190 |
|
319 | 191 | // Register resources for AI access |
320 | | - private function register_resources($server) { |
| 192 | + private function register_resources( $server ) { |
321 | 193 | // Register Users resource |
322 | | - $server->register_resource([ |
| 194 | + $server->register_resource( |
| 195 | + [ |
323 | 196 | 'name' => 'users', |
324 | 197 | 'uri' => 'data://users', |
325 | 198 | 'description' => 'List of users', |
326 | 199 | 'mimeType' => 'application/json', |
327 | 200 | 'dataKey' => 'users', // Data will be fetched from 'users' |
328 | | - ]); |
| 201 | + ] |
| 202 | + ); |
329 | 203 |
|
330 | 204 | // Register Product Catalog resource |
331 | | - $server->register_resource([ |
| 205 | + $server->register_resource( |
| 206 | + [ |
332 | 207 | 'name' => 'product_catalog', |
333 | 208 | 'uri' => 'file://./products.json', |
334 | 209 | 'description' => 'Product catalog', |
335 | 210 | 'mimeType' => 'application/json', |
336 | 211 | 'filePath' => './products.json', // Data will be fetched from products.json |
337 | | - ]); |
| 212 | + ] |
| 213 | + ); |
338 | 214 | } |
339 | 215 | } |
0 commit comments