Skip to main content
Glama
WpMcp.php11.8 kB
<?php //phpcs:ignore declare(strict_types=1); namespace Automattic\WordpressMcp\Core; use Automattic\WordpressMcp\Tools\McpCustomPostTypesTools; use Automattic\WordpressMcp\Tools\McpPostsTools; use Automattic\WordpressMcp\Resources\McpGeneralSiteInfo; use Automattic\WordpressMcp\Tools\McpRestApiCrud; use Automattic\WordpressMcp\Tools\McpSiteInfo; use Automattic\WordpressMcp\Tools\McpUsersTools; use Automattic\WordpressMcp\Tools\McpWooOrders; use Automattic\WordpressMcp\Tools\McpWooProducts; use Automattic\WordpressMcp\Tools\McpPagesTools; use Automattic\WordpressMcp\Tools\McpSettingsTools; use Automattic\WordpressMcp\Tools\McpMediaTools; use Automattic\WordpressMcp\Prompts\McpGetSiteInfo as McpGetSiteInfoPrompt; use Automattic\WordpressMcp\Prompts\McpAnalyzeSales; use Automattic\WordpressMcp\Resources\McpPluginInfoResource; use Automattic\WordpressMcp\Resources\McpThemeInfoResource; use Automattic\WordpressMcp\Resources\McpUserInfoResource; use Automattic\WordpressMcp\Resources\McpSiteSettingsResource; use InvalidArgumentException; /** * WordPress MCP * * @package WpMcp */ class WpMcp { /** * The tools. * * @var array */ private array $tools = array(); /** * The tool callbacks. * * @var array */ private array $tools_callbacks = array(); /** * The resources. * * @var array */ private array $resources = array(); /** * The resource callbacks. * * @var array */ private array $resource_callbacks = array(); /** * The prompts. * * @var array */ private array $prompts = array(); /** * The prompt message. * * @var array */ private array $prompts_messages = array(); /** * The namespace. * * @var string */ private string $namespace = 'wpmcp/v1'; /** * The instance. * * @var ?WpMcp */ private static ?WpMcp $instance = null; /** * The initialized flag. * * @var bool */ private static bool $initialized = false; /** * The MCP settings. * * @var array */ private array $mcp_settings = array(); /** * The has triggered init flag. * * @var bool */ private bool $has_triggered_init = false; /** * The all tools. * * @var array */ private array $all_tools = array(); /** * The tool states option name. * * @var string */ private const TOOL_STATES_OPTION = 'wordpress_mcp_tool_states'; /** * Constructor. */ public function __construct() { // Only initialize if not already initialized. if ( ! self::$initialized ) { $this->mcp_settings = get_option( 'wordpress_mcp_settings', array() ); // Only initialize components if MCP is enabled. if ( $this->is_mcp_enabled() ) { $this->init_default_resources(); $this->init_default_tools(); $this->init_default_prompts(); $this->init_features_as_tools(); // Register the MCP assets late in the rest_api_init hook (required for rest_alias tools). // This is to ensure that the rest_api_init hook is not called too early. // We use a priority of 20000 to ensure that the rest_api_init hook is called after the rest_api_init hook of the FeaturesAPI plugin. add_action( 'rest_api_init', array( $this, 'wordpress_mcp_init' ), 20000 ); self::$initialized = true; } } } /** * Initialize the plugin. */ public function wordpress_mcp_init(): void { // Only trigger the wordpress_mcp_init action if MCP is enabled and hasn't been triggered before. if ( $this->is_mcp_enabled() && ! $this->has_triggered_init ) { do_action( 'wordpress_mcp_init', $this ); $this->has_triggered_init = true; } } /** * Check if MCP is enabled in settings. * * @return bool Whether MCP is enabled. */ private function is_mcp_enabled(): bool { return isset( $this->mcp_settings['enabled'] ) && $this->mcp_settings['enabled']; } /** * Initialize the default resources. */ private function init_default_resources(): void { new McpGeneralSiteInfo(); new McpPluginInfoResource(); new McpThemeInfoResource(); new McpUserInfoResource(); new McpSiteSettingsResource(); } /** * Initialize the default tools. */ private function init_default_tools(): void { new McpPostsTools(); new McpSiteInfo(); new McpUsersTools(); new McpWooProducts(); new McpWooOrders(); new McpPagesTools(); new McpSettingsTools(); new McpMediaTools(); new McpCustomPostTypesTools(); new McpRestApiCrud(); } /** * Initialize the default prompts. */ private function init_default_prompts(): void { new McpGetSiteInfoPrompt(); new McpAnalyzeSales(); } /** * Initialize the features as tools. */ private function init_features_as_tools(): void { $features_enabled = isset( $this->mcp_settings['features_adapter_enabled'] ) && $this->mcp_settings['features_adapter_enabled']; if ( $features_enabled ) { new WpFeaturesAdapter(); } } /** * Get the instance. * * @return WpMcp */ public static function instance(): WpMcp { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Check if a tool type is enabled. * * @param string $type The tool type to check. * @return bool Whether the tool type is enabled. */ private function is_tool_type_enabled( string $type ): bool { // Read operations and action operations are always allowed if MCP is enabled. if ( 'read' === $type || 'action' === $type ) { return true; } // Check specific tool type settings. $type_settings_map = array( 'create' => 'enable_create_tools', 'update' => 'enable_update_tools', 'delete' => 'enable_delete_tools', ); // Check if the type exists in our mapping and is enabled. if ( isset( $type_settings_map[ $type ] ) ) { return isset( $this->mcp_settings[ $type_settings_map[ $type ] ] ) && $this->mcp_settings[ $type_settings_map[ $type ] ]; } return false; } /** * Register a tool. * * @param array $args The arguments. * @throws InvalidArgumentException If the tool name is not unique or if the tool type is disabled. */ public function register_tool( array $args ): void { $is_tool_type_enabled = $this->is_tool_type_enabled( $args['type'] ); $is_tool_enabled = $this->is_tool_enabled( $args['name'] ); // Check if REST API CRUD tools are enabled and this tool should be disabled. $is_rest_api_crud_enabled = ! empty( $this->mcp_settings['enable_rest_api_crud_tools'] ); $has_rest_alias = ! empty( $args['rest_alias'] ); $has_disabled_flag = ! empty( $args['disabled_by_rest_crud'] ); $is_disabled_by_rest_crud = $is_rest_api_crud_enabled && ( $has_rest_alias || $has_disabled_flag ); $args['tool_type_enabled'] = $is_tool_type_enabled; $args['tool_enabled'] = $is_tool_enabled; $args['disabled_by_rest_crud'] = $is_disabled_by_rest_crud; $this->all_tools[] = $args; // Skip actual registration if disabled by REST CRUD setting. if ( $is_disabled_by_rest_crud ) { return; } // Check if the tool is enabled. if ( ! $is_tool_enabled || ! $is_tool_type_enabled ) { return; // Skip registration if tool is disabled. } // The name should be unique. if ( in_array( $args['name'], array_column( $this->tools, 'name' ), true ) ) { $this->tools_callbacks[ $args['name'] ] = array(); // Search the tools array for the tool with the same name. foreach ( $this->tools as $tool ) { if ( $tool['name'] === $args['name'] ) { unset( $this->tools[ $tool['name'] ] ); break; } } } $this->tools_callbacks[ $args['name'] ] = array( 'callback' => $args['callback'], 'permission_callback' => $args['permission_callback'], 'rest_alias' => $args['rest_alias'] ?? null, ); unset( $args['callback'] ); unset( $args['permission_callback'] ); unset( $args['rest_alias'] ); unset( $args['disabled_by_rest_crud'] ); unset( $args['tool_type_enabled'] ); unset( $args['tool_enabled'] ); $this->tools[] = $args; } /** * Register a resource. * * @param array $args The arguments. * @throws InvalidArgumentException If the resource name or URI is not unique. */ public function register_resource( array $args ): void { // the name and uri should be unique. if ( in_array( $args['name'], array_column( $this->resources, 'name' ), true ) || in_array( $args['uri'], array_column( $this->resources, 'uri' ), true ) ) { $this->resources[ $args['uri'] ] = array(); } $this->resources[ $args['uri'] ] = $args; } /** * Register a resource callback. * * @param string $uri The uri. * @param callable $callback The callback. */ public function register_resource_callback( string $uri, callable $callback ): void { $this->resource_callbacks[ $uri ] = $callback; } /** * Register a prompt. * * @param array $prompt The prompt instance. * @param array $messages The messages for the prompt. * @throws InvalidArgumentException If the prompt name is not unique. */ public function register_prompt( array $prompt, array $messages ): void { $name = $prompt['name']; // Check if the prompt name is unique. if ( isset( $this->prompts[ $name ] ) ) { $this->prompts[ $name ] = array(); $this->prompts_messages[ $name ] = array(); } $this->prompts[ $name ] = $prompt; $this->prompts_messages[ $name ] = $messages; } /** * Get the tools. * * @return array */ public function get_tools(): array { return $this->tools; } /** * Get all tools with enabled state. * * @return array */ public function get_all_tools(): array { $tool_states = get_option( self::TOOL_STATES_OPTION, array() ); $tools = $this->all_tools; // Add enabled state to each tool. foreach ( $tools as &$tool ) { $tool['enabled'] = ! isset( $tool_states[ $tool['name'] ] ) || $tool_states[ $tool['name'] ]; } return $tools; } /** * Get the tool callbacks. * * @return array */ public function get_tools_callbacks(): array { return $this->tools_callbacks; } /** * Get the resources. * * @return array */ public function get_resources(): array { return $this->resources; } /** * Get the resource callbacks. * * @return array */ public function get_resource_callbacks(): array { return $this->resource_callbacks; } /** * Get the prompts. * * @return array */ public function get_prompts(): array { return $this->prompts; } /** * Get a prompt by name. * * @param string $name The prompt name. * @return array|null */ public function get_prompt_by_name( string $name ): ?array { return $this->prompts[ $name ] ?? null; } /** * Get the prompt messages. * * @param string $name The prompt name. * @return array|null */ public function get_prompt_messages( string $name ): ?array { return $this->prompts_messages[ $name ] ?? null; } /** * Get the namespace. * * @return string */ public function get_namespace(): string { return $this->namespace; } /** * Get a tool by name. * * @param string $name The tool name. * @return array|null */ public function get_tool_by_name( string $name ): ?array { foreach ( $this->tools as $tool ) { if ( $tool['name'] === $name ) { return $tool; } } return null; } /** * Get the MCP settings. * * @return array */ public function get_mcp_settings(): array { return $this->mcp_settings; } /** * Check if a tool is enabled. * * @param string $tool_name The name of the tool to check. * @return bool Whether the tool is enabled. */ public function is_tool_enabled( string $tool_name ): bool { $tool_states = get_option( self::TOOL_STATES_OPTION, array() ); return ! isset( $tool_states[ $tool_name ] ) || $tool_states[ $tool_name ]; } }

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