PluginProbe
ZIP AI – AI Website Builder & AI Agent (Beta) / 0.0.8
ZIP AI – AI Website Builder & AI Agent (Beta) v0.0.8
0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
zip-ai / lib / mcp-adapter / includes / Domain / Utils / SchemaTransformer.php

SchemaTransformer.php in ZIP AI – AI Website Builder & AI Agent (Beta) 0.0.8, at lib/mcp-adapter/includes/Domain/Utils/SchemaTransformer.php

139 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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