Not every ability you register should be reachable by an external AI agent. This
lesson covers the two mechanisms that control that: categories, which organize
abilities for humans and tooling, and meta.mcp.public, which is the actual
security-relevant gate on external MCP exposure.
Understanding Abilities (Lesson 3). No new tools needed.
Step 1: Registering a category
Categories group related abilities for discoverability, similar in spirit to how taxonomies group posts. Register one on the dedicated categories hook, which fires before the main abilities hook:
// File: my-plugin.php
add_action( 'wp_abilities_api_categories_init', function () {
wp_register_ability_category(
'content',
array( 'label' => __( 'Content management', 'my-plugin' ) )
);
} );
Then reference that category’s slug in any ability’s category argument, as shown in
Lesson 3. Categories exist to organize a growing list of abilities, they have no
security effect on their own.
Step 2: The actual gate, meta.mcp.public
This is the field that decides whether the MCP Adapter includes an ability in the tool list it hands to external AI clients at all:
'meta' => array(
'mcp' => array( 'public' => true ),
),
Registering an ability does not automatically expose it over MCP. Treat
meta.mcp.public the same way you’d treat any other capability boundary: default it
to false (or omit it, which the MCP Adapter treats as not exposed), and only set it to
true for abilities you’ve specifically reviewed for safe external use, meaning you’ve
also written a permission_callback that’s strict enough to trust with agent traffic.
Step 3: Why internal-only abilities are a normal pattern
An ability with no meta.mcp.public (or set to false) isn’t wasted, it’s still fully
usable by your own code, or by other plugins, via wp_get_ability()->execute() as
shown in Lesson 3. A common, legitimate pattern:
Test it: confirm what’s actually exposed
Once the MCP Adapter is active (from Lesson 2), you can check what it would currently expose without connecting a real AI client:
wp-env run cli wp eval '
$abilities = wp_get_abilities();
foreach ( $abilities as $ability ) {
$public = $ability->get_meta( "mcp" )["public"] ?? false;
echo $ability->get_name() . ": " . ( $public ? "public" : "private" ) . "\n";
}
'
This prints every registered ability and whether it’s currently exposed to MCP clients, a useful sanity check before connecting a real agent in Course 3.
It’s easy to assume that because an ability shows up in wp_get_abilities(), an AI
agent can see it too. It can’t, unless meta.mcp.public is true. This distinction is
exactly what earlier drafts of this material (and some third-party tutorials) blur
together under the informal, non-official phrase “MCP-public,” the real mechanism is
this specific meta field, not a separate registration step.
Recap
Categories organize abilities for humans and tooling, they don’t affect security.
meta.mcp.public is the actual boundary between an ability existing and an ability
being reachable by an external AI agent, and it should default to false. Plenty of
abilities are legitimately internal-only, existing purely so your own code has a
consistent, permission-checked way to call itself.
Resources & further reading
- Abilities API reference, developer.wordpress.org
- wp_register_ability() function reference, developer.wordpress.org
- MCP Adapter repository, GitHub