If there’s one issue that generates more confused bug reports than everything else in
this migration combined, it’s this one: an ability registers without error, shows up
in wp_get_abilities(), and then simply never appears to a connected AI agent. The
cause is almost always the same single missing field, and this lesson exists to make
sure you never lose an afternoon to it.
An ability already registered (Lesson 2 covers migrating registration itself). The MCP Adapter plugin installed and active, since the field has no effect without it.
Step 1: Confirm what the field actually does
meta.mcp.public is not part of registering an ability. It’s a value inside the
meta argument you pass to wp_register_ability(), and it is read specifically by
the MCP Adapter plugin to decide whether to include that ability in the tool list it
serves to external MCP clients:
// File: my-plugin.php
add_action( 'wp_abilities_api_init', function () {
wp_register_ability(
'my-plugin/create-draft-post',
array(
'label' => __( 'Create draft post', 'my-plugin' ),
'description' => __( 'Creates a new draft post from a title and body.', 'my-plugin' ),
'input_schema' => array(
'type' => 'object',
'properties' => array(
'title' => array( 'type' => 'string' ),
'body' => array( 'type' => 'string' ),
),
'required' => array( 'title' ),
),
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
'execute_callback' => 'my_plugin_create_draft_post',
'meta' => array(
'mcp' => array( 'public' => true ),
),
)
);
} );
Without that meta block, or with public set to false, the ability still fully
exists, your own code can still call it with wp_get_ability( 'my-plugin/create-draft-post' )->execute(), but the MCP Adapter will not hand it to any connected agent.
Step 2: Why migrated abilities are especially likely to miss this
The archived, pre-core wordpress/abilities-api package never depended on the MCP
Adapter existing at all, it only handled registration. If your original code was
written and tested purely against that package, before you’d installed the MCP
Adapter, there was never a moment where a missing meta.mcp.public would have caused a
visible failure. It’s an easy field to have simply never added, and migrating your
registration code line-for-line onto core doesn’t fix it, since the omission was never
a core-versus-package issue in the first place.
If you migrate a batch of abilities and only one class of bug shows up afterward, it’s
this one: agents reporting “the tool isn’t available” for something you know is
registered. Check meta.mcp.public first, before assuming a deeper migration problem.
Step 3: Run the diagnostic
This one wp eval command tells you, for every registered ability on the site, exactly
what the MCP Adapter would currently expose:
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";
}
'
Run this immediately after any migration batch. Anything printing private that you
expected an agent to be able to call is your list of abilities still needing the
meta.mcp.public fix from Step 1.
Step 4: Work through the full checklist, not just the obvious cause
meta.mcp.public being unset is the most common cause, but it isn’t the only thing
that can make an ability invisible to an agent. Work through all of these before
assuming a deeper bug:
Test it: connect a real client and compare
Once the diagnostic script and checklist agree an ability should be visible, confirm
against an actual connected MCP client (Claude Desktop, Cursor, or whichever client
Course 3 walked you through), and check its tool list matches your wp eval output
exactly. A mismatch at this point almost always points back to the client-side cache
item in Step 4’s checklist, not a server-side registration problem.
It’s tempting to treat wp_get_abilities() returning your ability as proof an agent
can use it. It isn’t. Registration and MCP exposure are two separate, independently
controlled things, and conflating them is exactly what generates the confused “it’s
registered but doesn’t work” bug reports this lesson exists to prevent.
Recap
meta.mcp.public is the actual gate between an ability existing and an ability being
usable by an external AI agent, and it’s a field the archived standalone package never
required you to think about, which is exactly why migrated abilities are especially
prone to missing it. Run the diagnostic script in Step 3 after every migration batch,
work the full checklist in Step 4 before assuming a deeper bug, and always confirm
against a real connected client before calling an ability “done.”
Resources & further reading
- Abilities API reference, developer.wordpress.org
- wp_register_ability() function reference, developer.wordpress.org
- MCP Adapter repository, GitHub