PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
elementor / vendor / wordpress / mcp-adapter / includes / Domain / Prompts / McpPromptBuilder.php

McpPromptBuilder.php in Elementor Website Builder – more than just a page builder 4.3.1, at vendor/wordpress/mcp-adapter/includes/Domain/Prompts/McpPromptBuilder.php

346 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Abstract base class for building MCP prompts.
4 *
5 * @package McpAdapter
6 */
7
8 declare( strict_types=1 );
9
10 namespace WP\MCP\Domain\Prompts;
11
12 use WP\MCP\Domain\Prompts\Contracts\McpPromptBuilderInterface;
13 use WP\MCP\Domain\Utils\McpValidator;
14 use WP\McpSchema\Server\Prompts\DTO\Prompt as PromptDto;
15 use WP\McpSchema\Server\Prompts\DTO\PromptArgument;
16
17 /**
18 * Abstract base class for building MCP prompts.
19 *
20 * @deprecated 0.5.0 Use {@see \WP\MCP\Domain\Prompts\McpPrompt} instead for creating prompts.
21 *
22 * The fluent API or array configuration provided by McpPrompt is simpler
23 * and more flexible than subclassing this abstract class:
24 *
25 * ```php
26 * // Fluent API (preferred)
27 * $prompt = McpPrompt::create('my-prompt')
28 * ->title('My Prompt')
29 * ->argument('input', 'Input text', true)
30 * ->handler(function(array $args): array {
31 * return ['messages' => [...]];
32 * });
33 *
34 * // Array configuration (WordPress-style)
35 * $prompt = McpPrompt::fromArray([
36 * 'name' => 'my-prompt',
37 * 'title' => 'My Prompt',
38 * 'arguments' => [['name' => 'input', 'description' => 'Input text', 'required' => true]],
39 * 'handler' => function(array $args): array { return [...]; },
40 * ]);
41 * ```
42 *
43 * This class remains functional for backward compatibility but will be
44 * removed in a future major version.
45 *
46 * @see McpPrompt For the preferred prompt creation API.
47 */
48 abstract class McpPromptBuilder implements McpPromptBuilderInterface {
49
50 /**
51 * The prompt name (unique identifier).
52 *
53 * @var string
54 */
55 protected string $name = '';
56
57 /**
58 * The prompt title (human-readable display name).
59 *
60 * @var string|null
61 */
62 protected ?string $title = null;
63
64 /**
65 * The prompt description.
66 *
67 * @var string|null
68 */
69 protected ?string $description = null;
70
71 /**
72 * The prompt arguments.
73 *
74 * @var list<array{name: string, title?: string, description?: string, required?: bool}>
75 */
76 protected array $arguments = array();
77
78 /**
79 * The prompt icons for UI display.
80 *
81 * @since 0.5.0
82 *
83 * @var list<array{src: string, mimeType?: string, sizes?: array<string>, theme?: string}>|null
84 */
85 protected ?array $icons = null;
86
87 /**
88 * Additional metadata for MCP clients.
89 *
90 * Use this to attach purpose-specific metadata that MCP clients can consume.
91 * Key names are kept as written. MCP declares `_meta` an object, so {@see self::build()}
92 * emits this only when it is a non-empty associative array; a list or an empty array
93 * would serialize as a JSON array and is omitted instead.
94 *
95 * @since 0.5.0
96 *
97 * @var array<string, mixed>
98 */
99 protected array $meta = array();
100
101 /**
102 * Constructor - automatically configures the prompt.
103 *
104 * Configuration happens exactly once during construction, ensuring
105 * idempotent behavior. Subclasses should NOT override this constructor;
106 * instead, implement the configure() method.
107 *
108 * @since 0.5.0
109 */
110 final public function __construct() {
111 $this->configure();
112 }
113
114 /**
115 * Configure the prompt properties.
116 *
117 * Subclasses must implement this method to set the name, title,
118 * description, and arguments for the prompt. This method is called
119 * exactly once during construction.
120 *
121 * @return void
122 */
123 abstract protected function configure(): void;
124
125 /**
126 * Build and return the Prompt DTO instance.
127 *
128 * This method converts the configured state into an MCP Prompt DTO.
129 * Safe to call multiple times - always returns a fresh DTO based on
130 * the current (immutable after construction) state.
131 *
132 * @return \WP\McpSchema\Server\Prompts\DTO\Prompt The built prompt DTO.
133 */
134 public function build(): PromptDto {
135 $argument_dtos = null;
136 if ( ! empty( $this->arguments ) ) {
137 $argument_dtos = array_map(
138 static function ( array $arg ): PromptArgument {
139 return PromptArgument::fromArray(
140 array(
141 'name' => $arg['name'],
142 'title' => $arg['title'] ?? null,
143 'description' => $arg['description'] ?? null,
144 'required' => $arg['required'] ?? null,
145 )
146 );
147 },
148 $this->arguments
149 );
150 }
151
152 // Validate and prepare icons if set.
153 $valid_icons = null;
154 if ( ! empty( $this->icons ) ) {
155 $icons_result = McpValidator::validate_icons_array( $this->icons );
156 if ( ! empty( $icons_result['valid'] ) ) {
157 $valid_icons = $icons_result['valid'];
158 }
159 }
160
161 $prompt_data = array(
162 'name' => $this->name,
163 'title' => $this->title,
164 'description' => $this->description,
165 'arguments' => $argument_dtos,
166 );
167
168 $prompt_meta = McpValidator::normalize_meta( $this->meta );
169 if ( null !== $prompt_meta ) {
170 $prompt_data['_meta'] = $prompt_meta;
171 }
172
173 // Only include icons if valid ones exist.
174 if ( null !== $valid_icons ) {
175 $prompt_data['icons'] = $valid_icons;
176 }
177
178 return PromptDto::fromArray( $prompt_data );
179 }
180
181 /**
182 * Get the unique name for this prompt.
183 *
184 * @return string The prompt name.
185 */
186 public function get_name(): string {
187 return $this->name;
188 }
189
190 /**
191 * Get the prompt title.
192 *
193 * @return string|null The prompt title.
194 */
195 public function get_title(): ?string {
196 return $this->title;
197 }
198
199 /**
200 * Get the prompt description.
201 *
202 * @return string|null The prompt description.
203 */
204 public function get_description(): ?string {
205 return $this->description;
206 }
207
208 /**
209 * Get the prompt arguments.
210 *
211 * @return list<array{name: string, title?: string, description?: string, required?: bool}> The prompt arguments.
212 */
213 public function get_arguments(): array {
214 return $this->arguments;
215 }
216
217 /**
218 * Get the prompt icons.
219 *
220 * @return list<array{src: string, mimeType?: string, sizes?: array<string>, theme?: string}> The prompt icons.
221 * @since 0.5.0
222 *
223 */
224 public function get_icons(): array {
225 return $this->icons ?? array();
226 }
227
228 /**
229 * Set the prompt icons for UI display.
230 *
231 * Icons are validated during build() using McpValidator::validate_icons_array().
232 * Invalid icons are filtered out with warnings (graceful degradation).
233 *
234 * Per MCP 2025-11-25:
235 * - MUST support: image/png, image/jpeg, image/jpg
236 * - SHOULD support: image/svg+xml, image/webp
237 *
238 * @param list<array{src: string, mimeType?: string, sizes?: array<string>, theme?: string}> $icons Array of icon definitions.
239 *
240 * @return self
241 * @since 0.5.0
242 *
243 */
244 protected function set_icons( array $icons ): self {
245 $this->icons = $icons;
246
247 return $this;
248 }
249
250 /**
251 * Get the additional metadata.
252 *
253 * @return array<string, mixed> The additional metadata.
254 * @since 0.5.0
255 *
256 */
257 public function get_meta(): array {
258 return $this->meta;
259 }
260
261 /**
262 * Set additional metadata.
263 *
264 * Key names are kept as written. MCP declares `_meta` an object, so {@see self::build()}
265 * emits this only when it is a non-empty associative array.
266 *
267 * @param array<string, mixed> $meta Additional metadata key-value pairs.
268 *
269 * @return self
270 * @since 0.5.0
271 *
272 */
273 protected function set_meta( array $meta ): self {
274 $this->meta = $meta;
275
276 return $this;
277 }
278
279 /**
280 * Handle the prompt execution when called.
281 *
282 * Subclasses must implement this method to handle the prompt logic.
283 *
284 * @param array<string, mixed> $arguments The arguments passed to the prompt.
285 *
286 * @return array<string, mixed> The prompt response.
287 */
288 abstract public function handle( array $arguments ): array;
289
290 /**
291 * Check if the current user has permission to execute this prompt.
292 *
293 * Default implementation allows all executions. Override this method
294 * to implement custom permission logic.
295 *
296 * @param array<string, mixed> $arguments The arguments passed to the prompt.
297 *
298 * @return bool True if execution is allowed, false otherwise.
299 */
300 public function has_permission( array $arguments ): bool {
301 // Default: allow all executions
302 // Override this method to implement custom permission logic
303 return true;
304 }
305
306 /**
307 * Helper method to add an argument to the prompt.
308 *
309 * @param string $name The argument name.
310 * @param string|null $description Optional argument description.
311 * @param bool $required Whether the argument is required.
312 *
313 * @return self
314 */
315 protected function add_argument( string $name, ?string $description = null, bool $required = false ): self {
316 $this->arguments[] = $this->create_argument( $name, $description, $required );
317
318 return $this;
319 }
320
321 /**
322 * Helper method to create an argument definition.
323 *
324 * @param string $name The argument name.
325 * @param string|null $description Optional argument description.
326 * @param bool $required Whether the argument is required.
327 *
328 * @return array{name: string, description?: string, required?: true} The argument definition.
329 */
330 protected function create_argument( string $name, ?string $description = null, bool $required = false ): array {
331 $argument = array(
332 'name' => $name,
333 );
334
335 if ( null !== $description ) {
336 $argument['description'] = $description;
337 }
338
339 if ( $required ) {
340 $argument['required'] = true;
341 }
342
343 return $argument;
344 }
345 }
346