lidation immediately after server creation. remove_filter( 'mcp_validation_enabled', array( __CLASS__, 'disable_mcp_validation' ), 999 ); } } /** * Get WooCommerce abilities for MCP server. * * Filters abilities to include only those explicitly exposed to the deprecated * WooCommerce MCP endpoint, with a filter to override inclusion decisions. * * @return array Array of ability IDs for MCP server. */ private function get_woocommerce_mcp_abilities(): array { // Get all abilities from the registry. $abilities_registry = wc_get_container()->get( AbilitiesRegistry::class ); $all_abilities_ids = $abilities_registry->get_abilities_ids(); // Filter abilities based on deprecated endpoint exposure metadata and custom filter. $mcp_abilities = array_filter( $all_abilities_ids, static function ( $ability_id ) { $include = self::should_include_ability_by_default( $ability_id ); // Allow filter to override inclusion decision. /** * Filter to override MCP ability inclusion decision. * * @since 10.3.0 * * @param bool $include Whether to include the ability by default. True when the ability has * `expose_in_deprecated_woocommerce_mcp => true` in its metadata * (set automatically on REST-derived abilities by RestAbilityFactory). * Migration note: this value no longer represents whether the ability uses * the `woocommerce/` namespace. * Return unchanged to keep the default, or return true/false to override. * @param string $ability_id The ability ID. */ return apply_filters( 'woocommerce_mcp_include_ability', $include, $ability_id ); } ); // Re-index array. return array_values( $mcp_abilities ); } /** * Check if an ability should be included in the deprecated WooCommerce MCP endpoint. * * REST-derived abilities can opt in to the deprecated WooCommerce MCP endpoint. * Require explicit metadata so semantic/domain abilities can use WooCommerce * namespaces without expanding the deprecated MCP tool list. * This intentionally allows abilities from any namespace to opt in to the * deprecated endpoint while keeping namespace and transport exposure separate. * * @param string $ability_id Ability ID. * @return bool Whether to include the ability by default. */ private static function should_include_ability_by_default( string $ability_id ): bool { // Keep the pre-check to avoid triggering _doing_it_wrong() for stale or mocked registry IDs. if ( function_exists( 'wp_get_ability' ) && function_exists( 'wp_has_ability' ) && wp_has_ability( $ability_id ) ) { $ability = wp_get_ability( $ability_id ); if ( $ability ) { // Strict boolean required: truthy values like 1 or "true" are intentionally excluded. return true === $ability->get_meta_item( RestAbilityFactory::EXPOSE_IN_DEPRECATED_MCP_META_KEY, false ); } } return false; } /** * Temporarily disable MCP validation. * * Used as a callback for the mcp_validation_enabled filter to work around * validator bugs with union types. * * @return bool Always returns false to disable validation. */ public static function disable_mcp_validation(): bool { return false; } /** * Check if MCP adapter is initialized. * * @return bool Whether MCP adapter is initialized. */ public function is_initialized(): bool { return $this->initialized; } /** * Check if the current request is for the MCP endpoint. * * @return bool True if this is an MCP endpoint request. */ public static function is_mcp_request(): bool { // Check if this is a REST request. if ( ! wp_is_serving_rest_request() ) { return false; } // Get the request URI. $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; // Build the MCP endpoint path dynamically from constants. $mcp_endpoint = '/' . self::MCP_NAMESPACE . '/' . self::MCP_ROUTE; // Check if the request is for the MCP endpoint. return false !== strpos( $request_uri, $mcp_endpoint ); } }
Fatal error: Uncaught Automattic\WooCommerce\Internal\DependencyManagement\ContainerException: Attempt to get an instance of class 'Automattic\WooCommerce\Internal\MCP\MCPAdapterProvider', which doesn't exist. in /htdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php:105 Stack trace: #0 /htdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php(78): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get_core('Automattic\\WooC...', Array) #1 /htdocs/wp-content/plugins/woocommerce/src/Container.php(68): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get('Automattic\\WooC...') #2 /htdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(379): Automattic\WooCommerce\Container->get('Automattic\\WooC...') #3 /htdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(268): WooCommerce->init_hooks() #4 /htdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(169): WooCommerce->__construct() #5 /htdocs/wp-content/plugins/woocommerce/woocommerce.php(47): WooCommerce::instance() #6 /htdocs/wp-content/plugins/woocommerce/woocommerce.php(62): WC() #7 /htdocs/wp-settings.php(560): include_once('/htdocs/wp-cont...') #8 /htdocs/wp-config.php(98): require_once('/htdocs/wp-sett...') #9 /htdocs/wp-load.php(50): require_once('/htdocs/wp-conf...') #10 /htdocs/wp-blog-header.php(13): require_once('/htdocs/wp-load...') #11 /htdocs/index.php(17): require('/htdocs/wp-blog...') #12 {main} thrown in /htdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php on line 105