Review fix round 1: content-query now excludes posts/statuses the user
cannot edit before querying (author restriction without edit_others_posts,
status filtering by edit_private_posts/edit_published_posts) instead of
only dropping them after fetching, and rejects unknown field/taxonomy
filters. content-types' not-found hint only lists editable types.
PostPresenter skips Pods password fields and readonly protected meta.
Query input gains search/terms length limits.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
- AbilityRegistrar: wrap permission_callback in try/catch(Throwable) like
execute_callback, so a throwing permission() denies (Errors::internal())
instead of skipping rest_request_after_callbacks and leaving
RequestContext's flag set for a later request in the same PHP worker.
- RequestContext::recordRoute() now recomputes the flag (and bearer token)
unconditionally on every matched REST request instead of only setting it
true for our own route, so a stale true left behind by an earlier request
is reset by the next non-matching one (fail closed, defense in depth).
- RequestContext::recordRoute() matches the Authorization "Bearer" scheme
case-insensitively.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
- Autoloader: add automattic/jetpack-autoloader and load
vendor/autoload_packages.php; require wordpress/mcp-adapter directly (^0.5).
- ServerRegistrar: make the adapter create_server() call and the
OAuthServerRegistrar class_exists() check injectable so createServer()'s
unhook-before-create ordering and the "mcp-oauth absent" branch are unit
tested; add a smoke-test check that booting REST triggers no
_doing_it_wrong().
- mcp-smoke.sh: assert mcp-adapter's default server route 404s, and that the
subscriber role-gate denial actually carries our/the adapter's denial text
(not just any isError/error).
- Guard tests/Integration/mint-token.php and tec-probe.php with
`defined('WP_CLI') && WP_CLI || exit;`; add .gitattributes export-ignore
for tests/docs-superpowers/.superpowers/phpunit/phpcs config.
- Security: add Server/RequestContext, tracking via
rest_request_before_callbacks whether the current REST dispatch is our
OAuth-protected /mcp/mcp-oauth-server route; AbilityRegistrar's
permission_callback now denies (after the role gate) when abilities are
invoked outside that route. Wired in Plugin::boot().
- Minors: single Plugin::VERSION constant used by ServerRegistrar;
IntegrationRegistry caches its computed abilities list; tec-probe.php
checks wp_insert_post's result and cleans up its probe post in a
try/finally.
composer test: 47/47 green. composer lint: clean. Full mcp-smoke.sh run ends
ALL CHECKS PASSED (plus the expected /.well-known WARN).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
- Default oauthEnabled to WPMedia\MCP\OAuth\Context::is_enabled() instead of
duplicating its filter logic, so the deprecated rocket_mcp_oauth_server_enabled
filter and the typed wpmedia_mcp_oauth_server_enabled filter are honored
exactly as mcp-oauth itself defines them.
- register() now disables mcp-adapter's default server
(mcp_adapter_create_default_server => false) so no second, unauthenticated
MCP endpoint (plain HttpTransport, is_user_logged_in()) is exposed alongside
our OAuth-protected one; mcp-oauth's own ServerRegistrar registers the
shared meta-abilities itself once the default server is disabled.
- Pass WPMedia\MCP\OAuth\Context::observability_handler() instead of null so
mcp-oauth's own observability filter keeps working for our server too.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
Proactively unhook wp-media/mcp-oauth's own mcp_adapter_init callback before
creating our server, rather than letting it collide and rely on WP_DEBUG=true
being harmless. The collision previously surfaced as a fatal-looking
_doing_it_wrong notice under WP-CLI (breaking every wp command while the
plugin is active) and could leak debug notices into HTTP responses on
customer sites that run WP_DEBUG.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
The lit_mcp_allowed_roles filter could return a non-array, causing
array_filter() to throw TypeError in PHP 8.1+. Now fallback to
['administrator'] if filter result is not an array.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7