diff --git a/includes/Core/McpAdapter.php b/includes/Core/McpAdapter.php index e181fda..30c28cf 100644 --- a/includes/Core/McpAdapter.php +++ b/includes/Core/McpAdapter.php @@ -2,7 +2,7 @@ /** * WordPress MCP Registry - Main class for managing multiple MCP servers. * - * @package McpAdapter + * @package WP\MCP\Core */ declare( strict_types=1 ); @@ -17,34 +17,13 @@ /** * WordPress MCP Registry - Main class for managing multiple MCP servers. */ -class McpAdapter { +final class McpAdapter { /** * Registry instance * - * @var \WP\MCP\Core\McpAdapter|null + * @var \WP\MCP\Core\McpAdapter */ - private static ?self $instance = null; - - /** - * The initialized flag. - * - * @var bool - */ - private static bool $initialized = false; - - /** - * Flag to track if initialization failed due to missing dependencies. - * - * @var bool - */ - private static bool $initialization_failed = false; - - /** - * Stores the reason for initialization failure. - * - * @var string[] - */ - private static array $initialization_errors = array(); + private static self $instance; /** * Registered servers @@ -54,137 +33,42 @@ class McpAdapter { private array $servers = array(); /** - * The has triggered init flag. + * Initialize the registry * - * @var bool - */ - private bool $has_triggered_init = false; - - /** - * Constructor - */ - private function __construct() { - if ( self::$initialized || self::$initialization_failed ) { - return; - } - - if ( ! $this->check_dependencies() ) { - self::$initialization_failed = true; - return; - } - add_action( 'rest_api_init', array( $this, 'mcp_adapter_init' ), 20000 ); - self::$initialized = true; - } - - /** - * Check if all required dependencies are available. - * - * @return bool True if all dependencies are met, false otherwise. - */ - private function check_dependencies(): bool { - $errors = array(); - - // Check if we're in a WordPress environment. - if ( ! defined( 'ABSPATH' ) ) { - $errors[] = 'WordPress environment not detected (ABSPATH not defined)'; - } - - // Check if Abilities API is available. - if ( ! function_exists( 'wp_register_ability' ) ) { - $errors[] = 'Abilities API not available (wp_register_ability function not found)'; - } - - // Store errors for later retrieval. - self::$initialization_errors = $errors; - - // Log errors if any. - if ( ! empty( $errors ) ) { - return false; - } - - return true; - } - - /** - * Initialize the MCP adapter. + * @internal For use by instance initialization only. */ - public function mcp_adapter_init(): void { - // Bail early if initialization failed. - if ( self::$initialization_failed ) { - return; - } - - if ( $this->has_triggered_init ) { - return; - } - + public function init(): void { do_action( 'mcp_adapter_init', $this ); - $this->has_triggered_init = true; } /** * Get the registry instance * - * @return \WP\MCP\Core\McpAdapter|null Returns null if initialization failed due to missing dependencies. + * @return \WP\MCP\Core\McpAdapter */ - public static function instance(): ?self { - if ( null === self::$instance && ! self::$initialization_failed ) { + public static function instance(): self { + if ( ! isset( self::$instance ) ) { self::$instance = new self(); + + // Defer initialization until after the REST API. + add_action( 'rest_api_init', array( self::$instance, 'init' ), 20000 ); } return self::$instance; } - /** - * Check if the MCP adapter is available (dependencies are met). - * - * @return bool True if the adapter is available, false otherwise. - */ - public static function is_available(): bool { - return ! self::$initialization_failed; - } - - /** - * Get the initialization errors if any. - * - * @return string[] Array of error messages. - */ - public static function get_initialization_errors(): array { - return self::$initialization_errors; - } - - /** - * Get detailed dependency status for troubleshooting. - * - * @return array Array with dependency status information. - */ - public static function get_dependency_status(): array { - return array( - 'is_available' => self::is_available(), - 'wordpress_detected' => defined( 'ABSPATH' ), - 'abilities_api_available' => function_exists( 'wp_register_ability' ), - 'initialization_errors' => self::$initialization_errors, - 'debug_info' => array( - 'php_version' => PHP_VERSION, - 'wordpress_version' => function_exists( 'get_bloginfo' ) ? get_bloginfo( 'version' ) : 'Unknown', - 'wp_debug' => defined( 'WP_DEBUG' ) ? WP_DEBUG : false, - 'wp_debug_log' => defined( 'WP_DEBUG_LOG' ) ? WP_DEBUG_LOG : false, - ), - ); - } - /** * Create and register a new MCP server. * - * @param string $server_id Unique identifier for the server. + * @param string $server_id Unique identifier for the server. * @param string $server_route_namespace Server route namespace. - * @param string $server_route Server route. - * @param string $server_name Server name. - * @param string $server_description Server description. - * @param string $server_version Server version. - * @param array $mcp_transports Array of classes that extend the BaseTransport. - * @param string|null $error_handler The error handler class name. If null, NullMcpErrorHandler will be used. - * @param string|null $observability_handler The observability handler class name. If null, NullMcpObservabilityHandler will be used. + * @param string $server_route Server route. + * @param string $server_name Server name. + * @param string $server_description Server description. + * @param string $server_version Server version. + * @param array $mcp_transports Array of classes that extend the BaseTransport. + * @param ?class-string<\WP\MCP\Infrastructure\ErrorHandling\Contracts\McpErrorHandlerInterface> $error_handler The error handler class name. If null, NullMcpErrorHandler will be used. + * @param ?class-string<\WP\MCP\Infrastructure\Observability\Contracts\McpObservabilityHandlerInterface> $observability_handler The observability handler class name. If null, NullMcpObservabilityHandler will be used. * @param array $tools Ability names to register as tools. * @param array $resources Resources to register. * @param array $prompts Prompts to register. @@ -224,6 +108,7 @@ public function create_server( string $server_id, string $server_route_namespace esc_html__( 'MCP Server creation must be done during mcp_adapter_init action.', 'mcp-adapter' ) ); } + if ( isset( $this->servers[ $server_id ] ) ) { throw new \Exception( // translators: %s: server ID. diff --git a/includes/Plugin.php b/includes/Plugin.php index 07c0b8c..18feb9c 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -20,9 +20,9 @@ final class Plugin { /** * The one true plugin. * - * @var ?static + * @var static */ - private static $instance; + private static self $instance; /** * {@inheritDoc} @@ -47,9 +47,43 @@ public static function instance(): self { * Setup the plugin. */ private function setup(): void { + // Bail if dependencies are not met. + if ( ! $this->has_dependencies() ) { + return; + } + McpAdapter::instance(); } + /** + * Check if all required dependencies are available. + * + * Will log an admin notice if dependencies are missing. + * + * @return bool True if all dependencies are met, false otherwise. + */ + private function has_dependencies(): bool { + // Check if Abilities API is available. + if ( ! function_exists( 'wp_register_ability' ) ) { + add_action( + 'admin_notices', + static function () { + wp_admin_notice( + __( 'Abilities API not available (wp_register_ability function not found)', 'mcp-adapter' ), + array( + 'type' => 'error', + 'dismiss' => false, + ), + ); + } + ); + + return false; + } + + return true; + } + /** * Prevent the class from being cloned. */