Core Concepts

Controlling Visibility: Ability Categories and the meta.mcp.public Flag

⏱ 10 min

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.

What you'll learn in this lesson
How ability categories work
Registering and assigning categories with wp_register_ability_category().
What meta.mcp.public actually controls
The difference between an ability existing and an ability being exposed to MCP clients.
Why the safe default is false
And when you deliberately flip it to true.
Internal-only abilities
A legitimate, common pattern: abilities that exist purely for your own plugin's internal use.
Prerequisites

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 ),
),
Default to false, opt in deliberately

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:

Build internal abilities for internal reuse
Standardize how your own plugin's features call each other, even with zero AI involvement.
Expose a narrower, purpose-built ability publicly
Rather than flipping an existing internal ability to public, register a second, more restrictive ability specifically for agent use.
Keep destructive or bulk operations private by default
A "delete all drafts older than 30 days" ability is a reasonable internal tool, and a much riskier one to hand an AI agent without careful scoping.

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.

Confusing 'registered' with 'exposed'

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

← How AI Agents Discover and Execute Actions on Your Site The PHP AI Client SDK: WordPress Calling AI vs AI Calling WordPress →