PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
← All changes | app/Modules/MCP/MCPInit.php +27 -70 2.4.0 → 2.5.0 View file →
@@ -7,22 +7,16 @@
7 7
8 8 defined('ABSPATH') || exit;
9 9
10 10 /**
11 - * Bootstrap for FluentBooking's Model Context Protocol integration.
11 + * Bootstrap for the MCP integration.
12 12 *
13 - * Wires the WordPress Abilities API (core 6.9+) to the WP MCP Adapter, which is
14 - * provided by FluentToolkit (which bundles it) or the standalone mcp-adapter
15 - * plugin — whichever is present. FluentBooking bundles nothing; it consumes
16 - * whatever is loaded, and surfaces an admin notice rather than failing silently
17 - * when neither is.
13 + * Wires the Abilities API (WP 6.9+) to the MCP Adapter, supplied by
14 + * FluentToolkit or the standalone mcp-adapter plugin. Shows an admin notice
15 + * when neither is loaded.
18 16 *
19 - * The whole surface is gated behind PermissionGate::isEnabled() (default off).
20 - * An operator turns it on in Settings and connects with an application password.
21 - * Even when on, the endpoint sits behind WP authentication, a FluentBooking
22 - * permission (transport gate), and per-ability permission checks.
23 - *
24 - * Called once from app/Hooks/actions.php.
17 + * Off by default (PermissionGate::isEnabled()). When on, the endpoint needs WP
18 + * auth, the transport permission gate and per-ability permission checks.
25 19 */
26 20 class MCPInit
27 21 {
28 22 const SERVER_ID = 'fluent-booking';
@@ -27,18 +21,10 @@
27 21 {
28 22 const SERVER_ID = 'fluent-booking';
29 23
30 24 /**
31 - * Bootstrap entry point.
32 - *
33 - * Toolkit discovery and the settings card register UNCONDITIONALLY: the
34 - * Toolkit needs to list FluentBooking on its MCP page while the feature is
35 - * still off, or the operator has no way to find the switch. Both are
36 - * add_filter calls that no-op unless something applies them, so the cost
37 - * when nothing does is nil.
38 - *
39 - * The server itself is instantiated only when enabled, so a site that never
40 - * turns MCP on pays nothing beyond one autoloaded option read.
25 + * Toolkit discovery and the settings entry always register, since they are
26 + * where the operator finds the switch. The server starts only when enabled.
41 27 */
42 28 public static function boot()
43 29 {
44 30 self::registerWithToolkit();
@@ -50,22 +36,19 @@
50 36 }
51 37
52 38 public function init()
53 39 {
54 - // Abilities API hooks — fire only on WP 6.9+ (or with the Abilities API
55 - // feature plugin active).
40 + // Fire only on WP 6.9+ or with the Abilities API plugin.
56 41 add_action('wp_abilities_api_categories_init', [$this, 'registerCategory']);
57 42 add_action('wp_abilities_api_init', [$this, 'registerAbilities']);
58 43
59 44 add_action('admin_init', [$this, 'registerPrivacyPolicyContent']);
60 45
61 - // Server registration — fires only when an adapter is loaded.
46 + // Fires only when an adapter is loaded.
62 47 add_action('mcp_adapter_init', [$this, 'registerCustomServer']);
63 48
64 - // Keep get-booking-context honest: drop its cache whenever something it
65 - // reports changes, so an operator's edit is visible to the agent on the
66 - // next call instead of up to CACHE_TTL later. Static callback so a site
67 - // can remove_action it.
49 + // Drop get-booking-context's cache when anything it reports changes.
50 + // Static callback so a site can remove_action it.
68 51 $invalidate = [ContextTools::class, 'invalidateCache'];
69 52
70 53 foreach ([
71 54 'fluent_booking/after_create_calendar',
@@ -78,9 +61,8 @@
78 61 ] as $hook) {
79 62 add_action($hook, $invalidate);
80 63 }
81 64
82 - // Warn the operator if they enabled MCP but no adapter is installed.
83 65 add_action('admin_notices', [$this, 'maybeShowAdapterNotice']);
84 66 }
85 67
86 68 public function registerCategory()
@@ -95,11 +77,10 @@
95 77 {
96 78 AbilitiesRegistrar::register();
97 79
98 80 /**
99 - * Fires after FluentBooking registers its core MCP abilities.
100 - * FluentBooking Pro hooks this to register its own abilities (payments)
101 - * under the same `fluent-booking/` namespace and on the same server.
81 + * Fires after FluentBooking registers its core MCP abilities. Pro
82 + * registers its own here, under the same namespace and server.
102 83 *
103 84 * @since 2.3.0
104 85 */
105 86 do_action('fluent_booking/mcp_loaded');
@@ -105,12 +86,10 @@
105 86 do_action('fluent_booking/mcp_loaded');
106 87 }
107 88
108 89 /**
109 - * Register the dedicated FluentBooking MCP server. The endpoint defaults to
110 - * /wp-json/fluent-booking/mcp — a sibling of the admin REST namespace
111 - * (fluent-booking/v2) but deliberately outside it, so it is not caught by
112 - * that policy stack.
90 + * Register the FluentBooking MCP server at /wp-json/fluent-booking/mcp,
91 + * outside fluent-booking/v2 so the admin policy stack doesn't apply.
113 92 *
114 93 * @param object $adapter the \WP\MCP\Core\McpAdapter instance
115 94 */
116 95 public function registerCustomServer($adapter)
@@ -122,10 +101,9 @@
122 101 $abilityNames = AbilitiesRegistrar::getToolNames();
123 102
124 103 /**
125 104 * Filters the ability names exposed by the FluentBooking MCP server.
126 - * Pro and extensions push their ability names here so they land on the
127 - * same server as the free ones.
105 + * Pro and extensions add theirs here to share the server.
128 106 *
129 107 * @since 2.3.0
130 108 *
131 109 * @param array $abilityNames fully-qualified ability names
@@ -132,11 +110,9 @@
132 110 */
133 111 $abilityNames = apply_filters('fluent_booking/mcp_ability_names', $abilityNames);
134 112 $abilityNames = array_values(array_unique(array_filter((array) $abilityNames)));
135 113
136 - // Prompts are a separate argument to create_server(). Listed as tools
137 - // they would show up in tools/list carrying a body of instructions —
138 - // both wrong and, at a few hundred tokens each, expensive.
114 + // Prompts go in their own argument, not in tools/list.
139 115 $promptNames = AbilitiesRegistrar::getPromptNames();
140 116
141 117 /**
142 118 * Filters the prompt ability names exposed by the server.
@@ -168,21 +144,14 @@
168 144 );
169 145 }
170 146
171 147 /**
172 - * Announce FluentBooking to FluentToolkit's MCP page.
173 - *
174 - * The Toolkit discovers products through `fluent_kit/mcp_products` and
175 - * toggles them through `fluent_kit/mcp_toggle_handlers`. Without these,
176 - * FluentBooking's server would be fully functional yet never appear in the
177 - * Toolkit's list, which reads to an operator as "not supported".
178 - *
179 - * Runs even while MCP is off so the card is reachable to switch on.
148 + * List FluentBooking on FluentToolkit's MCP page, even while MCP is off,
149 + * so the operator can switch it on there.
180 150 */
181 151 public static function registerWithToolkit()
182 152 {
183 - // Static callbacks rather than closures so a site can remove_filter
184 - // them — a closure registered here would be unreachable forever.
153 + // Static callbacks, not closures, so a site can remove_filter them.
185 154 add_filter('fluent_kit/mcp_products', [self::class, 'addToolkitProduct']);
186 155 add_filter('fluent_kit/mcp_toggle_handlers', [self::class, 'addToolkitToggleHandler']);
187 156 }
188 157
@@ -226,14 +195,10 @@
226 195 return $handlers;
227 196 }
228 197
229 198 /**
230 - * Add the MCP entry to FluentBooking → Settings.
231 - *
232 - * Registered even while the feature is off — it is the only place an
233 - * operator can turn it on, so hiding it when disabled would make the switch
234 - * unreachable. Priority 30 keeps it after the existing settings entries
235 - * rather than in the middle of them.
199 + * Add the MCP entry to Settings. Registered while off too, since it holds
200 + * the switch. Priority 30 puts it after the existing entries.
236 201 */
237 202 public static function registerSettingsMenu()
238 203 {
239 204 add_filter('fluent_booking/settings_menu_items', [self::class, 'addSettingsMenuItem'], 30);
@@ -263,18 +228,15 @@
263 228 return $items;
264 229 }
265 230
266 231 /**
267 - * How many abilities the server currently exposes, Pro's included. Reflects
268 - * the operator's toolset selection, because that is the number that governs
269 - * how much of every request's context window this server occupies.
232 + * How many tools the server exposes for the enabled toolsets, Pro's
233 + * included. Prompts don't count; they aren't in the tool list.
270 234 *
271 235 * @return int
272 236 */
273 237 public static function toolsCount()
274 238 {
275 - // Tools only: prompts do not occupy the tool list, which is the number
276 - // this count exists to report.
277 239 $names = AbilitiesRegistrar::getToolNames();
278 240
279 241 $names = apply_filters('fluent_booking/mcp_ability_names', $names);
280 242
@@ -317,15 +279,10 @@
317 279 && function_exists('wp_register_ability');
318 280 }
319 281
320 282 /**
321 - * Suggest privacy-policy wording while MCP is on.
322 - *
323 - * Enabling this makes whichever model provider the connected client uses a
324 - * recipient of attendee data the moment a read tool is called — the site
325 - * owner is the controller and has to disclose that. WordPress has a place
326 - * for exactly this text; not using it left the transfer undisclosed
327 - * everywhere except the settings screen.
283 + * Suggest privacy-policy wording while MCP is on. The connected client's
284 + * model provider receives attendee data, which the site owner must disclose.
328 285 */
329 286 public function registerPrivacyPolicyContent()
330 287 {
331 288 if (!function_exists('wp_add_privacy_policy_content')) {