PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / trunk
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). vtrunk
3.0.3 3.0.2 3.0.1 trunk 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.3.0 2.3.1 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.91 2.7.92 2.7.93 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0
commercebird / vendor / wordpress / mcp-adapter / includes / Domain / Utils / SchemaTransformer.php
commercebird / vendor / wordpress / mcp-adapter / includes / Domain / Utils Last commit date
AbilityArgumentNormalizer.php 2 months ago ContentBlockHelper.php 2 months ago McpAnnotationMapper.php 2 months ago McpNameSanitizer.php 2 months ago McpValidator.php 2 months ago SchemaTransformer.php 2 months ago
SchemaTransformer.php
139 lines
1 <?php
2 /**
3 * SchemaTransformer class for converting flattened schemas to MCP-compatible object schemas.
4 *
5 * @package McpAdapter
6 */
7
8 declare( strict_types=1 );
9
10 namespace WP\MCP\Domain\Utils;
11
12 /**
13 * SchemaTransformer class.
14 *
15 * This class transforms flattened JSON schemas (e.g., type: string, number, boolean, array)
16 * into MCP-compatible object schemas. MCP requires all tool input schemas to be of type "object".
17 *
18 * @package McpAdapter
19 */
20 class SchemaTransformer {
21 /**
22 * Transform a schema to MCP-compatible object format.
23 *
24 * If the schema is already an object type, it is returned unchanged.
25 * If the schema is a flattened type (string, number, boolean, array), it is
26 * wrapped in an object structure with a single property (defaults to "input").
27 *
28 * @param array<string,mixed>|null $schema The JSON schema to transform.
29 * @param string $wrapper_key Property name to use when wrapping non-object schemas.
30 *
31 * @return array<string,mixed> Array containing 'schema', 'was_transformed' (bool), and 'wrapper_property' when transformed.
32 */
33 public static function transform_to_object_schema( ?array $schema, string $wrapper_key = 'input' ): array {
34 // Convert any objects to arrays and strip empty properties.
35 // Abilities may contain objects from JSON decode cycles. Empty properties must be removed
36 // because MCP expects properties to be a JSON object, and PHP serializes empty arrays as [].
37 $schema = self::normalize( $schema );
38
39 // Handle null or empty schema - return minimal valid MCP object schema.
40 if ( empty( $schema ) ) {
41 return array(
42 'schema' => array(
43 'type' => 'object',
44 ),
45 'was_transformed' => false,
46 'wrapper_property' => null,
47 );
48 }
49
50 // If no type is specified, add 'object' type since MCP requires it.
51 if ( ! isset( $schema['type'] ) ) {
52 $schema['type'] = 'object';
53
54 return array(
55 'schema' => $schema,
56 'was_transformed' => false,
57 'wrapper_property' => null,
58 );
59 }
60
61 // If already an object type, return as-is
62 if ( 'object' === $schema['type'] ) {
63 return array(
64 'schema' => $schema,
65 'was_transformed' => false,
66 'wrapper_property' => null,
67 );
68 }
69
70 // Transform flattened schema to object format
71 return array(
72 'schema' => self::wrap_in_object( $schema, $wrapper_key ),
73 'was_transformed' => true,
74 'wrapper_property' => $wrapper_key,
75 );
76 }
77
78 /**
79 * Wrap a flattened schema in an object structure.
80 *
81 * Creates an object schema with a single property (named by $wrapper_key) that
82 * contains the original flattened schema.
83 *
84 * @param array<string,mixed> $schema The flattened schema to wrap.
85 * @param string $wrapper_key Property name to wrap the value under.
86 *
87 * @return array<string,mixed> The wrapped object schema.
88 */
89 private static function wrap_in_object( array $schema, string $wrapper_key ): array {
90 return array(
91 'type' => 'object',
92 'properties' => array(
93 $wrapper_key => $schema,
94 ),
95 'required' => array( $wrapper_key ),
96 );
97 }
98
99 /**
100 * Convert objects to arrays and strip empty properties.
101 *
102 * @param array<string,mixed>|null $schema The schema to normalize.
103 *
104 * @return array<string,mixed>|null The normalized schema.
105 */
106 private static function normalize( ?array $schema ): ?array {
107 if ( null === $schema ) {
108 return null;
109 }
110
111 $schema = self::convert_objects_to_arrays( $schema );
112
113 if ( array_key_exists( 'properties', $schema ) && is_array( $schema['properties'] ) && empty( $schema['properties'] ) ) {
114 unset( $schema['properties'] );
115 }
116
117 return $schema;
118 }
119
120 /**
121 * Recursively convert objects to arrays.
122 *
123 * @param mixed $value The value to convert.
124 *
125 * @return mixed The converted value.
126 */
127 private static function convert_objects_to_arrays( $value ) {
128 if ( is_object( $value ) ) {
129 $value = (array) $value;
130 }
131
132 if ( is_array( $value ) ) {
133 return array_map( array( self::class, 'convert_objects_to_arrays' ), $value );
134 }
135
136 return $value;
137 }
138 }
139