| 1 |
<?php |
| 2 |
/** |
| 3 |
* MCP Server registration. |
| 4 |
* |
| 5 |
* Registers the SureCookie MCP server with the WordPress MCP Adapter, |
| 6 |
* exposing surecookie/* abilities at /wp-json/surecookie/v1/mcp. |
| 7 |
* |
| 8 |
* @link https://developer.wordpress.org/news/2026/02/from-abilities-to-ai-agents-introducing-the-wordpress-mcp-adapter/ |
| 9 |
* @package SureCookie |
| 10 |
* @subpackage SureCookie/Inc/Modules/Mcp |
| 11 |
* @since 1.1.0 |
| 12 |
*/ |
| 13 |
|
| 14 |
namespace SureCookie\Inc\Modules\Mcp; |
| 15 |
|
| 16 |
use SureCookie\Inc\Functions\Settings; |
| 17 |
use SureCookie\Inc\Traits\GetInstance; |
| 18 |
use SureCookie\Inc\Utils\Logger; |
| 19 |
|
| 20 |
if ( ! defined( 'ABSPATH' ) ) { |
| 21 |
exit; // Exit if accessed directly. |
| 22 |
} |
| 23 |
|
| 24 |
/** |
| 25 |
* Class Server |
| 26 |
* |
| 27 |
* Creates the plugin-scoped MCP server on `mcp_adapter_init`, whitelisting |
| 28 |
* only `surecookie/` abilities; the adapter's default server covers "Global". |
| 29 |
* |
| 30 |
* @since 1.1.0 |
| 31 |
*/ |
| 32 |
class Server { |
| 33 |
use GetInstance; |
| 34 |
|
| 35 |
/** |
| 36 |
* Constructor. The enable check runs inside the callback at hook-fire time. |
| 37 |
* |
| 38 |
* @since 1.1.0 |
| 39 |
*/ |
| 40 |
private function __construct() { |
| 41 |
add_action( 'mcp_adapter_init', [ $this, 'register_mcp_server' ] ); |
| 42 |
} |
| 43 |
|
| 44 |
/** |
| 45 |
* Whether the MCP server is enabled via the admin setting. |
| 46 |
* |
| 47 |
* @return bool |
| 48 |
* @since 1.1.0 |
| 49 |
*/ |
| 50 |
public static function is_enabled(): bool { |
| 51 |
/** |
| 52 |
* Filters whether the SureCookie MCP server should be created. |
| 53 |
* |
| 54 |
* @param bool $enabled Defaults to the `enable_mcp` admin setting. |
| 55 |
* @since 1.1.0 |
| 56 |
*/ |
| 57 |
return (bool) apply_filters( 'surecookie_mcp_server_enabled', (bool) Settings::get( 'enable_mcp' ) ); |
| 58 |
} |
| 59 |
|
| 60 |
/** |
| 61 |
* Whether the MCP Adapter plugin (current or legacy build) is available. |
| 62 |
* |
| 63 |
* @return bool |
| 64 |
* @since 1.1.0 |
| 65 |
*/ |
| 66 |
public static function is_adapter_available(): bool { |
| 67 |
return class_exists( 'WP\\MCP\\Core\\McpAdapter' ) || class_exists( 'WP\\MCP\\Plugin' ); |
| 68 |
} |
| 69 |
|
| 70 |
/** |
| 71 |
* Register the SureCookie MCP server on `mcp_adapter_init`. |
| 72 |
* |
| 73 |
* @param object $adapter MCP adapter instance provided by the adapter plugin. |
| 74 |
* @return void |
| 75 |
* @since 1.1.0 |
| 76 |
*/ |
| 77 |
public function register_mcp_server( $adapter = null ): void { |
| 78 |
if ( ! self::is_enabled() ) { |
| 79 |
return; |
| 80 |
} |
| 81 |
|
| 82 |
if ( ! is_object( $adapter ) || ! method_exists( $adapter, 'create_server' ) ) { |
| 83 |
return; |
| 84 |
} |
| 85 |
|
| 86 |
// Created even with empty $tools (SureRank parity) so failures surface |
| 87 |
// as an empty tools list instead of a silent 404. |
| 88 |
$tools = $this->get_surecookie_ability_names(); |
| 89 |
|
| 90 |
// Newer adapter builds ship HttpTransport; older ones only RestTransport. |
| 91 |
$transport_class = class_exists( '\\WP\\MCP\\Transport\\HttpTransport' ) |
| 92 |
? '\\WP\\MCP\\Transport\\HttpTransport' |
| 93 |
: '\\WP\\MCP\\Transport\\Http\\RestTransport'; |
| 94 |
|
| 95 |
try { |
| 96 |
$adapter->create_server( |
| 97 |
'surecookie', |
| 98 |
'surecookie/v1', |
| 99 |
'mcp', |
| 100 |
__( 'SureCookie MCP Server', 'surecookie' ), |
| 101 |
__( 'SureCookie MCP Server for cookie consent settings, consent logs, cookie management, and site scanning workflows.', 'surecookie' ), |
| 102 |
SURECOOKIE_VERSION, |
| 103 |
[ $transport_class ], |
| 104 |
'\\WP\\MCP\\Infrastructure\\ErrorHandling\\ErrorLogMcpErrorHandler', |
| 105 |
'\\WP\\MCP\\Infrastructure\\Observability\\NullMcpObservabilityHandler', |
| 106 |
$tools, |
| 107 |
[], |
| 108 |
[], |
| 109 |
// Transport access requires the same capability that gates |
| 110 |
// ability execution; older adapters ignore this 13th argument. |
| 111 |
static function (): bool { |
| 112 |
return current_user_can( SURECOOKIE_CAPABILITY ); |
| 113 |
} |
| 114 |
); |
| 115 |
} catch ( \Throwable $e ) { |
| 116 |
// A transport/adapter version mismatch must not fatal the REST API. |
| 117 |
Logger::get_instance()->log( 'SureCookie MCP server registration failed: ' . $e->getMessage(), 'warning' ); |
| 118 |
} |
| 119 |
} |
| 120 |
|
| 121 |
/** |
| 122 |
* Collect the names of all registered surecookie/* abilities. |
| 123 |
* |
| 124 |
* @return array<int, string> |
| 125 |
* @since 1.1.0 |
| 126 |
*/ |
| 127 |
private function get_surecookie_ability_names(): array { |
| 128 |
$abilities = function_exists( 'wp_get_abilities' ) ? wp_get_abilities() : []; |
| 129 |
$tools = []; |
| 130 |
|
| 131 |
foreach ( $abilities as $ability ) { |
| 132 |
if ( ! is_object( $ability ) || ! method_exists( $ability, 'get_name' ) ) { |
| 133 |
continue; |
| 134 |
} |
| 135 |
|
| 136 |
$name = $ability->get_name(); |
| 137 |
|
| 138 |
if ( is_string( $name ) && strpos( $name, 'surecookie/' ) === 0 ) { |
| 139 |
$tools[] = $name; |
| 140 |
} |
| 141 |
} |
| 142 |
|
| 143 |
return $tools; |
| 144 |
} |
| 145 |
} |
| 146 |
|