{"id":300297,"date":"2026-05-08T12:14:09","date_gmt":"2026-05-08T12:14:09","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/mcp-manager\/"},"modified":"2026-07-22T04:13:13","modified_gmt":"2026-07-22T04:13:13","slug":"acrossai-mcp-manager","status":"publish","type":"plugin","link":"https:\/\/lmo.wordpress.org\/plugins\/acrossai-mcp-manager\/","author":15295430,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.1.6","stable_tag":"0.1.6","tested":"7.0.2","requires":"7.0","requires_php":"8.1","requires_plugins":null,"header_name":"AcrossAI MCP Manager","header_author":"raftaar1191","header_description":"Enable\/Disable MCP Adapter Integration for WordPress","assets_banners_color":"ccdbfb","last_updated":"2026-07-22 04:13:13","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/acrossai.co\/","header_author_uri":"https:\/\/profiles.wordpress.org\/raftaar1191\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":631,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.0.1":{"tag":"0.0.1","author":"raftaar1191","date":"2026-05-08 12:13:51"},"0.0.2":{"tag":"0.0.2","author":"raftaar1191","date":"2026-05-08 12:20:27"},"0.0.3":{"tag":"0.0.3","author":"raftaar1191","date":"2026-05-14 14:45:29"},"0.0.4":{"tag":"0.0.4","author":"raftaar1191","date":"2026-06-02 11:53:16"},"0.0.5":{"tag":"0.0.5","author":"raftaar1191","date":"2026-06-02 12:01:31"},"0.0.6":{"tag":"0.0.6","author":"raftaar1191","date":"2026-07-04 00:14:27"},"0.0.7":{"tag":"0.0.7","author":"raftaar1191","date":"2026-07-04 00:46:20"},"0.0.8":{"tag":"0.0.8","author":"raftaar1191","date":"2026-07-04 01:08:15"},"0.0.9":{"tag":"0.0.9","author":"raftaar1191","date":"2026-07-04 01:33:59"},"0.1.1":{"tag":"0.1.1","author":"raftaar1191","date":"2026-07-17 02:08:40"},"0.1.2":{"tag":"0.1.2","author":"raftaar1191","date":"2026-07-17 02:17:28"},"0.1.3":{"tag":"0.1.3","author":"raftaar1191","date":"2026-07-19 07:07:06"},"0.1.4":{"tag":"0.1.4","author":"raftaar1191","date":"2026-07-20 05:14:29"},"0.1.5":{"tag":"0.1.5","author":"raftaar1191","date":"2026-07-20 12:01:25"},"0.1.6":{"tag":"0.1.6","author":"raftaar1191","date":"2026-07-22 04:13:13"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon.svg":{"filename":"icon.svg","revision":3595613,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3614699,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3614699,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.0.1","0.0.2","0.0.3","0.0.4","0.0.5","0.0.6","0.0.7","0.0.8","0.0.9","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.1.6"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3614210,"resolution":"1","location":"assets","locale":"","width":3268,"height":1874},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3614210,"resolution":"10","location":"assets","locale":"","width":3268,"height":1874},"screenshot-11.png":{"filename":"screenshot-11.png","revision":3614210,"resolution":"11","location":"assets","locale":"","width":3268,"height":1874},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3614210,"resolution":"2","location":"assets","locale":"","width":3268,"height":1874},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3614210,"resolution":"3","location":"assets","locale":"","width":3268,"height":1874},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3614210,"resolution":"4","location":"assets","locale":"","width":3268,"height":1874},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3614210,"resolution":"5","location":"assets","locale":"","width":3268,"height":1874},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3614210,"resolution":"6","location":"assets","locale":"","width":3268,"height":1874},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3614210,"resolution":"7","location":"assets","locale":"","width":3268,"height":1874},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3614210,"resolution":"8","location":"assets","locale":"","width":3268,"height":1874}},"screenshots":{"1":"Settings page with client tabs for easy configuration","2":"Copy-paste ready JSON configuration","3":"One-click password generation","4":"Per-provider configuration file locations and top-level keys"}},"plugin_section":[],"plugin_tags":[2353,229563,222885,242115,254221],"plugin_category":[44,54],"plugin_contributors":[140910],"plugin_business_model":[],"class_list":["post-300297","plugin","type-plugin","status-publish","hentry","plugin_tags-ai","plugin_tags-claude","plugin_tags-copilot","plugin_tags-mcp","plugin_tags-vscode","plugin_category-discussion-and-community","plugin_category-security-and-spam-protection","plugin_contributors-raftaar1191","plugin_committers-raftaar1191"],"banners":{"banner":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/banner-772x250.png?rev=3614699","banner_2x":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/banner-1544x500.png?rev=3614699","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/icon.svg?rev=3595613","icon":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/icon.svg?rev=3595613","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-1.png?rev=3614210","caption":"Settings page with client tabs for easy configuration"},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-2.png?rev=3614210","caption":"Copy-paste ready JSON configuration"},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-3.png?rev=3614210","caption":"One-click password generation"},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-4.png?rev=3614210","caption":"Per-provider configuration file locations and top-level keys"},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-5.png?rev=3614210","caption":""},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-6.png?rev=3614210","caption":""},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-7.png?rev=3614210","caption":""},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-8.png?rev=3614210","caption":""},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-10.png?rev=3614210","caption":""},{"src":"https:\/\/ps.w.org\/acrossai-mcp-manager\/assets\/screenshot-11.png?rev=3614210","caption":""}],"raw_content":"<!--section=description-->\n<p>MCP Manager uses the standard <code>@automattic\/mcp-wordpress-remote@latest<\/code> package with WordPress Application Passwords for the default remote flow. It also includes an optional experimental direct Claude Connectors mode backed by a WordPress-hosted OAuth approval flow.<\/p>\n\n<p>MCP Manager is a WordPress plugin that enables seamless integration with Model Context Protocol (MCP) servers, allowing AI assistants and code editors to safely access your WordPress instance through secure application passwords.<\/p>\n\n<h4>Key Features<\/h4>\n\n<ul>\n<li><p><strong>Multi-Client Support<\/strong>: Configure MCP for:<\/p>\n\n<ul>\n<li>VS Code with Copilot<\/li>\n<li>Claude Desktop App<\/li>\n<li>GitHub Copilot &amp; Codex<\/li>\n<li>OpenAI ChatGPT Codex<\/li>\n<li>Custom MCP Clients<\/li>\n<\/ul><\/li>\n<li><p><strong>Secure Authentication<\/strong>: Uses WordPress native Application Passwords system<\/p>\n\n<ul>\n<li>One-click password generation<\/li>\n<li>Secure credential management<\/li>\n<li>Password revocation support<\/li>\n<li>Per-server Access Control still enforced after authentication<\/li>\n<\/ul><\/li>\n<li><p><strong>Easy Configuration<\/strong>:<\/p>\n\n<ul>\n<li>Copy-paste ready JSON configurations<\/li>\n<li>Per-provider configuration file paths<\/li>\n<li>Automatic top-level key detection<\/li>\n<\/ul><\/li>\n<li><p><strong>Format #1 Standard<\/strong>: Uses the Automattic-recommended MCP configuration format<\/p>\n\n<ul>\n<li>npx command execution<\/li>\n<li>@automattic\/mcp-wordpress-remote@latest package<\/li>\n<li>Full environment variable support<\/li>\n<\/ul><\/li>\n<\/ul>\n\n<h4>How It Works<\/h4>\n\n<ol>\n<li>Navigate to Settings \u2192 MCP Manager<\/li>\n<li>Select your MCP client (VS Code, Claude, GitHub Copilot, ChatGPT, or Custom)<\/li>\n<li>Click \"Generate New Application Password\"<\/li>\n<li>Copy the ready-to-use JSON configuration<\/li>\n<li>Paste into your client's configuration file<\/li>\n<li>Restart your MCP client<\/li>\n<\/ol>\n\n<p>All application passwords are managed through WordPress's native Application Passwords system and appear in your profile under Account Management.<\/p>\n\n<h4>CLI Connection and Authorization Flow<\/h4>\n\n<p>MCP Manager also supports a browser-assisted CLI connection flow for local MCP clients.<\/p>\n\n<p>Typical command:<\/p>\n\n<pre><code>npx -y @acrossai\/mcp-manager --siteurl=https:\/\/example.com --server=default-mcp-server\n<\/code><\/pre>\n\n<p>Flow summary:<\/p>\n\n<ol>\n<li>The CLI checks <code>\/wp-json\/acrossai-mcp-manager\/v1\/health<\/code><\/li>\n<li>The CLI starts auth with <code>\/wp-json\/acrossai-mcp-manager\/v1\/auth\/start<\/code><\/li>\n<li>WordPress returns an <code>auth_code<\/code> and frontend <code>auth_url<\/code><\/li>\n<li>The CLI opens the frontend approval page at <code>\/acrossai-mcp-manager\/<\/code><\/li>\n<li>If needed, the user signs in through normal WordPress login<\/li>\n<li>The signed-in user approves access in the browser<\/li>\n<li>The CLI polls <code>\/auth\/status<\/code> until the request is approved<\/li>\n<li>The CLI fetches the approved user's accessible servers from <code>\/servers<\/code><\/li>\n<li>The CLI exchanges the approved code at <code>\/auth\/exchange<\/code><\/li>\n<li>WordPress creates a one-time Application Password and the CLI writes the MCP client config<\/li>\n<\/ol>\n\n<p>Terminology:<\/p>\n\n<ul>\n<li><strong>Sign in \/ Log in<\/strong> = WordPress account authentication<\/li>\n<li><strong>Connect<\/strong> = starting the CLI-to-site linking flow<\/li>\n<li><strong>Authorize \/ Approve access<\/strong> = granting the CLI permission in the browser<\/li>\n<\/ul>\n\n<p>Important notes:<\/p>\n\n<ul>\n<li>The frontend authorization page must never be cached<\/li>\n<li>Auth codes are single-use<\/li>\n<li><code>\/servers<\/code> and <code>\/auth\/exchange<\/code> respect per-server access control<\/li>\n<li>User-facing copy should say <strong>CLI Connections<\/strong> rather than <strong>npm Login<\/strong><\/li>\n<li>Generated remote MCP configs use Application Passwords and explicitly disable OAuth discovery in <code>@automattic\/mcp-wordpress-remote<\/code><\/li>\n<\/ul>\n\n<h4>Experimental Direct Claude Connectors<\/h4>\n\n<p>An optional <strong>Claude Connectors Screen (Experimental)<\/strong> setting can enable a direct OAuth flow for Claude's hosted connectors.<\/p>\n\n<p>When the global feature toggle is enabled and a specific server is configured in its <strong>Claude Connector<\/strong> tab, the plugin exposes:<\/p>\n\n<ul>\n<li><code>\/.well-known\/oauth-authorization-server<\/code><\/li>\n<li><code>\/.well-known\/oauth-protected-resource?resource=&lt;mcp-url&gt;<\/code><\/li>\n<li><code>\/acrossai-mcp-connectors\/oauth\/authorize\/<\/code><\/li>\n<li><code>\/wp-json\/acrossai-mcp-manager\/v1\/connector\/oauth\/token<\/code><\/li>\n<\/ul>\n\n<p>Important notes:<\/p>\n\n<ul>\n<li>Disabled by default<\/li>\n<li>The Application Password flow remains available and supported<\/li>\n<li>The master experimental toggle is global, but OAuth client settings are stored per server<\/li>\n<li>Direct connector approval signs Claude in as a WordPress user<\/li>\n<li>Per-server Access Control still applies to every MCP request after OAuth<\/li>\n<li>Public HTTPS is recommended for hosted connector usage<\/li>\n<\/ul>\n\n<h4>Provider Configuration Paths<\/h4>\n\n<ul>\n<li><strong>VS Code<\/strong>: ~\/.config\/Code\/User\/globalStorage\/Copilot.copilot-chat\/mcp.json (top-level key: \"servers\")<\/li>\n<li><strong>Claude<\/strong>: ~\/Library\/Application Support\/Claude\/claude_desktop_config.json (top-level key: \"mcpServers\")<\/li>\n<li><strong>GitHub Copilot<\/strong>: ~\/.gh-copilot\/config.json (top-level key: \"servers\")<\/li>\n<li><strong>OpenAI ChatGPT<\/strong>: ~\/.config\/chatgpt\/config.json (top-level key: \"servers\")<\/li>\n<li><strong>Custom<\/strong>: .\/your-project\/.mcp\/config.json (top-level key: configurable)<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 5.9 or higher<\/li>\n<li>PHP 7.4 or higher<\/li>\n<li>WordPress Application Passwords support (built-in since WP 5.6)<\/li>\n<\/ul>\n\n<h3>Support &amp; Contribution<\/h3>\n\n<p>For issues, feature requests, or contributions, visit the plugin repository.<\/p>\n\n<p>Questions? Check the FAQ section or look for documentation in the plugin settings page.<\/p>\n\n<h3>Development<\/h3>\n\n<p>This plugin follows WordPress coding standards and best practices:\n- PHP 7.4+ compatible\n- Full object-oriented architecture\n- Secure nonce verification\n- Proper capability checks\n- Sanitized input validation\n- Escaped output<\/p>\n\n<h3>License<\/h3>\n\n<p>This plugin is licensed under the GPL-2.0-or-later license. See LICENSE file for details.<\/p>\n\n<h3>Credits<\/h3>\n\n<p>MCP Manager is built with:\n- WordPress native APIs\n- Automattic's MCP WordPress Remote package\n- WordPress Application Passwords system<\/p>\n\n<p>Developed with \u2764\ufe0f for the WordPress community.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin directory to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress<\/li>\n<li>Navigate to Settings \u2192 MCP Manager to configure<\/li>\n<\/ol>\n\n<p>Or:<\/p>\n\n<ol>\n<li>Go to Admin \u2192 Plugins \u2192 Add New<\/li>\n<li>Search for \"MCP Manager\"<\/li>\n<li>Click \"Install Now\" then \"Activate\"<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20my%20password%20secure%3F\"><h3>Is my password secure?<\/h3><\/dt>\n<dd><p>Yes! MCP Manager uses WordPress's native Application Passwords system. Each password is:\n- Generated using WordPress's secure methods\n- Associated with your user account\n- Visible in your profile for management\n- Revocable at any time<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20with%20multiple%20mcp%20clients%3F\"><h3>Can I use this with multiple MCP clients?<\/h3><\/dt>\n<dd><p>Yes! You can generate separate passwords for each client (VS Code, Claude, GitHub Copilot, ChatGPT, and any custom client).<\/p><\/dd>\n<dt id=\"where%20are%20my%20application%20passwords%20saved%3F\"><h3>Where are my application passwords saved?<\/h3><\/dt>\n<dd><p>All application passwords are managed through WordPress's native Application Passwords system. View and manage them at:\nUser Profile \u2192 Account Management \u2192 Application Passwords<\/p><\/dd>\n<dt id=\"what%20mcp%20clients%20are%20supported%3F\"><h3>What MCP clients are supported?<\/h3><\/dt>\n<dd><ul>\n<li>Visual Studio Code (with Copilot)<\/li>\n<li>Anthropic Claude Desktop App<\/li>\n<li>GitHub Copilot<\/li>\n<li>OpenAI ChatGPT Codex<\/li>\n<li>Any custom MCP client supporting the standard format<\/li>\n<\/ul><\/dd>\n<dt id=\"can%20i%20revoke%20a%20password%3F\"><h3>Can I revoke a password?<\/h3><\/dt>\n<dd><p>Yes! You can revoke any application password from your profile page under Account Management \u2192 Application Passwords.<\/p><\/dd>\n<dt id=\"is%20this%20compatible%20with%20multisite%3F\"><h3>Is this compatible with multisite?<\/h3><\/dt>\n<dd><p>Yes! MCP Manager works with WordPress multisite installations. Each site can be configured independently.<\/p><\/dd>\n<dt id=\"do%20i%20need%20to%20install%20additional%20software%3F\"><h3>Do I need to install additional software?<\/h3><\/dt>\n<dd><p>No additional software is needed on the WordPress side. Your MCP clients (VS Code extension, Claude app, etc.) handle the integration.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.1.5<\/h4>\n\n<ul>\n<li><strong>Feature 031 \u2014 Add Google Gemini CLI as a supported MCP client.<\/strong> The server-edit Clients tab now surfaces a Gemini card (\ud83d\udc8e pill) alongside the existing 7. Uses the same npx <code>@automattic\/mcp-wordpress-remote@latest<\/code> bridge + WP Application Password Basic auth as Claude Desktop \/ Cursor \/ other stdio-based clients; config paste target is <code>~\/.gemini\/settings.json<\/code> under the standard <code>mcpServers<\/code> key. <code>GeminiClient<\/code> is a near-verbatim mirror of <code>ClaudeDesktopClient<\/code> (slug <code>gemini<\/code>, name <code>Gemini CLI<\/code>, byte-for-byte identical <code>get_config_snippet<\/code> shape) \u2014 no new auth mechanism, no new abstraction, no new render path. Registered in <code>MCPClientsBlock::$default_classes<\/code> + <code>CLIENT_META['gemini']<\/code>. Test suite canary bumped from 7 \u2192 8 concrete clients; <code>mcpclients<\/code> PHPUnit suite now runs 74 tests \/ 124 assertions (up from 67\/111 pre-F031).<\/li>\n<li><strong>Assets \u2014 Refreshed WordPress.org plugin-directory banners<\/strong> (1544\u00d7500 + 772\u00d7250 PNGs in <code>.wordpress-org\/<\/code>). No code change; visual update only.<\/li>\n<li><strong>Internal: <code>ACROSSAI_MCP_MANAGER_VERSION<\/code> constant bumped to <code>0.1.5<\/code> matching the plugin header.<\/strong><\/li>\n<\/ul>\n\n<h4>0.1.4<\/h4>\n\n<ul>\n<li><strong>Feature 030 \u2014 Per-server ability permission_callback override.<\/strong> The MCP-server-edit \"Access Control\" tab now hosts a second section (below the existing wpb-access-control React panel, separated by <code>&lt;hr&gt;<\/code>) with a single toggle: when enabled, every ability exposed to this MCP server via the Abilities tab bypasses its own <code>permission_callback<\/code> for MCP requests routed to this server. Site-wide ability callers (WP admin, non-MCP REST namespaces, WP-CLI) see the original <code>permission_callback<\/code> unchanged \u2014 the closure short-circuits when <code>CurrentServerHolder<\/code> is empty. Runtime filter registers on <code>wp_register_ability_args<\/code> at priority <code>999999<\/code>, strictly higher than sibling <code>acrossai-abilities-manager<\/code>'s P100000 injector and this plugin's own <code>CallbackReplacer<\/code> P10, so the operator toggle wins deterministically. Gated by six defensive layers documented in <code>DEC-F030-PERMISSION-CALLBACK-OPERATOR-OPT-IN-BYPASS<\/code>: <code>manage_options<\/code> capability + per-server nonce (<code>acrossai_mcp_manager_permission_override_{server_id}<\/code>) + persistent warning banner when ON + native <code>confirm()<\/code> prompt on submit-to-ON + <code>CurrentServerHolder<\/code> scope + <code>ExposureResolver::resolve()<\/code> gate. Adds one column via D28 3-part BerlinDB contract (<code>MCPServer\\Table<\/code> <code>1.1.1 \u2192 1.1.2<\/code> + <code>upgrade_to_1_1_2<\/code> callback, idempotent per <code>INFORMATION_SCHEMA.COLUMNS<\/code>). Fires new observability action <code>acrossai_mcp_permission_override_toggled( $server_id, $value, $user_id, $timestamp )<\/code> on every save \u2014 operators can attach any logger (Query Monitor, custom audit table, syslog) without a hard dependency. Also adds a promotional card for the sibling <code>acrossai-abilities-manager<\/code> plugin (already in <code>acrossai-co\/main-menu<\/code>'s baseline addon list \u2014 no double-register) with links to install\/activate via the shared Add-ons page or edit abilities when active, plus a <code>&lt;details&gt;<\/code> \"Prefer to use code?\" fallback documenting the filter name + priority for developers who prefer not to install another plugin.<\/li>\n<li><strong>Feature 030 (bonus) \u2014 Test-infrastructure fix.<\/strong> <code>tests\/phpunit\/{Abilities,Database,MCP}\/<\/code> were orphaned in <code>phpunit.xml.dist<\/code> \u2014 no suite covered them, so CI never ran F011\/F017\/F026 legacy tests OR any F030 new tests. Fixed by adding 3 new PHPUnit suites (<code>abilities<\/code>, <code>database<\/code>, <code>mcp<\/code>) + 3 matching CI workflow steps in <code>.github\/workflows\/phpunit.yml<\/code>. All previously-orphaned tests + all F030 new tests now execute in CI on every push.<\/li>\n<li><strong>Feature 030 \u2014 Durable memory captured.<\/strong> Five new entries in <code>docs\/memory\/<\/code>: <code>D29<\/code> (six-layer defensive gating framework for any future <code>permission_callback<\/code> bypass \u2014 scoped carve-out from <code>D24<\/code>), <code>D30<\/code> (F030 intentionally passes empty <code>$meta<\/code> to <code>ExposureResolver::resolve()<\/code> \u2014 scoped carve-out from <code>DEC-ABILITY-OVERRIDE-RESOLUTION<\/code>), <code>B35<\/code> (<code>wp_register_ability_args<\/code> filter-priority slot map: P10 CallbackReplacer, P100000 sibling, P999999 F030), <code>B36<\/code> (inline <code>&lt;script&gt;<\/code> string-interpolation requires <code>wp_json_encode()<\/code>, not <code>esc_html<\/code>\/<code>esc_attr<\/code> \u2014 generalizable JS-context escaping rule), <code>DEV5<\/code> (per-server-edit tab hand-rolled admin form exception to \u00a7IV DataForm mandate per D13 escalation \u2265 2 features).<\/li>\n<li><strong>Internal: <code>ACROSSAI_MCP_MANAGER_VERSION<\/code> constant bumped to <code>0.1.4<\/code> matching the plugin header.<\/strong><\/li>\n<\/ul>\n\n<h4>0.1.3<\/h4>\n\n<ul>\n<li><strong>Feature 029 (OAuth) \u2014 RFC 6749 \u00a72.3.1 HTTP Basic auth accepted on <code>\/token<\/code> + <code>client_secret_post<\/code> softening.<\/strong> <code>TokenController<\/code> now parses <code>Authorization: Basic base64(client_id:client_secret)<\/code> with CGI fallback (<code>REDIRECT_HTTP_AUTHORIZATION<\/code>) and applies header-first-then-body credential resolution to both <code>authorization_code<\/code> and <code>refresh_token<\/code> grants. When a client registered as <code>client_secret_post<\/code> submits NO secret at exchange (header AND body both empty), the endpoint now falls through to PKCE-only verification instead of hard-rejecting with <code>invalid_client<\/code>. Modern MCP hosts (Claude.ai, ChatGPT, Cursor, Cline) frequently register as <code>client_secret_post<\/code> but behave as public+PKCE at exchange; the softening keeps them interoperable. Confidential clients that DO send a secret are still verified via constant-time <code>ClientRepository::verify_secret<\/code> (unchanged). Codified as durable decision <code>D27<\/code>. Residual risk bounded by mandatory PKCE S256 + RFC 8707 audience binding + single-use auth codes + refresh-family revocation.<\/li>\n<li><strong>Feature 029 (OAuth) \u2014 DCR-registered clients now attributed to their connector profile at registration time.<\/strong> <code>ClientRegistrationController::handle_register()<\/code> walks <code>ConnectorProfileRegistry::get_profiles()<\/code> and calls <code>matches_dcr_client( $client_name, $redirect_uris )<\/code> on each \u2014 first matching profile's slug is persisted as <code>connector_slug<\/code> (previously always empty). Fixes F024's per-connector settings gate: DCR-registered clients (Claude.ai etc.) that previously bypassed the operator's enable\/disable toggle now honor it correctly. Bug pattern captured as <code>B33<\/code> (admin-gate silent-bypass on data-field left empty).<\/li>\n<li><strong>Feature 029 (DB) \u2014 BerlinDB schema-drift reconciliation for <code>wp_acrossai_mcp_cli_auth_logs<\/code> + <code>wp_acrossai_mcp_servers<\/code>.<\/strong> Two live tables had drifted from their <code>Schema.php<\/code> while stored <code>db_version<\/code> still matched code \u2014 <code>parent::maybe_upgrade()<\/code> short-circuited forever, and any INSERT referencing a Schema column missing from the actual table returned <code>false<\/code>, which callers cast to <code>int(0)<\/code> and treated as success (silent write-loss; identical shape took down Claude OAuth on <code>procureco.uk<\/code> before F029). Bumps <code>CliAuthLog\\Table<\/code> <code>1.0.0<\/code> \u2192 <code>1.0.1<\/code> (adds <code>upgrade_to_1_0_1<\/code> callback that ALTER MODIFYs <code>status<\/code> <code>varchar(20)<\/code> \u2192 <code>varchar(32)<\/code>, <code>failure_code<\/code> <code>varchar(100)<\/code> \u2192 <code>varchar(64)<\/code>, <code>app_password_uuid<\/code> <code>varchar(64)<\/code> \u2192 <code>varchar(36)<\/code>) and <code>MCPServer\\Table<\/code> <code>1.1.0<\/code> \u2192 <code>1.1.1<\/code> (adds <code>upgrade_to_1_1_1<\/code> callback that ALTER ADD COLUMN for the three F025 protocol flags <code>tool_discover_abilities<\/code>, <code>tool_get_ability_info<\/code>, <code>tool_execute_ability<\/code>). Both callbacks idempotent per-column via <code>INFORMATION_SCHEMA<\/code> existence\/width check. Codified as <code>D28<\/code> (BerlinDB <code>$upgrades<\/code> reconciliation pattern) + <code>B34<\/code> (silent write-loss bug pattern).<\/li>\n<li><strong>Feature 029 (Boot) \u2014 <code>Main::reconcile_database_schemas()<\/code> on <code>admin_init@3<\/code>.<\/strong> New Loader-wired admin hook fires <code>maybe_upgrade()<\/code> on all 7 BerlinDB Tables on every admin request. Before F029, <code>maybe_upgrade()<\/code> only ran from <code>Activator::activate()<\/code> \u2014 activation runs once, so version bumps on in-place upgrades (composer \/ wp-cli plugin update \/ manual file replace) stayed inert until deactivate + reactivate. Priority 3 fires BEFORE <code>Settings::maybe_seed_default_server<\/code> (4) and <code>Settings::handle_actions<\/code> (5) so schema is reconciled before any handler reads from these tables. Per-admin-request cost: 7 option reads (needs_upgrade short-circuits when versions match).<\/li>\n<li><strong>Internal: <code>ACROSSAI_MCP_MANAGER_VERSION<\/code> constant bumped to <code>0.1.3<\/code> matching the plugin header.<\/strong><\/li>\n<\/ul>\n\n<h4>0.1.2<\/h4>\n\n<ul>\n<li><strong>Feature 027 \u2014 Fix: DCR <code>token_endpoint_auth_method<\/code> default flipped to <code>none<\/code> for public+PKCE clients.<\/strong> <code>ClientRegistrationController::handle_register()<\/code> (<code>includes\/OAuth\/ClientRegistrationController.php:310<\/code>) previously defaulted the RFC 7591 Dynamic Client Registration <code>token_endpoint_auth_method<\/code> field to <code>client_secret_post<\/code> when the caller omitted it. Modern MCP hosts (Claude.ai, ChatGPT, Cursor, Cline) register as public+PKCE clients \u2014 they omit the field in DCR and never carry a <code>client_secret<\/code> through the <code>\/token<\/code> exchange. The old default silently stored these clients as confidential; the follow-up authorization-code exchange then failed at <code>TokenController::handle_authorization_code()<\/code> (<code>includes\/OAuth\/TokenController.php:106-111<\/code>) with <code>invalid_client<\/code> HTTP 401 <em>after<\/em> the auth code had already been consumed atomically at <code>AuthCodeRepository::consume_atomic<\/code> line 89 \u2014 so the client saw a generic \"Authorization failed\" page with no ability to retry. Default now flips to <code>none<\/code>, matching RFC 8252 \u00a78.4 for public+PKCE clients. Confidential-client callers can still pass <code>token_endpoint_auth_method=client_secret_post<\/code> explicitly in the DCR body; admin-generated clients at <code>handle_admin_generate<\/code> are unaffected (they continue to hardcode <code>client_secret_post<\/code>). New phpunit case <code>test_omitted_auth_method_defaults_to_none_public_client<\/code> in <code>tests\/phpunit\/OAuth\/DCRRegisterFreshTest.php<\/code> locks the invariant.<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li><strong>Feature 028 \u2014 Retire Freemius integration; consume <code>acrossai-co\/main-menu<\/code> 0.0.22+ filter-driven Add-ons page.<\/strong> The bundled <code>freemius\/wordpress-sdk<\/code> transitive dependency is dropped entirely (vendor removed it from <code>acrossai-co\/main-menu<\/code> 0.0.22's <code>require<\/code> block along with the <code>AcrossAI_Addon\\<\/code> PSR-4 namespace). This plugin's Freemius integration in <code>Main::define_admin_hooks()<\/code> \u2014 the <code>\\AcrossAI_Addon\\AddonsPage<\/code> instantiation with <code>fs_product_id =&gt; '34418'<\/code> \/ <code>fs_public_key<\/code> \/ <code>fs_slug =&gt; 'acrossai-add-ons'<\/code> \/ <code>fs_menu<\/code> \/ <code>fs_has_addons<\/code> config, its <code>class_exists<\/code>+<code>try\/catch<\/code> guards, and its admin-notice fallback closure \u2014 is removed in full (94 lines). No opt-in card, no <code>api.freemius.com<\/code> outbound requests, no umbrella-product license state. Bumps <code>acrossai-co\/main-menu<\/code> <code>0.0.18<\/code> \u2192 <code>0.0.23<\/code>.<\/li>\n<li><strong>New consumer self-exclusion filter.<\/strong> A new singleton <code>admin\/Partials\/AddonsFilter<\/code> hooks the vendor's <code>acrossai_addons<\/code> filter and drops the entry with <code>slug === 'acrossai-mcp-manager'<\/code> from the array \u2014 an already-active plugin should not advertise itself as an installable add-on on the shared Add-ons page. Codified as <code>D26 \/ DEC-CONSUMER-SELF-EXCLUSION-VIA-VENDOR-FILTER<\/code> (paired with <code>D20<\/code> on the subtractive side). Every future AcrossAI plugin whose slug appears in <code>AddonsPageRenderer::ADDONS<\/code> MUST ship the same pattern.<\/li>\n<li><strong>User-visible behavior change: the AcrossAI \u2192 Add-ons submenu no longer renders from this plugin.<\/strong> The Add-ons submenu is now rendered by whichever consumer of <code>acrossai-co\/main-menu<\/code> 0.0.22+ activates first. If this plugin is the only AcrossAI plugin active on an install, the Add-ons submenu disappears until a companion plugin activates.<\/li>\n<li><strong>Related durable memory flipped to Superseded (F028):<\/strong> <code>DEC-ADDONS-PAGE-VENDOR-CTOR-BOOT<\/code> (external-package self-registering-in-constructor exception to A1 \u2014 obsolete because <code>\\AcrossAI_Addon\\AddonsPage<\/code> no longer exists), <code>DEC-FREEMIUS-DOUBLE-OPTIN-GATES-ACCOUNT<\/code> (opt-in state-machine diagnosis \u2014 no live surface here anymore), and <code>B28<\/code> (Freemius two-level <code>menu.&lt;key&gt;<\/code> + <code>has_&lt;key&gt;<\/code> enablement pattern \u2014 SDK is gone). Entry bodies retained per PATTERN-MEMORY-SUPERSESSION-VS-ANNOTATION.<\/li>\n<li><strong>Internal: <code>ACROSSAI_MCP_MANAGER_VERSION<\/code> constant resynced.<\/strong> Drifted at <code>0.0.9<\/code> across the 0.1.0 release; now correctly reads <code>0.1.1<\/code> matching the plugin header.<\/li>\n<li><strong>Operator recipe for prior installs (optional cleanup):<\/strong> Freemius' SDK previously wrote <code>fs_accounts<\/code>, <code>fs_active_plugins<\/code>, <code>fs_api_cache<\/code>, <code>fs_cache_*<\/code>, and <code>fs_debug_mode<\/code> rows to <code>wp_options<\/code>. Nothing this plugin loads reads or writes them post-F028. To purge: <code>DELETE FROM wp_options WHERE option_name LIKE 'fs_%';<\/code>. The plugin does NOT ship this as an automatic migration (per <code>D21<\/code> fresh-install-only retirement pattern established by F016).<\/li>\n<\/ul>\n\n<h4>0.1.6<\/h4>\n\n<ul>\n<li><p><strong>Feature 032 \u2014 OAuth per-server scoping (SECURITY FIX + BREAKING CHANGE for legacy DCR sessions).<\/strong><\/p>\n\n<p>\u26a0\ufe0f <strong>BEFORE UPGRADE \u2014 READ THIS<\/strong>: this release deletes any pre-F032 DCR-registered OAuth client rows (those without a <code>server-{id}-<\/code> prefix \u2014 e.g., legacy Claude.ai \/ ChatGPT \/ Cursor \/ Cline connections) and their associated tokens + auth codes as part of the D28 upgrade migration. Any live AI-host session bound to a legacy DCR row will disconnect on the next request; affected users must re-run the OAuth authorize flow from their AI host to reconnect. All post-F032 DCR registrations are per-server and unaffected. Consider (a) snapshotting <code>wp_acrossai_mcp_oauth_{clients,tokens,auth_codes}<\/code> before upgrade, and (b) notifying users with active AI-host connections that they will need to re-authorize once after upgrade.<\/p>\n\n<p><strong>Security fix<\/strong>: closes a cross-server privilege-escalation gap where an admin on Server A's Connectors tab could revoke or delete Server B's clients + tokens by modifying the <code>client_id<\/code> in the outbound REST body. Also closes a read-side display leak in the \"authorized users\" listing on the AI Connectors tab.<\/p>\n\n<p><strong>What ships<\/strong>: adds <code>server_id BIGINT UNSIGNED NOT NULL<\/code> column (final state) to <code>wp_acrossai_mcp_oauth_clients<\/code>, <code>wp_acrossai_mcp_oauth_tokens<\/code>, and <code>wp_acrossai_mcp_oauth_auth_codes<\/code> via the D28 3-part BerlinDB <code>$upgrades<\/code> contract (each Table bumps <code>$version<\/code> 1.0.0 \u2192 1.0.1 with matching <code>upgrade_to_1_0_1()<\/code> callback). Replaces standalone <code>UNIQUE(client_id)<\/code> on <code>oauth_clients<\/code> with composite <code>UNIQUE(client_id, server_id)<\/code> so the same DCR connector can be registered on multiple MCP servers as independent rows. Every mutating REST endpoint (<code>revoke-client-tokens<\/code>, <code>delete-client<\/code>, <code>revoke-connector-tokens<\/code>) now requires + validates <code>server_id<\/code> in the body \u2014 mismatch returns 403 <code>acrossai_mcp_oauth_cross_server<\/code> AND fires <code>do_action( 'acrossai_mcp_oauth_cross_server_attempted', $client_id, $server_id_requested, $user_id, $timestamp )<\/code> (4-arg signature \u2014 intentionally does NOT disclose the actual owning server_id to listeners, per SEC-032-001 remediation). DCR endpoint now requires resolvable RFC 8707 <code>resource<\/code> parameter with mandatory origin verification against <code>home_url()<\/code> (rejects attacker-origin URLs with 400 <code>invalid_target<\/code> + fires <code>acrossai_mcp_oauth_dcr_resource_url_origin_mismatch<\/code>). DCR endpoint also gates against a rare deploy\u2192migration race window with 503 <code>service_unavailable<\/code> when <code>server_id<\/code> column is absent (prevents silent destruction of legitimate registrations by the auto-purge step). Backfill of admin clients from <code>server-{id}-<\/code> prefix includes an orphan-server guard (parsed server_id must exist in <code>wp_acrossai_mcp_servers<\/code>; otherwise row left NULL and purged alongside legacy DCR rows). Fires <code>do_action( 'acrossai_mcp_oauth_legacy_dcr_purged', $clients_deleted, $tokens_deleted, $auth_codes_deleted )<\/code> exactly once per upgrade run for operator observability. <code>UserLifecycle::on_user_deleted()<\/code> cascade preserved unchanged (site-wide per FR-042 \u2014 regression-tested).<\/p>\n\n<p><strong>F032 extended scope (folded in-branch)<\/strong>: new BerlinDB module <code>wp_acrossai_mcp_connector_approved_users<\/code> promotes admin-approval state from serialized wp_options to a first-class relational table (FR-029); new \"Approved Users\" admin panel (FR-046..FR-048) surfaces between Connections and Settings when <code>require_admin_approval<\/code> is enabled; new revoke-approval \u2192 token-revoke cascade wired via <code>acrossai_mcp_connector_user_approval_revoked<\/code> action with opt-out filter <code>acrossai_mcp_connector_revoke_tokens_on_approval_revoked<\/code> (FR-040\/FR-041); new \"Revoke from all servers\" nuclear button (FR-043 \u2014 deliberate D31 carve-out, fires <code>acrossai_mcp_oauth_client_revoked_across_all_servers<\/code> NEVER <code>acrossai_mcp_oauth_cross_server_attempted<\/code>); Access Control connection-time gate now enforces at OAuth authorize + CLI device-grant + Application Password generation (FR-049) so denied users see immediate <code>access_denied<\/code> instead of confusing \"connected then silent 403\" behavior; annotated token counts (<code>2 (1 access \u00b7 1 refresh)<\/code>) replace opaque totals in Connections panel (FR-045); enriched AC 403 with <code>server_slug<\/code> + <code>user_roles<\/code> (FR-050).<\/p>\n\n<p><strong>Admins bypass <code>require_admin_approval<\/code> (FR-051)<\/strong>: users with <code>manage_options<\/code> capability skip the pending-approval queue entirely and are auto-added to the Approved Users list on first connection with <code>approved_by = $user_id<\/code> (self-approval). Rationale: admins can approve themselves in one click from the Approved Users panel anyway; the pending detour is UX friction, not a security boundary. Effective threat model unchanged (admins already have <code>manage_options<\/code>, a strict superset of any approval decision they could make on themselves). The Settings-panel description under \"Require admin approval for new connections\" includes an inline note explaining this so operators are not confused when they connect as admin and skip the queue.<\/p><\/li>\n<li><p><strong>Feature 022 \u2014 Shared AcrossAI Add-ons submenu.<\/strong> The plugin now registers the shared \"Add-ons\" nav entry under the AcrossAI top-level menu, powered by Freemius for product id 34418. The page requires <code>install_plugins<\/code>; when a companion AcrossAI plugin is active simultaneously only one plugin contributes the nav entry (the shared package coordinates this so operators never see duplicate submenu rows). Bumps <code>acrossai-co\/main-menu<\/code> from <code>0.0.14<\/code> to <code>0.0.18<\/code>. <code>0.0.15<\/code> enabled the Freemius <strong>Account<\/strong>, <strong>Contact Us<\/strong>, and <strong>wp.org Support Forum<\/strong> submenus at package level; <code>0.0.16<\/code> promotes those defaults to <code>FreemiusInitializer::DEFAULT_MENU<\/code> and introduces a new <code>fs_menu<\/code> key on <code>AddonsPage<\/code>'s <code>$args<\/code> array so each consumer plugin explicitly decides which auto-submenus surface. <code>0.0.17<\/code> disables the vendor's own <code>MenuRegistrar::register()<\/code> \u2014 Freemius's <code>menu.addons<\/code> submenu (enabled here via <code>fs_menu.addons = true<\/code>) is now the sole source of the Add-ons row, per the AcrossAI \"umbrella product\" model where Freemius product <code>34418<\/code> (<code>acrossai-add-ons<\/code>) owns the single ecosystem-wide Add-ons page. <code>0.0.18<\/code> adds an <code>fs_has_addons<\/code> key on <code>AddonsPage<\/code>'s <code>$args<\/code> \u2014 Freemius' SDK gates the Add-ons row on <code>if ( $this-&gt;has_addons() )<\/code> (class-freemius.php:18964), so <code>menu.addons =&gt; true<\/code> alone was insufficient. The plugin now passes <code>fs_has_addons =&gt; true<\/code> explicitly, which forwards to <code>fs_dynamic_init()<\/code> and unblocks the Add-ons row. The plugin passes an explicit <code>fs_menu<\/code> array in <code>includes\/Main.php<\/code> declaring every key so the full menu policy is visible at the call site \u2014 flip any boolean there to change what operators see without a vendor release. Adds an explicit VCS repositories entry for <code>acrossai-co\/main-menu<\/code> in <code>composer.json<\/code> so consumers resolve deterministically from GitHub without waiting on Packagist sync.<\/p><\/li>\n<li><strong>Feature 021 \u2014 OAuth 2.1 + PKCE authorization server.<\/strong> Provider-agnostic OAuth 2.1 authorization server exposed at four domain-root endpoints (<code>\/.well-known\/oauth-authorization-server<\/code> per RFC 8414, <code>\/.well-known\/oauth-protected-resource<\/code> per RFC 9728, <code>\/authorize<\/code>, <code>\/token<\/code>) plus RFC 7591 Dynamic Client Registration at <code>\/wp-json\/acrossai-mcp-manager\/v1\/oauth\/register<\/code> and an admin-only credential generator at <code>\/wp-json\/acrossai-mcp-manager\/v1\/oauth\/generate-client<\/code>. PKCE S256 mandatory (plain rejected regardless of client claim). RFC 8707 <code>resource<\/code> parameter mandatory and enforced at call time \u2014 a token issued for one MCP server rejects when presented against a different server on the same site. RFC 9207 <code>iss<\/code> parameter emitted on authorization callbacks. Refresh-token rotation with <strong>family revocation on reuse detection<\/strong> (RFC 9700 \u00a72.2.2). Bearer authentication via a new <code>TokenValidator<\/code> on <code>determine_current_user @ 20<\/code> with 4-fallback header extraction and static recursion guard. New built-in per-server \"AI Connectors\" tab (priority 35) renders one card per registered <code>AbstractConnectorProfile<\/code> \u2014 companion plugins contribute Claude \/ ChatGPT \/ Gemini \/ Copilot profiles via the new <code>acrossai_mcp_manager_connector_profiles<\/code> filter; base plugin ships zero profiles. Four new observability actions: <code>_oauth_token_issued<\/code>, <code>_oauth_authorization_denied<\/code>, <code>_oauth_token_revoked<\/code>, <code>_oauth_cleanup<\/code>. Three new BerlinDB tables (<code>OAuthClients<\/code>, <code>OAuthTokens<\/code>, <code>OAuthAuthCodes<\/code>) \u2014 all with F011 phantom-version guard, SHA-256 hashes at rest, atomic single-use auth codes via <code>consume_atomic<\/code> (B10 pattern). Daily <code>acrossai_mcp_manager_oauth_cleanup<\/code> cron purges expired codes + expired-and-revoked tokens. WordPress user deletion cascades to token revocation + code deletion via <code>deleted_user @ 10<\/code>. Uninstall respects the existing <code>acrossai_mcp_uninstall_delete_data<\/code> opt-in gate. Zero new composer runtime dependencies.<\/li>\n<li><strong>Feature 020 \u2014 Per-server Tools tab.<\/strong> Pick which registered abilities each MCP server exposes as callable tools via a two-column shuttle picker on the Tools tab. Per-row Add \/ Remove, bulk Add all \/ Remove all, search, a running counter, an empty-state warning banner, and explicit Save changes \/ Cancel \u2014 pending edits stay local until the operator commits. Selection is stored in a new BerlinDB table <code>{prefix}acrossai_mcp_server_tools<\/code> (phantom-version self-heal). Enforcement is call-time via a new <code>mcp_adapter_pre_tool_call<\/code> callback at priority 30 that returns <code>403 acrossai_mcp_tool_not_added<\/code> for abilities not in the curated set; stacks after F015 access control (10) and F017 ability exposure (20) with deny-precedence. Server deletion cascades tool selections cleanly (hooks BerlinDB's native <code>mcp_server_deleted<\/code>). The three <code>mcp-adapter\/*<\/code> protocol tools remain built-in and are not configurable per server. Uninstall drops the table under the same opt-in gate as F011\/F017.<\/li>\n<li><strong>Feature 017 \u2014 Per-server ability selection.<\/strong> The Abilities tab on each MCP server is now interactive. Site administrators pick which registered WordPress abilities the server exposes to connected AI clients, with search, category + type filters, sortable columns, per-row toggle, and bulk Expose \/ Hide actions. Backed by a new <code>{prefix}acrossai_mcp_server_abilities<\/code> BerlinDB table (phantom-version self-heal guard). Backwards-compatible \u2014 servers with no explicit selection continue to expose abilities whose <code>meta[mcp][public]<\/code> is true. Enforcement is call-time (via a new <code>mcp_adapter_pre_tool_call<\/code> callback at priority 20 that returns <code>403 acrossai_mcp_ability_not_exposed<\/code> on hidden abilities); list-time hiding of hidden abilities from <code>mcp\/tools\/list<\/code> is a documented follow-up. The tab is extensible \u2014 companion plugins can add columns and per-row actions via three <code>@wordpress\/hooks<\/code> filters (<code>acrossaiMcpManager.abilities.{fields,actions,row}<\/code>) plus one PHP filter (<code>acrossai_mcp_ability_row<\/code>) \u2014 see <code>docs\/extending-abilities-tab.md<\/code>. All new hooks are marked <code>@experimental May change without notice before 1.0.0<\/code> per the F013 public-API precedent.<\/li>\n<li><strong>Feature 016 \u2014 Retired the Claude Connectors integration in full.<\/strong> The OAuth 2.1 authorization-server surface (well-known discovery URLs, <code>\/wp-json\/acrossai-mcp\/v1\/token<\/code> REST route, bearer-token acceptance on the <code>determine_current_user<\/code> filter, daily <code>acrossai_mcp_oauth_cleanup<\/code> cron, per-server Claude Connector admin tab, Settings \u2192 MCP toggle, <code>[acrossai_mcp_claude_connector_block]<\/code> shortcode, and the <code>frontend-oauth<\/code> CSS bundle) is fully removed. The feature never worked with claude.ai's hosted Connectors UI on local installs and has been retired to reduce attack surface. This release is compat-breaking on Claude-Connector-owned data only; every other MCP server row and setting is preserved. Net effect: ~4,000 lines of security-sensitive code removed, one fewer REST route, one fewer <code>determine_current_user<\/code> filter, no more OAuth discovery endpoints.<\/li>\n<li><p><strong>Operator action required for pre-016 installs.<\/strong> The plugin ships fresh-install-only \u2014 no in-plugin schema migration. Before reactivating the updated plugin on an install that had populated Claude Connector data, run this manual retirement recipe (SEC-016-001 defense-in-depth: the pre-DROP <code>UPDATE<\/code> forces the InnoDB tablespace to overwrite the plaintext <code>client_secret<\/code> bytes before the column is dropped):<\/p>\n\n<p>UPDATE wp_acrossai_mcp_servers SET\n    claude_connector_client_secret = '',\n    claude_connector_redirect_uri  = '';\nDROP TABLE IF EXISTS wp_acrossai_mcp_oauth_tokens;\nDROP TABLE IF EXISTS wp_acrossai_mcp_oauth_audit;\nALTER TABLE wp_acrossai_mcp_servers\n    DROP COLUMN claude_connector_client_id,\n    DROP COLUMN claude_connector_client_secret,\n    DROP COLUMN claude_connector_redirect_uri;\nDELETE FROM wp_options WHERE option_name IN (\n    'acrossai_mcp_oauth_tokens_db_version',\n    'acrossai_mcp_oauth_audit_db_version',\n    'acrossai_mcp_claude_connectors_enabled'\n);<\/p>\n\n<p>And one companion WP-CLI step to clear the retired daily cron: <code>wp cron event unschedule acrossai_mcp_oauth_cleanup<\/code>. If your install has any active claude.ai Connector tokens, revoke them from claude.ai's Connectors UI BEFORE running the retirement SQL \u2014 the retirement drops the audit log with no recovery.<\/p><\/li>\n<li><strong>Behavior change: <code>Authorization: Bearer<\/code> headers no longer elevate users.<\/strong> The Bearer resolver on the <code>determine_current_user<\/code> filter has been removed. Integrators relying on the retired path should migrate to WordPress Application Passwords via the CLI auth flow (<code>public\/Partials\/FrontendAuth<\/code>), which is untouched by this release.<\/li>\n<\/ul>\n\n<h4>0.0.9<\/h4>\n\n<ul>\n<li><strong>Fix: Claude Code MCP Clients tab now shows a JSON config block instead of a <code>claude mcp add<\/code> shell command.<\/strong> The <code>~\/.claude.json<\/code> config file path is displayed correctly (was incorrectly listed as <code>~\/.claude\/mcp_servers.json<\/code>), the snippet renders as a copy-pasteable <code>mcpServers<\/code> block with <code>command<\/code>\/<code>args<\/code>\/<code>env<\/code>, and the env now pins <code>OAUTH_ENABLED: \"false\"<\/code> alongside <code>WP_API_URL<\/code> \/ <code>WP_API_USERNAME<\/code> \/ <code>WP_API_PASSWORD<\/code> to keep the <code>@automattic\/mcp-wordpress-remote<\/code> client from falling into an OAuth branch it can't complete against an Application Password server. Instructions on the tab updated to match (\"paste under the top-level key\" \u2014 no more <code>claude mcp add-json<\/code>).<\/li>\n<li><strong>Internal: <code>ACROSSAI_MCP_MANAGER_VERSION<\/code> constant now tracks the plugin header.<\/strong> It had drifted at <code>0.0.6<\/code> across the 0.0.7 and 0.0.8 releases; this release resyncs it to <code>0.0.9<\/code>. Consumers reading the constant to key cache entries or telemetry will see a version bump even though there are no functional changes since 0.0.8 beyond the Claude Code tab fix above.<\/li>\n<li><strong>Tests: repair 14 stale JSON fixtures.<\/strong> The <code>ConcreteClientsTest<\/code> golden fixtures for <code>claude-desktop<\/code>, <code>vscode<\/code>, <code>github-copilot<\/code>, <code>codex<\/code>, <code>cursor<\/code>, and <code>custom<\/code> were missing the <code>WP_API_USERNAME<\/code> env field that all 6 clients have emitted since Feature 004. Adding the field brings fixtures back in sync with the code \u2014 49\/49 tests now pass (was 35\/49).<\/li>\n<\/ul>\n\n<h4>0.0.8<\/h4>\n\n<ul>\n<li>Dependencies: bump <code>acrossai-co\/main-menu<\/code> to <code>0.0.11<\/code>.<\/li>\n<\/ul>\n\n<h4>0.0.7<\/h4>\n\n<ul>\n<li>Docs: rewrite README.txt from the canonical baseline (proper Description, FAQ, Screenshots, install steps).<\/li>\n<li>Docs: fix wp.org import warnings \u2014 real Contributors (<code>raftaar1191<\/code>), plugin-relevant Tags (<code>mcp, ai, copilot, vscode, claude<\/code>), and a Short Description tagline.<\/li>\n<li>Header: refresh plugin header \u2014 Plugin URI <code>https:\/\/acrossai.co\/<\/code>, Author <code>raftaar1191<\/code>, wp.org profile Author URI, License normalized to <code>GPL-2.0-or-later<\/code>.<\/li>\n<li>Build: expand <code>.distignore<\/code> to exclude tooling \/ config \/ docs \/ tests \/ editor dirs from the wp.org build. <code>.gitignore<\/code> cleaned up.<\/li>\n<li>CI: add GitHub Actions workflows for PHPStan, PHPCompatibility, PHPUnit (mcpclients suite), PHPCS, build-zip, and wp.org deploy.<\/li>\n<li>Requirements: bump minimums to WordPress 7.0 \/ PHP 8.1.<\/li>\n<\/ul>\n\n<h4>0.0.6<\/h4>\n\n<ul>\n<li>Migrated the four internal DB modules (MCP Servers, CLI Auth Log, OAuth Tokens, OAuth Audit) to BerlinDB Core 3.0. Fresh installs create tables with BerlinDB-derived schemas; the phantom-version guard on every Table subclass silently self-heals a stamped-but-missing table on the next activation. This release ships to zero live installs \u2014 no data migration path is provided; sites with pre-migration schema must be recreated from scratch.<\/li>\n<li>Added an \"MCP\" tab to the shared AcrossAI Settings page (?page=acrossai-settings) with three operator toggles: enable CLI connections (acrossai_mcp_npm_login_enabled), enable direct Claude Connectors mode (acrossai_mcp_claude_connectors_enabled), and Delete all data on uninstall (acrossai_mcp_uninstall_delete_data). Sibling to acrossai-abilities-manager's Abilities tab.<\/li>\n<li>BEHAVIOR CHANGE: uninstall.php now preserves ALL plugin data by default. The pre-Feature-012 build dropped acrossai_mcp_oauth_tokens + acrossai_mcp_oauth_audit unconditionally; this build preserves every wp_acrossai_mcp_* table and every acrossai_mcp_* option unless the operator explicitly ticks the \"Delete all data on uninstall\" checkbox on the MCP settings tab and saves. Sites that expected the pre-Feature-012 OAuth-table wipe on uninstall must tick the new checkbox before uninstall.<\/li>\n<li>Removed the standalone \"CLI Auth Log\" admin submenu at ?page=acrossai_mcp_manager_cli_auth_log. The underlying wp_acrossai_mcp_cli_auth_logs table + Query\/Row classes remain \u2014 they continue to power the OAuth authentication flow. Auth-log inspection is now available via WP-CLI (wp db query \"SELECT ... FROM wp_acrossai_mcp_cli_auth_logs\"); the standalone submenu was redundant post-Feature-011.<\/li>\n<li>Refactored the per-server-edit page (?page=acrossai_mcp_manager&amp;action=edit) into a per-tab class hierarchy under admin\/Partials\/ServerTabs\/. Ported 7 additional tabs from the reference plugin (Overview, npm, MCP Clients, WP-CLI, Tools, Abilities, MCP Tracker) plus 2 database-registered-only tabs (Update Server, Danger Zone). The full 11-tab UI is now available for database-registered servers; plugin-registered servers see 9 tabs.<\/li>\n<li>NEW: Public Renderer layer under public\/Renderers\/ exposes 3 client-configuration blocks (npm, MCP Clients, Claude Connector) as a reusable API so third-party plugins (BuddyBoss, WooCommerce, other AcrossAI-family plugins) can embed the same UI on their own admin or frontend surfaces with zero code duplication. Public API surface: static Renderer::render() method + acrossai_mcp_render_client_block action hook + acrossai_mcp_client_block_context filter + acrossai_mcp_client_classes filter + shortcodes ([acrossai_mcp_npm_block], [acrossai_mcp_clients_block], [acrossai_mcp_claude_connector_block]) + REST endpoint (\/wp-json\/acrossai-mcp-manager\/v1\/generate-app-password) with defense-in-depth Application Password lockdown to get_current_user_id(). API is @experimental May change without notice before 1.0.0 (per DEC-CLIENT-RENDERER-PUBLIC-API). Restored CliAuthLogListTable + added ConnectorAuditLogListTable as per-server tab inspectors under DEC-ADMIN-SURFACE-PRUNE-CLI-AUTH-LOG's blessed reintroduction path. See docs\/integrations\/buddyboss-example.md and docs\/integrations\/woocommerce-example.md for third-party integrator onboarding.<\/li>\n<li>Adopted wpboilerplate\/wpb-access-control v2 with per-server access rules, MCP-boundary enforcement via the mcp_adapter_pre_tool_call filter shipped by wordpress\/mcp-adapter, and a shared Renderer block (AccessControlBlock) that third-party plugins can embed on their own admin surfaces. Fixes 3 fatal v1-API call sites (AccessControlTab.php, CliController.php \/servers route, Main.php TODO block). Activator now creates the {prefix}mcp_manager_access_control table; uninstall opt-in gate purges the namespace + drops the table + deletes the version option. Two observability action hooks let operators log denials via any listener: <code>acrossai_mcp_access_control_denied<\/code> fires immediately before returning WP_Error \/ empty server list on deny (args: user_id, server_slug, tool_name-or-null, context_slug where context_slug is <code>'cli_servers'<\/code> at CliController or <code>'mcp_tool_call'<\/code> at MCP boundary); <code>acrossai_mcp_access_control_missing_server<\/code> fires when a server was DELETEd mid-flight (args: server_slug, tool_name, user_id). Minimal listener example: <code>add_action('acrossai_mcp_access_control_denied', function($u,$s,$t,$c){ error_log(\"[AC deny] user=$u server=$s tool=$t via=$c\"); }, 10, 4);<\/code>. See DEC-ACCESS-CONTROL-V2-ADOPTION + D18 + D19 for the wrapper pattern, canonical MCP-boundary hook, and fail-open observability pattern.<\/li>\n<\/ul>\n\n<h4>0.0.5<\/h4>\n\n<ul>\n<li>Changed: access-control admin UI now loads assets from the wpb-access-control vendor package's own compiled React bundle; removed plugin-bundled copies at assets\/access-control\/<\/li>\n<li>Changed: replace AccessControlUI AJAX bootstrap with REST API registration via AccessControlManager::register_rest_api(); rules are now served and saved via dedicated REST endpoints<\/li>\n<li>Changed: access-control tab renders a React component hydrated by the vendor webpack bundle instead of legacy plain-JS markup<\/li>\n<li>Added: graceful degradation notice when vendor assets are unavailable \u2014 enforcement remains active<\/li>\n<li>Updated: wpb-access-control to v1.0.0 (stable baseline); automattic\/jetpack-autoloader to latest minor<\/li>\n<\/ul>\n\n<h4>0.0.4<\/h4>\n\n<ul>\n<li>Improved: bundle access-control UI assets (CSS + JS) directly in the plugin at assets\/access-control\/ so the admin panel works regardless of whether the wpb-access-control vendor package ships them<\/li>\n<\/ul>\n\n<h4>0.0.3<\/h4>\n\n<ul>\n<li>Dependencies: update wpb-access-control to BerlinDB-backed version; add berlindb\/core; update bshaffer\/oauth2-server-httpfoundation-bridge and symfony\/deprecation-contracts<\/li>\n<li>Fixed: remove removed AccessControlTable references; fixes fatal error on plugin activation<\/li>\n<li>Fixed: access-control table is now auto-bootstrapped by RuleQuery \u2014 no manual maybe_create_table() needed<\/li>\n<li>Fixed: remove dead save_access_control POST handler; access-control saves now handled by library AJAX<\/li>\n<li>Fixed: update v1.5.0 legacy migration to use RuleQuery::set_rule() instead of removed AccessControlTable::update()<\/li>\n<\/ul>\n\n<h4>0.0.2<\/h4>\n\n<ul>\n<li>Security: sanitize and validate all $_GET\/$_POST inputs with sanitize_key(), sanitize_text_field(), absint(), and wp_unslash()<\/li>\n<li>Paths: replace hardcoded ABSPATH with get_home_path() for correct subdirectory-install support<\/li>\n<li>Enqueue: remove all inline \/ blocks; move to external CSS\/JS files loaded via wp_enqueue_style() and wp_enqueue_script()<\/li>\n<\/ul>\n\n<h4>0.0.1<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Support for VS Code, Claude, GitHub Copilot, ChatGPT Codex, and custom clients<\/li>\n<li>Format #1 (Automattic-recommended) MCP configuration<\/li>\n<li>Native WordPress Application Passwords integration<\/li>\n<li>Dynamic configuration generation per provider<\/li>\n<li>Full REST API support<\/li>\n<li>Admin UI with client tabs<\/li>\n<li>Copy-to-clipboard functionality<\/li>\n<\/ul>","raw_excerpt":"Connect WordPress to MCP clients like VS Code, Claude, and Copilot using secure application passwords.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/300297","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=300297"}],"author":[{"embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/raftaar1191"}],"wp:attachment":[{"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=300297"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=300297"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=300297"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=300297"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=300297"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/lmo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=300297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}