Skip to content

Ability schemas are not JSON-Schema clean: object-valued sanitize_callback and a malformed ai/get-post-terms output schema break MCP tool conversion #668

@WouterP0lman

Description

@WouterP0lman

Summary

Two abilities ship input/output schemas that are not valid JSON Schema. ai/alt-text-generation puts an object-bound callable (array( $this, 'method' )) in sanitize_callback, and ai/get-post-terms has a structurally malformed output_schema. Any strict JSON-Schema consumer of these schemas breaks. Concretely, exposing them through WordPress/mcp-adapter causes a stack overflow (alt-text) and a validation failure (get-post-terms), so these abilities cannot become MCP tools.

Environment

WordPress/ai 1.0.1
WordPress 7.0 (Abilities API in core)
PHP 8.3
Surfaced via wordpress/mcp-adapter 0.5.0

Problem 1: object-valued sanitize_callback in ai/alt-text-generation

includes/Abilities/Image/Alt_Text_Generation.php:

'image_url' => array(
    'type'              => 'string',
    'sanitize_callback' => array( $this, 'sanitize_image_reference_input' ), // object-bound callable
    'description'       => '...',
),

The exported input schema therefore contains a live PHP object. A JSON-Schema consumer that walks the schema descends into that object graph. In mcp-adapter 0.5.0 this recurses until the Zend stack limit: Maximum call stack size ... reached. Infinite recursion?. The string-valued callbacks on attachment_id (absint) and context (sanitize_textarea_field) are fine; only the object-bound one is a problem.

Problem 2: malformed output_schema in ai/get-post-terms

includes/Abilities/Utilities/Posts.php:

'output_schema' => array(
    'type'       => 'object',
    'properties' => array(
        'type'  => 'array',          // 'properties' should be a map of name => sub-schema
        'items' => array( ... ),     // this looks like an array schema placed under 'properties'
    ),
),

properties must be an object mapping property names to sub-schemas. Here it holds type (string "array") and items, which reads like an array schema was pasted into the properties slot. A strict validator reports Expected array or object for key "type", got string. The output is presumably meant to be an array of term objects, so the schema shape is wrong.

Expected behavior

input_schema and output_schema should be valid JSON Schema. WordPress-only concerns such as sanitization belong in execution or validation, not as object-valued keys inside the exported schema. The get-post-terms output schema should describe an array of term objects correctly.

Proposed fix

  • For alt-text-generation: keep sanitization server-side, but do not emit an object-bound callable in the exported schema. Either reference a named function, or strip callable keys from the schema exposed via REST and MCP.
  • For get-post-terms: correct the output_schema to a proper array-of-objects shape (for example type: array with items: { type: object, properties: { term_id, name, slug, ... } }), rather than nesting that under properties.
  • Consider a unit test that asserts every registered ai/* ability schema round-trips through wp_json_encode() and validates as JSON Schema, so non-clean schemas are caught in CI.

Context

Discovered while exposing the WordPress/ai abilities as MCP tools via mcp-adapter. A companion robustness issue is filed on WordPress/mcp-adapter (it should strip WordPress-only keys and guard against recursion regardless), but the schemas themselves should also be JSON-Schema clean. Happy to open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions