Description
#116 was closed as fixed in v0.5.0 via AbilityArgumentNormalizer, but the fix only covers abilities without an input schema. Abilities with an input schema (the exact case in #116's reproduction steps) still fail on v0.5.0 when called with empty {} parameters:
Ability "wds/get-posts" has invalid input. Reason: input is not of type object.
We reproduced this today in production on mcp-adapter v0.5.0 across two independent WordPress sites, for every registered ability that defines an input_schema (type object, all-optional or required properties alike).
Steps to Reproduce
- Register an ability with an
input_schema of type object (optional properties, no default key).
- Call
mcp-adapter-execute-ability with:
{
"ability_name": "example/get-info",
"parameters": {}
}
- Expected: ability executes (no required properties).
- Actual:
Ability "example/get-info" has invalid input. Reason: input is not of type object.
Any non-empty parameters object (e.g. {"anything": true}) succeeds.
Evidence that the ability receives null, not []
AbilityArgumentNormalizer::normalize() only converts [] → null when the ability has no schema, and never converts null → [] when it has one. On v0.5.0 the inner ability demonstrably receives null:
We patched our plugin to add 'default' => array() to every ability's input_schema — and the failure disappeared on the same v0.5.0 install, with no other change. WP_Ability::normalize_input() only applies the schema default when input is null, and rest_validate_value_from_schema( array(), … ) passes — so the pre-patch failure must be rest_validate_value_from_schema( null, {type: object} ) → "input is not of type object".
So somewhere in the v0.5.0 execution chain, "parameters": {} (or an omitted parameters key — $input['parameters'] ?? null in ExecuteAbilityAbility::execute()) reaches WP_Ability::execute() as null for schema-defining abilities, and validation rejects it with the misleading type error.
Suggested fix
In AbilityArgumentNormalizer::normalize() (or ExecuteAbilityAbility::execute() / the tools handler), handle the inverse case as well: when the ability has an input schema and the arguments are null or an empty array, pass array() so it validates as an empty object. Roughly:
if ( ! empty( $input_schema ) && ( null === $parameters || array() === $parameters ) ) {
return array();
}
This keeps strict rejection for abilities without schemas (current behavior) while letting zero-argument calls through for schema-defining abilities — which is what every MCP client sends for tools it believes take no arguments.
Workarounds
- Client side: always send a non-empty parameters object, e.g.
{"refresh": true}.
- Ability side: add
'default' => array() to every registered input_schema (what we shipped).
Environment
- MCP Adapter: v0.5.0 (reproduced on two independent production sites)
- WordPress: 6.9 (core Abilities API — no standalone abilities-api plugin installed)
- Client: Claude (Desktop/Code) via MCP integration, calling the
mcp-adapter-execute-ability tool
Related: #116 (same symptom, closed for v0.5.0), #75 (the no-schema half, fixed).
Description
#116 was closed as fixed in v0.5.0 via
AbilityArgumentNormalizer, but the fix only covers abilities without an input schema. Abilities with an input schema (the exact case in #116's reproduction steps) still fail on v0.5.0 when called with empty{}parameters:We reproduced this today in production on mcp-adapter v0.5.0 across two independent WordPress sites, for every registered ability that defines an
input_schema(typeobject, all-optional or required properties alike).Steps to Reproduce
input_schemaof typeobject(optional properties, nodefaultkey).mcp-adapter-execute-abilitywith:{ "ability_name": "example/get-info", "parameters": {} }Ability "example/get-info" has invalid input. Reason: input is not of type object.Any non-empty parameters object (e.g.
{"anything": true}) succeeds.Evidence that the ability receives
null, not[]AbilityArgumentNormalizer::normalize()only converts[]→nullwhen the ability has no schema, and never convertsnull→[]when it has one. On v0.5.0 the inner ability demonstrably receivesnull:We patched our plugin to add
'default' => array()to every ability'sinput_schema— and the failure disappeared on the same v0.5.0 install, with no other change.WP_Ability::normalize_input()only applies the schemadefaultwhen input isnull, andrest_validate_value_from_schema( array(), … )passes — so the pre-patch failure must berest_validate_value_from_schema( null, {type: object} )→ "input is not of type object".So somewhere in the v0.5.0 execution chain,
"parameters": {}(or an omittedparameterskey —$input['parameters'] ?? nullinExecuteAbilityAbility::execute()) reachesWP_Ability::execute()asnullfor schema-defining abilities, and validation rejects it with the misleading type error.Suggested fix
In
AbilityArgumentNormalizer::normalize()(orExecuteAbilityAbility::execute()/ the tools handler), handle the inverse case as well: when the ability has an input schema and the arguments arenullor an empty array, passarray()so it validates as an empty object. Roughly:This keeps strict rejection for abilities without schemas (current behavior) while letting zero-argument calls through for schema-defining abilities — which is what every MCP client sends for tools it believes take no arguments.
Workarounds
{"refresh": true}.'default' => array()to every registeredinput_schema(what we shipped).Environment
mcp-adapter-execute-abilitytoolRelated: #116 (same symptom, closed for v0.5.0), #75 (the no-schema half, fixed).