TL;DR: The WordPress Abilities API is a central registry where plugins describe what they can do — a label, a JSON input schema, a permission callback, and an execute callback — under a namespaced id like my-plugin/create_webhook.
- Register once, consume three ways: your own PHP, the REST surface under
/wp-abilities/v1/, and MCP clients like Claude Code or Cursor via the MCP Adapter. - Hook
wp_abilities_api_initand guard withfunction_exists('wp_register_ability')so the plugin still works on older WordPress. - Every invocation passes the ability's permission callback before its execute callback runs — AI access inherits your capability model.
- The next major release of the Webhook Actions plugin publishes 17 webhook-building abilities this way; its in-admin Build with AI agent calls the same registry directly.
/ Overview
What is the WordPress Abilities API?
The Abilities API is WordPress core's standard way for plugins, themes, and core itself to describe distinct machine-callable capabilities in one central registry. An ability is a typed operation — "create a webhook", "list delivery logs" — bundled with a human-readable label and description, a JSON Schema for its input and output, an execute callback, and a permission callback. The canonical reference lives in the Abilities API handbook, and the API's development happens in the WordPress/abilities-api repository.
The motivation is AI. Agents are only as good as the operations they can call, and until now every plugin invented its own bridge: bespoke REST endpoints, admin-ajax handlers, prompt glue. The Abilities API replaces that with a discoverable catalog — an AI client can enumerate what a site can do, read each ability's schema, and invoke it with validated input, without knowing anything about the plugin's internals¹.
/ Registration
How does wp_register_ability() work?
You register each ability on the wp_abilities_api_init action with a namespaced name — vendor/ability — and a definition array. The function reference is on developer.wordpress.org; registration returns a WP_Ability instance. Group related abilities with wp_register_ability_category() so clients can present them as one toolset.
PHP — registering an ability (guarded for older WordPress)
// The Abilities API ships in newer WordPress cores — guard so the // plugin still activates cleanly where it is absent. if ( function_exists( 'wp_register_ability' ) ) { add_action( 'wp_abilities_api_init', function () { wp_register_ability_category( 'webhook-actions', [ 'label' => __( 'Webhook Actions', 'my-plugin' ), ] ); wp_register_ability( 'my-plugin/create_webhook', [ 'label' => 'Create webhook', 'description' => 'Create a new outbound webhook (created disabled).', 'category' => 'webhook-actions', 'input_schema' => [ 'type' => 'object', 'properties' => [ 'name' => [ 'type' => 'string' ], 'endpoint_url' => [ 'type' => 'string' ], ], 'required' => [ 'name', 'endpoint_url' ], ], 'output_schema' => [ 'type' => 'object' ], 'execute_callback' => fn( $input ) => $registry->execute( 'create_webhook', $input ), 'permission_callback' => fn() => current_user_can( 'manage_options' ), ] ); } ); }
/ Schemas
How do input schemas make abilities machine-callable?
The input schema is what turns a PHP callback into something a language model can call reliably. Models hallucinate parameter names and shapes; a JSON Schema pins the contract — property names, types, required fields, and enums — so the client can construct valid input and the site can validate it before the callback ever runs.
Enums are the underrated part. A property like conditions_evaluate_on declared as enum: ['original', 'transformed'] means the model cannot invent a third mode — the invalid call is rejected at the schema boundary, not deep inside your business logic. The same schema doubles as documentation: agents read the description strings to decide which ability fits the user's goal, so write them like one-line docs, not labels.
/ Permissions
How do permission callbacks gate AI access?
Every invocation — from PHP, REST, or an MCP client — passes the ability's permission_callback before the execute_callback runs. There is no separate "AI permission system" to design: abilities inherit WordPress's capability model, and an agent can never do more than the identity it authenticates as.
In practice you want more granularity than one capability check. The Webhook Actions plugin (in its upcoming major release) tags each ability with a scope — read for list/inspect operations, full for mutations — mirroring its REST API token scopes, and exposes the decision through a filter so site owners can open specific scopes to token-mediated MCP access without touching code. Destructive abilities additionally carry a requires_confirm flag in their meta: enabling or deleting a webhook always demands explicit user confirmation, and an HTTP probe demands it only when the probe method is unsafe.
Register an ability once and every consumer — your own admin UI, the REST surface, and any MCP client — gets the same typed, permission-gated operation. — the registration pattern
/ Discovery
How do external AI clients discover abilities?
Two surfaces come free with registration. The REST surface under /wp-abilities/v1/ lets any authenticated HTTP client list registered abilities, read their schemas, and run them. And the MCP Adapter exposes the same registry over the Model Context Protocol — the open standard AI tools use to connect to external systems — so Claude Code, Cursor, and other MCP clients can discover and invoke your site's toolset like any other MCP server².
This is the payoff of central registration: you write zero per-client integration code. The day a new MCP-speaking tool appears, it can already drive your plugin.
/ Case study
How does a real plugin register its toolset?
The upcoming Webhook Actions release publishes 17 abilities under the flowsystems-webhook-actions/* namespace: five read abilities (list triggers, list webhooks, inspect a webhook, read a captured trigger schema, read delivery logs) and twelve full-scope abilities (list credential names, create and update webhooks, set field mappings and conditions, assign credentials, run test dispatches, probe endpoints, build chains, enable and delete webhooks).
The instructive part is that the registration is purely additive. The plugin's own in-admin AI agent calls the internal registry directly in PHP, so Build with AI works on any supported WordPress version. When the Abilities API is present, a thin registrar class also publishes each definition with wp_register_ability() — same schemas, same callbacks, same permission gates. One toolset, defined once, consumed by the in-admin agent, the REST surface, and external MCP clients alike. (For how the agent side works, see the plan-first agent architecture.)
| Concern | DIY AI bridge (custom endpoints + glue) | Abilities API (Webhook Actions) |
|---|---|---|
| Discovery | Hand-written docs the model never sees | Machine-readable registry with JSON Schemas |
| Validation | Each endpoint re-implements input checks | Schema-validated input before the callback runs |
| Permissions | Per-endpoint checks you must remember | Central permission callback + confirm meta per ability |
| New AI clients | One custom integration per tool | REST + MCP Adapter serve every client |
/ Adoption
Should your plugin adopt the Abilities API now?
If your plugin has operations an agent could usefully drive — creating content, configuring integrations, querying state — yes, and the additive pattern makes it low-risk. Keep your internal API as the source of truth, register abilities as a thin layer over it, guard with function_exists(), and mark destructive operations with confirmation metadata. Your plugin loses nothing on older WordPress and gains a full AI surface on newer cores.
Two design rules from building this: keep ability granularity at the level of user intent (one ability per meaningful operation, not per database row), and never expose secrets through read abilities — list credential names, never values. If you already run a REST API, your ability scopes should mirror its token scopes so there is exactly one permission story to audit. For the REST-first view of the same toolset, see creating and managing webhooks over the REST API.
The Webhook Actions plugin will ship its full webhook toolset as WordPress Abilities in its next major release — so Claude Code, Cursor, or any MCP client can build and manage reliable, queued, retried webhook integrations on your site.