Every confusing MCP Adapter problem you’ll hit falls into one of three buckets: the ability never registered in the first place, it registered but a permission check is rejecting the caller, or it’s executing and failing partway through. Almost all wasted debugging time comes from not knowing which bucket you’re in before you start changing code. This lesson builds the workflow the rest of the course keeps applying: reproduce the failure on demand, check what the log actually says, inspect the server with a real tool instead of guessing, then isolate which of the three buckets you’re actually dealing with.
At least one registered ability and a working MCP server (Courses 1 and 2). A local
environment where you can enable WP_DEBUG and WP_DEBUG_LOG, and Node.js available
for npx if you want to run MCP Inspector later in this course.
Step 1: Reproduce it without the AI client in the loop
The first mistake is debugging through the AI client that reported the problem. A chat client’s error message is often a paraphrase of a paraphrase, by the time you’re reading “the tool failed,” you’ve lost the actual JSON-RPC error and the actual PHP state that produced it. Reproduce the same call directly, with WP-CLI, so the only variable is your own code:
# File: terminal
wp eval '
$ability = wp_get_ability( "my-plugin/my-ability" );
var_dump( $ability );
if ( $ability ) {
var_dump( $ability->execute( array( /* the exact args the client sent */ ) ) );
}
'
If wp_get_ability() itself returns null, you already know the problem is
registration, not execution, and you can stop looking at your execute_callback
entirely. That’s the whole point of reproducing outside the client: it tells you which
bucket you’re in within the first minute, instead of after an hour of trial and error.
wp eval runs as whichever user WP-CLI is configured to act as, often none at all in a
bare install. If the ability’s permission_callback checks current_user_can(), a
bare wp eval will fail that check even when the ability is registered correctly. Use
wp eval-file with an explicit wp_set_current_user() call, or wp shell --user=,
so you’re testing as the same user your AI client actually authenticates as.
Step 2: Check the error log before changing any code
WordPress’s own debug log, not your imagination, is the fastest way to find out what actually happened. Turn it on if it isn’t already:
// File: wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Then reproduce the failure and read wp-content/debug.log directly:
# File: terminal
tail -n 100 wp-content/debug.log | grep -i -E "abilit|mcp|doing_it_wrong"
A _doing_it_wrong() notice is easy to miss because WordPress core only surfaces it
when WP_DEBUG is on, it does not appear in a normal request. Several of the real
registration failures covered later in this course produce exactly this kind of
notice, invisible until you turn debugging on. If you’ve been developing with
WP_DEBUG off, turn it on before you conclude a registration “just silently fails for
no reason.”
By default the MCP Adapter’s ErrorLogMcpErrorHandler writes execution failures to
this same PHP error log with structured context (which tool, which user, what error).
Lesson 7 covers reading and extending it in detail, for now just know it’s one more
reason to check the log first.
Step 3: Inspect the server with a real tool, not a guess
Once you know the ability registers and the log is clean, the next step is confirming what an MCP client would actually see, without trusting the client’s own UI to render it accurately. The MCP Inspector, the Model Context Protocol project’s own testing tool, gives you that directly:
# File: terminal
npx @modelcontextprotocol/inspector \
wp --path=/path/to/your/wordpress/site mcp-adapter serve \
--server=my-plugin-content-server --user=admin
Inspector shows you the exact tool list, the exact schema for each tool, and lets you call one manually with arguments you control. Lesson 6 goes deep on Inspector; for this workflow, the important habit is using it before assuming a client-reported failure is a WordPress bug at all. Plenty of confusing “MCP Adapter is broken” reports turn out to be a specific client’s own quirks in how it renders a schema or handles an empty response, not the adapter.
Step 4: Isolate the failing layer
Working through these in this specific order matters because the symptoms overlap. A
tool that “doesn’t show up” in an AI client could be a genuine registration failure, or
it could be an ability that registered fine but is being filtered out of that
particular server’s tool list, or it could be a permission check quietly rejecting the
connected user before the client ever renders it as a tool at all. Checking
registration first, with wp_get_ability() directly, rules out the entire first
category in seconds.
Test it: build a one-line triage command
A command worth keeping in your notes, since you’ll run some version of it constantly while working through this course:
# File: terminal
wp eval '
$name = "my-plugin/my-ability";
echo "registered: " . ( wp_has_ability( $name ) ? "yes" : "no" ) . PHP_EOL;
$ability = wp_get_ability( $name );
if ( $ability ) {
echo "permission: " . ( $ability->permission_callback() ? "pass" : "fail" ) . PHP_EOL;
}
'
Run it, read the two lines it prints, and you already know which of the next three modules of this course you need.
An AI client retrying, rephrasing, or silently giving up on a failed tool call can look a lot like success from the outside. Always confirm the underlying state change directly (the post exists, the option changed, the row got inserted), the same discipline the testing lessons in Course 2 already established, not just the absence of a visible error in the client.
Recap
Reproduce failures with wp eval so you’re debugging PHP directly, not a client’s
paraphrase of an error. Check wp-content/debug.log with WP_DEBUG_LOG enabled before
changing any code, _doing_it_wrong() notices from the Abilities API are invisible
without it. Use MCP Inspector to confirm what a client would actually see instead of
trusting a specific client’s rendering of a failure. Then isolate registration, then
permission, then execution, in that order, every time. The next three lessons are all
registration-layer problems, the most common place this workflow actually lands.
Resources & further reading
- MCP Adapter repository, GitHub
- MCP Inspector repository, GitHub
- Debugging in WordPress, developer.wordpress.org
- Abilities API reference, developer.wordpress.org