---
title: "WordPress Abilities API: Expose Plugin Features to AI"
description: "What the WordPress Abilities API is, how wp_register_ability() works, and how to expose plugin features to AI agents and MCP clients safely."
url: "https://wpwebhooks.org/blog/wordpress-abilities-api-ai-agents/"
date: "2026-07-02"
---

# WordPress Abilities API: Expose Plugin Features to AI

**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_init` and guard with `function_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](https://developer.wordpress.org/apis/abilities-api/), and the API's development happens in the [WordPress/abilities-api repository](https://github.com/WordPress/abilities-api).

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](https://developer.wordpress.org/reference/functions/wp_register_ability/); registration returns a [`WP_Ability`](https://developer.wordpress.org/reference/classes/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](https://wordpress.org/plugins/flowsystems-webhook-actions/) (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.

FIG 01 — One ability registration, three consumers

> 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](https://github.com/WordPress/mcp-adapter) exposes the same registry over the [Model Context Protocol](https://www.anthropic.com/news/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](/blog/wordpress-ai-agent-plugin-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](/blog/create-manage-wordpress-webhooks-rest-api/).

→

The [Webhook Actions plugin](/wordpress-webhook-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.

/Footnotes

¹ Abilities API handbook and background: [developer.wordpress.org/apis/abilities-api/](https://developer.wordpress.org/apis/abilities-api/); development at [github.com/WordPress/abilities-api](https://github.com/WordPress/abilities-api).

² The Model Context Protocol was introduced by Anthropic as an open standard for connecting AI assistants to external systems: [anthropic.com/news/model-context-protocol](https://www.anthropic.com/news/model-context-protocol).

## Structured data

```json
{"@context":"https://schema.org","@type":"Article","headline":"WordPress Abilities API: Expose Plugin Features to AI","description":"What the WordPress Abilities API is, how wp_register_ability() works, and how to expose plugin features to AI agents and MCP clients safely.","datePublished":"2026-07-02","dateModified":"2026-07-02","author":{"@type":"Person","name":"Mateusz Skorupa","url":"https://wpwebhooks.org/about/"},"publisher":{"@type":"Organization","name":"WP Webhooks","url":"https://wpwebhooks.org"},"url":"https://wpwebhooks.org/blog/wordpress-abilities-api-ai-agents/","image":"https://wpwebhooks.org/og_image.jpg","keywords":["wordpress abilities api","wp register ability","wordpress ai agents","wordpress mcp adapter","expose plugin features to ai","abilities api rest"]}

{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"WP Webhooks","item":"https://wpwebhooks.org/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://wpwebhooks.org/blog/"},{"@type":"ListItem","position":3,"name":"WordPress Abilities API: Expose Plugin Features to AI","item":"https://wpwebhooks.org/blog/wordpress-abilities-api-ai-agents/"}]}

{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"What is the WordPress Abilities API?","acceptedAnswer":{"@type":"Answer","text":"It is a central WordPress registry where plugins, themes, and core describe machine-callable capabilities. Each ability bundles a namespaced id, a label and description, JSON input and output schemas, an execute callback, and a permission callback, so AI agents and other clients can discover and invoke plugin features in a standard, validated way."}},{"@type":"Question","name":"How do I register an ability in WordPress?","acceptedAnswer":{"@type":"Answer","text":"Hook the wp_abilities_api_init action and call wp_register_ability() with a namespaced name like my-plugin/create_webhook and a definition array: label, description, category, input_schema, output_schema, execute_callback, and permission_callback. Guard the registration with function_exists() so the plugin still works on WordPress versions without the API."}},{"@type":"Question","name":"How do AI tools like Claude Code use WordPress abilities?","acceptedAnswer":{"@type":"Answer","text":"Through two surfaces that come free with registration: the REST surface under /wp-abilities/v1/, and the MCP Adapter, which exposes the registry as a Model Context Protocol server. Any MCP client — Claude Code, Cursor, and others — can then list the site's abilities, read their schemas, and invoke them with validated input."}},{"@type":"Question","name":"Is the Abilities API safe to expose on a production site?","acceptedAnswer":{"@type":"Answer","text":"Yes, if you use its gates. Every invocation passes the ability's permission callback before the execute callback runs, so access inherits your capability model. Mark destructive abilities with confirmation metadata, scope read and write abilities separately, and never expose secret values through read abilities."}},{"@type":"Question","name":"Does my plugin need the Abilities API to work with AI?","acceptedAnswer":{"@type":"Answer","text":"No — and the best pattern treats it as additive. Keep an internal registry your own features call directly, then also publish each definition via wp_register_ability() when the API is present. The Webhook Actions plugin is built exactly this way: its upcoming in-admin Build with AI agent works on any supported WordPress, and MCP/REST access lights up automatically on newer cores."}}]}
```
