Skip to main content
Glama
HandleToolsCall.php5.9 kB
<?php //phpcs:ignore declare(strict_types=1); namespace Automattic\WordpressMcp\Utils; use Automattic\WordpressMcp\Core\WpMcp; use Automattic\WordpressMcp\Core\McpErrorHandler; use Exception; use WP_REST_Request; /** * Handle Tools Call message. */ class HandleToolsCall { /** * Handle tool call request. * * @param array $message The message. * * @return array */ public static function run( array $message ): array { $tool_name = $message['params']['name'] ?? $message['name'] ?? ''; $args = $message['params']['arguments'] ?? $message['arguments'] ?? array(); // Get the WordPress MCP instance. $wpmcp = WpMcp::instance(); // Get the tool callbacks. $tools_callbacks = $wpmcp->get_tools_callbacks(); // Check if the tool exists. if ( ! isset( $tools_callbacks[ $tool_name ] ) ) { return array( 'error' => McpErrorHandler::tool_not_found( 0, $tool_name ), ); } // Get the tool callback. $tool_callback = $tools_callbacks[ $tool_name ]; // Handle REST API alias if present. if ( isset( $tool_callback['rest_alias'] ) ) { try { $rest_alias = $tool_callback['rest_alias']; $route = $rest_alias['route']; $method = $rest_alias['method']; // Substitute route parameters with actual values from arguments. $route = self::substitute_route_params( $route, $args ); $request = new \WP_REST_Request( $method, $route ); // Execute preCallback if it exists to transform the arguments. $processed_params = array( 'args' => $args, ); if ( isset( $rest_alias['preCallback'] ) && is_callable( $rest_alias['preCallback'] ) ) { try { $processed_params = call_user_func( $rest_alias['preCallback'], $args ); } catch ( \Exception $e ) { return array( 'error' => McpErrorHandler::create_error_response( 0, McpErrorHandler::INTERNAL_ERROR, 'Error in preCallback', $e->getMessage() ), ); } } // Set any custom headers if they were set by the preCallback. if ( isset( $processed_params['headers'] ) && is_array( $processed_params['headers'] ) ) { foreach ( $processed_params['headers'] as $header => $value ) { $request->set_header( $header, $value ); } } // Set the raw body if it was set by the preCallback. if ( isset( $processed_params['body'] ) ) { $request->set_body( $processed_params['body'] ); } // Use the processed args, falling back to original args if not set. $final_args = $processed_params['args'] ?? $args; // Set the arguments as query parameters or body parameters based on method. if ( in_array( $method, array( 'GET', 'DELETE' ), true ) ) { // For GET and DELETE, use query parameters. foreach ( $final_args as $key => $value ) { $request->set_query_params( array_merge( $request->get_query_params(), array( $key => $value ) ) ); } } elseif ( ! isset( $processed_params['body'] ) ) { // For POST, PUT, PATCH, use body parameters. // Only set params if we don't have a raw body from preCallback. foreach ( $final_args as $key => $value ) { $request->set_param( $key, $value ); } } $rest_response = rest_do_request( $request ); if ( $rest_response->is_error() ) { // Handle REST API error. return array( 'error' => McpErrorHandler::create_error_response( 0, McpErrorHandler::REST_API_ERROR, 'REST API error occurred', $rest_response->as_error()->get_error_message() ), ); } else { return $rest_response->get_data(); } } catch ( \Exception $e ) { McpErrorHandler::log_error( 'REST API tool execution failed', array( 'tool' => $tool_name, 'exception' => $e->getMessage(), ) ); return array( 'error' => McpErrorHandler::create_error_response( 0, McpErrorHandler::REST_API_ERROR, 'Error executing REST API', $e->getMessage() ), ); } } else { // Check permissions first. if ( isset( $tool_callback['permission_callback'] ) && is_callable( $tool_callback['permission_callback'] ) ) { $permission_result = call_user_func( $tool_callback['permission_callback'], $args ); if ( ! $permission_result ) { return array( 'error' => array( 'code' => 'rest_forbidden', 'message' => 'Permission denied', 'data' => array( 'status' => 403 ), ), ); } } // Execute the tool callback. try { $result = call_user_func( $tool_callback['callback'], $args ); return $result; } catch ( \Exception $e ) { McpErrorHandler::log_error( 'Tool execution failed', array( 'tool' => $tool_name, 'exception' => $e->getMessage(), ) ); return array( 'error' => McpErrorHandler::create_error_response( 0, McpErrorHandler::INTERNAL_ERROR, 'Error executing tool', $e->getMessage() ), ); } } } /** * Substitute route parameters with actual values from arguments. * * @param string $route The route pattern with named parameters. * @param array $args The arguments containing parameter values. * * @return string The route with parameters substituted. */ private static function substitute_route_params( string $route, array $args ): string { // Find all named capture groups in the route pattern. if ( preg_match_all( '/\(\?P<([^>]+)>[^)]+\)/', $route, $matches ) ) { $param_names = $matches[1]; // Replace each parameter with its value from args if available. foreach ( $param_names as $param_name ) { if ( isset( $args[ $param_name ] ) ) { $pattern = '/\(\?P<' . preg_quote( $param_name, '/' ) . '>[^)]+\)/'; $route = preg_replace( $pattern, (string) $args[ $param_name ], $route ); } } } return $route; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Automattic/wordpress-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server