Most of this course has shown you what the MCP Adapter does well. This lesson is the honest inventory of what it doesn’t do at all, as of this writing, so you stop looking for a setting that doesn’t exist and start building the workaround instead. None of this is a criticism of the project: the MCP Adapter is an actively developing plugin built by the WordPress AI team, and gaps like these are exactly what an early-stage piece of infrastructure looks like before a wider ecosystem of add-ons fills them in. Treat this lesson as a map of “build it yourself for now,” not “avoid this tool.”
This lesson assumes you completed MCP Security & Authentication for WordPress, since every workaround here is a direct application of that course’s custom rate-limiting and capability patterns to the specific gaps named below.
Step 1: No OAuth, at all
The MCP Adapter supports exactly two authentication mechanisms: WordPress Application Passwords, and cookie/nonce authentication for same-origin browser contexts. There is no OAuth flow built in, anywhere in the adapter. If a client or an integration partner asks “does this support OAuth,” the honest answer today is no, and the workaround is the same one Course 4 built: an Application Password issued per integration, treated with the same operational discipline (rotation, per-integration issuance, revocation on offboarding) an OAuth token would get.
// File: my-plugin.php
// There is no OAuth handshake to hook into. This is the entire auth surface:
// Application Passwords (wp-admin > Users > Profile, or the REST endpoint),
// or an authenticated cookie session for same-origin requests.
For genuinely external, third-party OAuth-expecting integrations, the honest path is a thin OAuth-to-Application-Password bridge you build and control yourself, not a setting inside the adapter.
Step 2: No built-in rate limiting
The adapter enforces no request-per-minute or request-per-user ceiling anywhere.
Nothing stops a misbehaving or compromised client from calling an ability in a tight
loop. Course 4’s transient-based rate limiter is the real answer, applied inside your
own permission_callback:
// File: my-plugin.php
'permission_callback' => function () {
$user_id = get_current_user_id();
$key = "my_plugin_rl_{$user_id}";
$count = (int) get_transient( $key );
if ( $count >= 30 ) {
return new WP_Error( 'rate_limited', __( 'Too many requests, try again shortly.', 'my-plugin' ) );
}
set_transient( $key, $count + 1, MINUTE_IN_SECONDS );
return current_user_can( 'edit_posts' );
},
This lives entirely in your ability’s own code, the adapter has no concept of rate limiting to configure or override.
Step 3: No RBAC beyond core capabilities
The adapter doesn’t add a role or permission system of its own, permission_callback
is just PHP, and whatever authorization model it expresses is entirely up to you.
That’s usually fine, since WordPress’s own roles and capabilities are already a real
RBAC system, but if you need something finer-grained (an “MCP client tier” concept that
doesn’t map to an existing WordPress role) you build it as a custom capability, exactly
as Course 4 covered:
// File: my-plugin.php
add_action( 'init', function () {
$role = get_role( 'editor' );
$role->add_cap( 'my_plugin_use_mcp_partner_tier' );
} );
Then check it, and only it, in the relevant abilities’ permission_callbacks. There’s
no separate “MCP permissions” system to configure, it’s the same capability system
you’ve always had.
Step 4: No built-in audit trail
Nothing in the adapter itself persists a durable, queryable log of “which user, via
which client, called which ability, with what input, when.” The ErrorLogMcpErrorHandler
default writes failures to the PHP error log, and the observability handler (Lesson 3)
gives you a hook to build metrics, but neither one is a compliance-grade audit trail by
itself. Build that as a custom observability handler that writes to a dedicated
database table instead of a transient bucket, exactly the pattern Course 4 introduced
for security event logging:
// File: my-plugin.php
class My_Plugin_Audit_Log_Handler implements \WP\MCP\Infrastructure\Observability\Contracts\McpObservabilityHandlerInterface {
public function record_event( string $event, array $tags = array(), ?float $duration_ms = null ): void {
global $wpdb;
$wpdb->insert( "{$wpdb->prefix}mcp_audit_log", array(
'event_time' => current_time( 'mysql' ),
'user_id' => get_current_user_id(),
'event' => $event,
'ability' => $tags['ability'] ?? null,
'tags' => wp_json_encode( $tags ),
) );
}
}
| What’s missing | Workaround | Covered in depth |
|---|---|---|
| OAuth | Disciplined Application Password issuance and rotation | Course 4 |
| Rate limiting | Transient counters inside permission_callback | Course 4 |
| Fine-grained RBAC | Custom capabilities added to roles, checked in permission_callback | Course 4 |
| Audit trail | Custom McpObservabilityHandlerInterface writing to a real table | This course, Lesson 3 |
Test it
Confirm your rate limiter actually engages by calling an ability more than the
threshold in under a minute through a real MCP client, and confirm the 31st call
returns the rate_limited error rather than executing:
for i in $(seq 1 32); do
wp-env run cli wp eval 'var_dump( wp_get_ability( "my-plugin/some-ability" )->has_permission( array() ) );'
done
The final few calls in that loop should return false or a WP_Error, not true.
The MCP Adapter is a young, actively maintained project. Treat this lesson’s contents
as accurate today and worth re-checking against the project’s own changelog and the
make.wordpress.org/ai/ roadmap before assuming any specific gap still exists a year
from now.
Recap
As of this writing, the MCP Adapter has no OAuth, no built-in rate limiting, no RBAC system beyond WordPress’s own capabilities, and no persistent audit trail out of the box. Every one of those gaps has a real, working custom pattern, Application Password discipline, transient-based rate limiting, custom capabilities, and a database-backed observability handler, all of which Course 4 and this course have already built. None of this is a reason to avoid the adapter; it’s the current shape of an early-stage piece of infrastructure.
Resources & further reading
- MCP Adapter repository, GitHub
- MCP Adapter announcement: from abilities to AI agents, developer.wordpress.org
- make.wordpress.org/ai, make.wordpress.org