-
Notifications
You must be signed in to change notification settings - Fork 140
Fix: Add placeholder property for parameterless ability schemas #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,13 @@ | |||||||||||||||
| * @package McpAdapter | ||||||||||||||||
| */ | ||||||||||||||||
| class SchemaTransformer { | ||||||||||||||||
| /** | ||||||||||||||||
| * No-op property placeholder for tools without input fields. | ||||||||||||||||
| * | ||||||||||||||||
| * @var string | ||||||||||||||||
| */ | ||||||||||||||||
| private const NOOP_PROPERTY = '_mcp_noop'; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Transform a schema to MCP-compatible object format. | ||||||||||||||||
| * | ||||||||||||||||
|
|
@@ -39,8 +46,10 @@ public static function transform_to_object_schema( ?array $schema, string $wrapp | |||||||||||||||
| // Handle null or empty schema - return minimal valid MCP object schema. | ||||||||||||||||
| if ( empty( $schema ) ) { | ||||||||||||||||
| return array( | ||||||||||||||||
| 'schema' => array( | ||||||||||||||||
| 'type' => 'object', | ||||||||||||||||
| 'schema' => self::ensure_object_properties( | ||||||||||||||||
| array( | ||||||||||||||||
| 'type' => 'object', | ||||||||||||||||
| ) | ||||||||||||||||
| ), | ||||||||||||||||
| 'was_transformed' => false, | ||||||||||||||||
| 'wrapper_property' => null, | ||||||||||||||||
|
Comment on lines
46
to
55
|
||||||||||||||||
|
|
@@ -52,7 +61,7 @@ public static function transform_to_object_schema( ?array $schema, string $wrapp | |||||||||||||||
| $schema['type'] = 'object'; | ||||||||||||||||
|
|
||||||||||||||||
| return array( | ||||||||||||||||
| 'schema' => $schema, | ||||||||||||||||
| 'schema' => self::ensure_object_properties( $schema ), | ||||||||||||||||
| 'was_transformed' => false, | ||||||||||||||||
| 'wrapper_property' => null, | ||||||||||||||||
| ); | ||||||||||||||||
|
|
@@ -61,7 +70,7 @@ public static function transform_to_object_schema( ?array $schema, string $wrapp | |||||||||||||||
| // If already an object type, return as-is | ||||||||||||||||
| if ( 'object' === $schema['type'] ) { | ||||||||||||||||
| return array( | ||||||||||||||||
| 'schema' => $schema, | ||||||||||||||||
| 'schema' => self::ensure_object_properties( $schema ), | ||||||||||||||||
| 'was_transformed' => false, | ||||||||||||||||
| 'wrapper_property' => null, | ||||||||||||||||
| ); | ||||||||||||||||
|
|
@@ -75,6 +84,34 @@ public static function transform_to_object_schema( ?array $schema, string $wrapp | |||||||||||||||
| ); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Ensure an object schema has properties. | ||||||||||||||||
| * | ||||||||||||||||
| * If the schema already has non-empty properties, it is returned unchanged. | ||||||||||||||||
| * Otherwise, it injects a no-op placeholder property to ensure the schema | ||||||||||||||||
| * is a valid JSON object with at least one property. | ||||||||||||||||
|
Comment on lines
+90
to
+92
|
||||||||||||||||
| * If the schema already has non-empty properties, it is returned unchanged. | |
| * Otherwise, it injects a no-op placeholder property to ensure the schema | |
| * is a valid JSON object with at least one property. | |
| * If the schema already has non-empty properties, they are preserved. | |
| * Otherwise, it injects a no-op placeholder property to ensure the schema | |
| * is a valid JSON object with at least one property. This method also | |
| * normalizes the `required` field to an array when it is missing or invalid. |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SchemaTransformer is also used by RegisterAbilityAsMcpPrompt to derive prompt arguments from input_schema. Injecting a _mcp_noop property here means abilities with an otherwise-parameterless object schema (e.g. { type: 'object' } / empty properties) will now surface a _mcp_noop prompt argument, which is a user-visible API change. Consider making placeholder injection opt-in (e.g., a flag on transform_to_object_schema), or have prompt argument conversion explicitly ignore the NOOP_PROPERTY key so prompts remain argument-less.
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ensure_object_properties() currently normalizes required by overwriting any non-array value with an empty array. This can silently mask invalid schemas (e.g., a mis-specified string/object required) that the existing MCP validation layer would otherwise report. Consider only defaulting required when it is missing, and leaving invalid types untouched so validators can surface a clear error.
| if ( ! isset( $schema['required'] ) || ! is_array( $schema['required'] ) ) { | |
| if ( ! array_key_exists( 'required', $schema ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes the contract for null/empty schemas: instead of returning the minimal
{ type: 'object' }, it now injects placeholderproperties(andrequired). The existing PHPUnit expectations intests/Unit/Domain/Utils/SchemaTransformerTest.phpfor null/empty schemas (and empty properties stripping) will fail unless updated to match the new output shape.