Wp rocket mcp and abilities
Skill Lonsdale201/wp-agent-skills/wp-rocket/wp-rocket-mcp-and-abilities
A community-maintained collection of agent skills for WordPress plugin and theme development.
npx -y skills add Lonsdale201/wp-agent-skills --skill wp-rocket-mcp-and-abilitiesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Expose, scope, or secure WP Rocket settings for AI / MCP clients — new in 3.23. Two layers — WP Abilities API abilities (wp-rocket/get-options readonly, wp-rocket/set-option destructive, category wp-rocket-options, cap rocket_manage_options) and a built-in MCP OAuth 2.1 server at /wp-json/mcp/mcp-oauth-server (/oauth/*, /.well-known) with trusted publisher Claude (claude.ai). Critical — abilities default ON (rocket_enable_abilities), the OAuth server defaults OFF (rocket_mcp_oauth_server_enabled), and both need the WP Abilities API + wordpress/mcp-adapter or nothing registers. Scope what AI may read / write via rocket_mcp_options_allowlist (an additive allowlist); add clients via rocket_mcp_trusted_publishers. Filters are typed (wpm_apply_filters_typed) — return exact bool / array. Use when exposing WP Rocket settings to an MCP client, scoping the allowlist, or reviewing AI-facing code. Triggers on rocket_mcp_, rocket_enable_abilities, wp-rocket/get-options, wp-rocket/set-option, "/oauth/" MCP server.
SKILL.md
19.6 KB, ~4.6k tokens by cl100k_base, as published. Nobody here has run it
WP Rocket: MCP server and AI Abilities
New in WP Rocket 3.23. WP Rocket ships an AI-integration surface that lets a Model Context Protocol (MCP) client — the bundled/trusted publisher is Claude — read and write WP Rocket settings on a live site in natural language. For a companion plugin / theme developer this skill covers how to scope, extend, or lock down that surface, not how to build an MCP client.
The MCP OAuth server is described in its own source as a proof of concept (inc/Engine/MCP/Auth/ClaudeClientVerifier.php:8). Treat it as experimental: the abilities are stable-ish public hooks, the OAuth transport is newer and off by default.
The two layers (the mental model that prevents 90% of mistakes)
WP Rocket's AI surface is two independent layers with opposite defaults:
| Layer | What it is | Default | Enable/kill filter |
|---|---|---|---|
| Abilities | WP Abilities API entries (wp-rocket/get-options, wp-rocket/set-option) in category wp-rocket-options | ON (true) | rocket_enable_abilities |
| MCP OAuth server | OAuth 2.1 + JWT transport at /wp-json/mcp/mcp-oauth-server, /oauth/*, /.well-known/* that lets a remote client authenticate and reach the abilities | OFF (false) | rocket_mcp_oauth_server_enabled |
Key consequences:
- Abilities register on their own, gated only by
rocket_enable_abilities(defaulttrue) — verified inc/Engine/Abilities/Context.php:19. They are reachable by any local abilities/MCP consumer and via REST (show_in_rest => true), still behind therocket_manage_optionscapability. Turning the OAuth server on is NOT required for the abilities to exist. - The OAuth server is what a remote client (Claude) needs to log in. It is off until a site owner opts in with
rocket_mcp_oauth_server_enabled— verified inc/Engine/MCP/Context.php:23. - To fully remove AI read/write of WP Rocket settings, set
rocket_enable_abilitiestofalse. Turning off only the OAuth server still leaves the abilities registered for local consumers.
Feature-detection — three things must ALL be present
Nothing here loads on a stock WordPress. Before relying on it:
- WP Rocket 3.23+ —
defined('WP_ROCKET_VERSION')andversion_compare(WP_ROCKET_VERSION, '3.23', '>='). - The WP Abilities API —
function_exists('wp_register_ability'). WP Rocket'sregister()methods early-return without it (GetOptions.php:44, SetOption.php:154). - The MCP Adapter —
class_exists(\WP\MCP\Core\McpAdapter::class)(bundled aswordpress/mcp-adapter^0.4.1). The transportServer::register_server()early-returns without it (Server.php:19). Only needed for the OAuth/MCP server layer, not for the abilities themselves.
if (
! defined( 'WP_ROCKET_VERSION' )
|| version_compare( WP_ROCKET_VERSION, '3.23', '<' )
|| ! function_exists( 'wp_register_ability' )
) {
return; // No WP Rocket AI surface to customize.
}
Misconception this skill corrects
"Enabling the MCP OAuth server is what exposes my settings to AI, so leaving it off is safe."
Half-true. The OAuth server (off by default) only gates remote authentication. The abilities (wp-rocket/get-options, wp-rocket/set-option) register regardless, defaulting ON, and are callable by any local abilities consumer and over REST — always subject to the rocket_manage_options capability. If you need to guarantee no AI path can touch settings, use add_filter( 'rocket_enable_abilities', '__return_false' ), don't just leave the OAuth server off.
Other AI-prone misconceptions:
- "
rocket_mcp_options_allowlistis a blocklist — I add keys to hide them." Wrong, it's an allowlist. Whatever it returns is exactly what AI can read (get-options) and write (set-option). Adding a key EXPOSES it; removing a key restricts it. Verified AllowedOptions.php:14 and enforced inSetOption::validate_option_name()(SetOption.php:318). - "These are
apply_filters, so I return whatever." They run throughwpm_apply_filters_typed( 'boolean' | 'array', ... )— the wrapper calls coreapply_filters(soadd_filterworks normally) then coerces/validates the return type. Return a realboolfor boolean filters and a realarrayfor array filters; a wrong type is coerced or dropped. Prefer__return_true/__return_falsefor the booleans. - "
rocket_mcp_trusted_publisherslets me bless any client_id." No — it can only ADD publishers, and each must still pass an exact client_id URL match plus a host-based SSRF gate; it cannot bypass theverifiedhard-reject. Verified ClaudeClientVerifier.php:83-113. - "
set-optionjust writes what I send." It validates the key against the allowlist, sanitizes per option type, and for array/textarea optionsupdate(default) MERGES into the existing list; onlyreplaceoverwrites. Verified SetOption.php:331.
When to use this skill
Trigger when ANY of the following is true:
- Exposing WP Rocket settings to Claude / an MCP client, or scoping WHICH settings AI may touch.
- The diff adds
add_filter( 'rocket_enable_abilities' | 'rocket_mcp_oauth_server_enabled' | 'rocket_mcp_options_allowlist' | 'rocket_mcp_trusted_publishers', ... ). - Code references
wp-rocket/get-options,wp-rocket/set-option, thewp-rocket-optionsability category, or/wp-json/mcp/mcp-oauth-server//oauth/*//.well-known/oauth-*. - Reviewing a companion plugin that registers its own abilities and wants to appear alongside WP Rocket's, or that adds custom option keys to the allowlist.
- Security review: is a destructive
set-optionreachable, is the allowlist minimal, is the OAuth server intentionally on?
The abilities (verified surface)
Both live in category wp-rocket-options (registered on wp_abilities_api_categories_init), and both check current_user_can( 'rocket_manage_options' ) (rocket_manage_options is a WP Rocket capability that exists @since 3.4, granted to administrator on activation).
| Ability | Kind | meta.annotations | Permission |
|---|---|---|---|
wp-rocket/get-options | Read all allowlisted options as a flat key→value object | readonly: true, destructive: false, idempotent: true | rocket_manage_options |
wp-rocket/set-option | Write ONE option (option_name, option_value, optional update_mode) | readonly: false, destructive: true, idempotent: true | rocket_manage_options |
Both carry meta.mcp.public => true and show_in_rest => true.
set-option input schema (verified SetOption.php:171):
option_name— enum of the allowlist keys.option_value—anyOfstring / boolean / integer / array-of-string.update_mode—update(default, appends to array/textarea options) orreplace(overwrites the whole list).
set-option returns { success, error?, previous_value, new_value }. The ability's own description text instructs the AI to show current→new value and require explicit per-change confirmation before writing, and to call get-options first when editing an array-type option so it doesn't clobber existing entries.
Controlling exposure — the allowlist and the kill switch
The single control point for "what can AI see and change" is rocket_mcp_options_allowlist. The built-in list (~70 keys) spans cache, CSS/JS optimization, media/lazyload, fonts, preload, database cleanup, CDN, Cloudflare, Heartbeat, performance monitoring, and add-ons — verified AllowedOptions.php:14.
// Expose a custom / third-party option key to the get-options & set-option abilities.
add_filter( 'rocket_mcp_options_allowlist', function ( array $allowlist ): array {
$allowlist[] = 'my_plugin_cache_toggle';
return $allowlist;
} );
// RESTRICT — remove sensitive settings you never want AI to change (e.g. CDN + Cloudflare).
add_filter( 'rocket_mcp_options_allowlist', function ( array $allowlist ): array {
return array_values( array_diff( $allowlist, [
'cdn', 'cdn_cnames', 'cdn_zone',
'do_cloudflare', 'cloudflare_auto_settings',
] ) );
} );
// Kill switch — no AI read/write of WP Rocket settings at all.
add_filter( 'rocket_enable_abilities', '__return_false' );
A key added to the allowlist is readable via
get-optionsonly if it also has a schema entry inGetOptions(the readable set = allowlist ∩ known schema,array_intersect_keyat GetOptions.php:416); it is writable viaset-optionpurely on allowlist membership, and unknown keys fall throughsanitize_value()unmodified. So when you expose a custom key, prefer wiring your own sanitization on the WP Rocket option save path rather than trusting the pass-through.
The MCP OAuth server (opt-in)
Off until a site owner opts in:
// Turn the MCP OAuth server ON (rewrite rules, /oauth/* endpoints, discovery, transport).
add_filter( 'rocket_mcp_oauth_server_enabled', '__return_true' );
// After toggling, flush rewrite rules once (Settings > Permalinks, or wp rewrite flush).
What it registers when enabled (verified):
- MCP server at
/wp-json/mcp/mcp-oauth-serverviaWP\MCP\Core\McpAdapter, exposingmcp-adapter/discover-abilities,get-ability-info,execute-abilityover a custom JWT-BearerOAuthHttpTransport— Server.php:18-41. - OAuth endpoints via rewrite rules (query var
mcp_oauth_endpoint, handled ontemplate_redirect) — Rewrite.php:43-48:/oauth/authorize,/oauth/authorize-callback,/oauth/token,/oauth/consent,/oauth/revoke. - Discovery documents (rewrite on
init) — Discovery/Endpoints.php:44-52:/.well-known/oauth-protected-resource(RFC 9728),/.well-known/oauth-authorization-server(RFC 8414).
Trusted publishers (who may connect)
Client identification uses Client ID Metadata Documents (CIMD). Only client_ids whose host is allowlisted are ever network-fetched (SSRF gate), and the fetched doc must exactly match a pinned client_id. The bundled publisher is Claude — verified ClaudeClientVerifier.php:100-112:
claude → client_ids: https://claude.ai/oauth/claude-code-client-metadata
https://claude.ai/oauth/mcp-oauth-client-metadata
host: claude.ai
Add another trusted MCP client (can only ADD; the exact client_id match + host gate still apply):
add_filter( 'rocket_mcp_trusted_publishers', function ( array $publishers ): array {
$publishers['my-agent'] = [
'client_ids' => [ 'https://agent.example.com/.well-known/mcp-client' ],
'host' => 'agent.example.com',
];
return $publishers;
} );
Security considerations
set-optionis destructive by declaration. Anyone (or any AI) that can authenticate as a user holdingrocket_manage_optionscan flip caching, CDN, Cloudflare, and database-cleanup settings. Keep the allowlist minimal for the risk profile you accept.- Minimize the allowlist, don't expand it casually. Database-cleanup toggles (
database_*),cdn*, andcloudflare_*have real side effects if flipped by a confused agent. - The OAuth server is a public network surface when enabled — leave it off unless a specific integration needs it, and confirm the trusted-publisher list is exactly what you intend.
- Telemetry: every ability execution fires
track_event( 'MCP Ability Executed', … )(WP Media Mixpanel, viaTrackingTrait) — GetOptions.php:467, SetOption.php:269. If your compliance posture forbids that, gate it at WP Rocket's analytics/consent setting. - Capability, not nonce, is the gate. Access hinges entirely on
rocket_manage_options; do not grant that cap to roles you wouldn't trust to reconfigure caching.
Critical rules
- Two layers, opposite defaults: abilities default ON (
rocket_enable_abilities), OAuth server default OFF (rocket_mcp_oauth_server_enabled). Reason about them separately. - To disable AI settings access entirely, use
rocket_enable_abilities => false; the OAuth-server toggle alone is not enough. rocket_mcp_options_allowlistis an ALLOWLIST — adding exposes, removing restricts. Minimize it.- Typed filters (
wpm_apply_filters_typed): return the exact declared type —boolfor the two enable filters,arrayfor allowlist / trusted-publishers. Use__return_true/__return_falsefor booleans. set-optionupdate_modedefaults toupdate(merge) for array/textarea options; passreplaceto overwrite. Readget-optionsbefore editing an array option.rocket_mcp_trusted_publisherscan only ADD publishers; exact client_id match + host SSRF gate still apply. Never widen a host to a shared domain.- Flush rewrite rules after toggling the OAuth server on/off (the
/oauth/*and/.well-known/*paths are rewrite-based). - Feature-detect all three: WP Rocket 3.23+,
wp_register_ability, and (for the server)McpAdapter. - The abilities are behind
rocket_manage_options— treat that capability as the real security boundary.
Common mistakes
// WRONG — assuming the allowlist hides keys
add_filter( 'rocket_mcp_options_allowlist', function ( $a ) {
$a[] = 'stripe_secret_key'; // WRONG: this EXPOSES it to AI read/write
return $a;
} );
// RIGHT — allowlist is additive exposure; to hide, remove
add_filter( 'rocket_mcp_options_allowlist', function ( $a ) {
return array_values( array_diff( $a, [ 'do_cloudflare' ] ) );
} );
// WRONG — returning the wrong type into a typed filter
add_filter( 'rocket_mcp_oauth_server_enabled', function () {
return 1; // WRONG: boolean filter; return a real bool
} );
// RIGHT
add_filter( 'rocket_mcp_oauth_server_enabled', '__return_true' );
// WRONG — thinking "OAuth server off" means settings are AI-proof
add_filter( 'rocket_mcp_oauth_server_enabled', '__return_false' );
// abilities still registered & REST-exposed behind rocket_manage_options
// RIGHT — to guarantee no AI settings surface
add_filter( 'rocket_enable_abilities', '__return_false' );
// WRONG — trusting an arbitrary client via a shared host
add_filter( 'rocket_mcp_trusted_publishers', function ( $p ) {
$p['x'] = [ 'client_ids' => [ 'https://github.com/foo' ], 'host' => 'github.com' ];
return $p; // WRONG: shared host = anyone on that host is a candidate client
} );
// RIGHT — a host you control, with exact client_id URLs
add_filter( 'rocket_mcp_trusted_publishers', function ( $p ) {
$p['my-agent'] = [
'client_ids' => [ 'https://agent.example.com/.well-known/mcp-client' ],
'host' => 'agent.example.com',
];
return $p;
} );
// WRONG — expecting update_mode 'update' to overwrite an array option
// set-option { option_name: 'cache_reject_uri', option_value: ['/x'] }
// → MERGES '/x' into the existing list, does not replace it
// RIGHT — pass replace when you mean overwrite
// set-option { option_name: 'cache_reject_uri', option_value: ['/x'], update_mode: 'replace' }
Cross-references
- Run
wp-abilities-apifor the generic WP Abilities API mechanics (registering abilities, categories,wp_register_ability, permission/execute callbacks,input_schema/output_schema) — WP Rocket's abilities are a concrete consumer of that API. - Run
claude-api/ MCP references when building the client side that connects to this server (Claude as the trusted publisher). - Run
wp-rocket-cache-rejection-and-filtersto understand what the exposed option keys actually do (cache_reject_uri,cdn_*,lazyload*, etc.) before allowlisting them. - Run
wp-rocket-cache-invalidationwhen the task is clearing cache after a change rather than exposing settings. - Run
wp-security-audit/wp-security-secretswhen reviewing whether the allowlist or trusted-publisher list widens the attack surface.
What this skill does NOT cover
- Building an MCP client (the Claude side). This is the server/integrator surface only.
- The WP Abilities API internals — see
wp-abilities-api. - The
wordpress/mcp-adapterpackage internals (WP\MCP\*) — bundled dependency; treat its classes as private and version-volatile. Integrate via WP Rocket's filters and the public abilities. - OAuth/JWT protocol internals (token issuance, JTI/refresh handling, application-password linkage) — private
inc/Engine/MCP/Auth/*implementation; do not call directly. - The WP Rocket settings UI / license / activation — out of scope for integrators.
References
- Abilities enable gate: inc/Engine/Abilities/Context.php:19 —
wpm_apply_filters_typed( 'boolean', 'rocket_enable_abilities', true ). - Allowlist: inc/Engine/Abilities/Options/AllowedOptions.php:14-102 — built-in ~70 keys +
rocket_mcp_options_allowlist. wp-rocket/get-options: inc/Engine/Abilities/Options/GetOptions.php:418 — readonly,mcp.public, caprocket_manage_options.wp-rocket/set-option: inc/Engine/Abilities/Options/SetOption.php:158 — destructive;input_schema,update_mode, per-type sanitization at SetOption.php:331.- MCP OAuth enable gate: inc/Engine/MCP/Context.php:23 —
wpm_apply_filters_typed( 'boolean', 'rocket_mcp_oauth_server_enabled', false ). - MCP server: inc/Engine/MCP/Transport/Server.php:18 —
/wp-json/mcp/mcp-oauth-server, McpAdapter, ability-adapter tools. - OAuth endpoints: inc/Engine/MCP/Auth/Rewrite.php:43 —
/oauth/{authorize,authorize-callback,token,consent,revoke}. - Discovery: inc/Engine/MCP/Auth/Discovery/Endpoints.php:44 —
/.well-known/oauth-protected-resource,/.well-known/oauth-authorization-server. - Trusted publishers (Claude): inc/Engine/MCP/Auth/ClaudeClientVerifier.php:100 —
rocket_mcp_trusted_publishers. - Bundled deps (composer.json):
wordpress/mcp-adapter ^0.4.1,wp-media/apply-filters-typed ^1.0(thewpm_apply_filters_typedhelper),wp-media/wp-mixpanel(telemetry). - Official documentation: https://docs.wp-rocket.me/article/92-plugin-compatibility-with-wp-rocket
- Official documentation: https://docs.wp-rocket.me/article/2-getting-started