Beskrivning
MCP Manager connects your WordPress site to any MCP-compatible AI client — Claude, ChatGPT, Cursor, VS Code, GitHub Copilot, Gemini, and more — so those clients can safely read, edit, and act on your site.
Every headline section below links to the full documentation at acrossai.co/doc-category/mcp-manager — the docs are the source of truth and get updated first. Source and issues live at github.com/acrossai-co/acrossai-mcp-manager.
Key Features
- Multiple MCP servers per site — create, enable, disable, and configure independently. Docs
- Multi-client connection guides — copy-paste-ready configs for Claude Desktop, VS Code + Copilot, GitHub Copilot, ChatGPT, Cursor, Gemini CLI, and custom clients. Docs
- CLI browser-approval flow — let terminal users connect with one command; approval happens in a browser tab. Docs
- WP-CLI (STDIO) transport — local clients can connect through a WP-CLI subprocess with no network credential transmission. Docs
- Application Passwords under the hood — WordPress-native credentials, one-click generation, and revocation from the user profile page. Docs
- Per-server tool and ability curation — pick exactly which WordPress abilities each MCP server exposes as callable tools. Docs
- Per-server access control — gate every MCP request by user, role, capability, or your own policy provider. Docs
- Frontend embeds — shortcode + block to show your users how to connect their AI clients from your own site. Docs
How It Works
- Install and activate the plugin (step-by-step)
- Open AcrossAI MCP in your WordPress admin
- Pick your AI client tab (Claude, VS Code, ChatGPT, Cursor, Gemini, GitHub Copilot, or Custom)
- Generate a new Application Password with one click
- Copy the ready-made JSON config and paste it into your client
- Restart your client — it now sees your site’s abilities
Longer walkthrough with screenshots: Getting started connect your first AI client.
Connection Types
MCP Manager ships with three connection styles out of the box, plus one optional paid add-on:
- MCP Client (npx bridge) — the default. Paste a JSON config into Claude Desktop, VS Code, Cursor, etc. Uses
@automattic/mcp-wordpress-remote@latestwith a WordPress Application Password. Docs - CLI Connections (browser approval) — one command in the terminal, one click in the browser, zero password copying. Docs
- WP-CLI (STDIO) — local subprocess, no network credential transmission. Best for CI or local dev boxes. Docs
- AI Connectors (paid add-on) — one-click Claude, ChatGPT, and Grok hosted-OAuth connectors. Requires the separate AcrossAI AI Connectors plugin (14-day money-back). Docs
Requirements
- WordPress 7.0 or higher
- PHP 8.1 or higher
- WordPress Application Passwords support (built-in since WP 5.6)
Support
- Docs hub — acrossai.co/doc-category/mcp-manager
- Troubleshooting & FAQ — acrossai.co/docs/mcp-faq-troubleshooting
- Source code + issue tracker — github.com/acrossai-co/acrossai-mcp-manager
Support & Contribution
For issues, feature requests, or contributions, visit the plugin repository.
Questions? Check the FAQ section or look for documentation in the plugin settings page.
Development
This plugin follows WordPress coding standards and best practices:
– PHP 7.4+ compatible
– Full object-oriented architecture
– Secure nonce verification
– Proper capability checks
– Sanitized input validation
– Escaped output
License
This plugin is licensed under the GPL-2.0-or-later license. See LICENSE file for details.
Credits
MCP Manager is built with:
– WordPress native APIs
– Automattic’s MCP WordPress Remote package
– WordPress Application Passwords system
Developed with ❤️ for the WordPress community.
Skärmdumpar
Installation
- Upload the plugin directory to
/wp-content/plugins/ - Activate the plugin through the ’Plugins’ menu in WordPress
- Navigate to Settings MCP Manager to configure
Or:
- Go to Admin Plugins Add New
- Search for ”MCP Manager”
- Click ”Install Now” then ”Activate”
Vanliga frågor
Full FAQ + troubleshooting lives at acrossai.co/docs/mcp-faq-troubleshooting. Quick answers below.
-
Are my credentials secure?
-
Yes. MCP Manager uses WordPress’s native Application Passwords — each one is generated by WordPress, tied to your user, revocable from the profile page, and never stored in this plugin’s own tables. Full detail: Application passwords & security.
-
Can I connect multiple AI clients to the same site?
-
Yes — generate a separate password (or CLI approval) per client. You can also run multiple MCP servers on the same site with different tool/ability sets and per-server access rules. See MCP servers.
-
Which AI clients are supported?
-
Claude Desktop, ChatGPT, Cursor, VS Code (with Copilot), GitHub Copilot, Gemini CLI, and any custom MCP-compatible client. Adding a new client is a filter callback. See Connecting an AI client.
-
Does it work on multisite?
-
Yes — each site in the network configures independently.
-
Do I need the paid AI Connectors add-on?
-
Only if you want the one-click hosted-OAuth flow for Claude, ChatGPT, or Grok. All other connection styles (MCP Client, CLI, WP-CLI STDIO) are free and shipped with this plugin. See AI Connectors add-on.
Recensioner
Detta tillägg har inga recensioner.
Bidragsgivare och utvecklare
”AcrossAI MCP Manager” är programvara med öppen källkod. Följande personer har bidragit till detta tillägg.
Bidragande personerÖversätt ”AcrossAI MCP Manager” till ditt språk.
Intresserad av programutveckling?
Läs programkoden, kika på SVN-filförvaret eller prenumerera på utvecklarloggen via RSS.
Ändringslogg
0.2.4
- Dependencies — bump
wpboilerplate/wpb-access-control2.0.03.1.0. Two vendor changes surface in the per-server Access Control tab (?tab=access-control): (1) new ”Any logged-in user” option in the Who can access dropdown — backed by the newTYPE_AUTHENTICATEDsentinel inAccessControlManager(returnstrueiff$user_id > 0), and (2) the existing ”Everyone (no restriction)” option is relabelled ”Public (no login required)” — pure UI relabel, same underlying behavior (TYPE_EVERYONEunchanged, existing rules unaffected). v3.0.0 also removed the built-inBuddyBossProfileTypeProvider+MemberPressMembershipProvider(moved to a separateacrossai/user-access-proadd-on); this plugin never wired them into the Who can access dropdown, so removal has no visible effect here. Docblock atincludes/Main.phprefreshed to drop the stale BuddyBoss/MemberPress reference. No data migration required. - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant +Stable tagbumped to0.2.4matching the plugin header.
0.2.3
- UX — In-context nudges to install the AcrossAI Abilities Manager add-on. When the sibling
acrossai-abilities-managerplugin is not active, the server-edit Abilities and Tools tabs (?tab=abilities/?tab=tools) now surface a small WordPress-nativenotice-infoblock above the picker with a link to the shared Add-ons page (admin.php?page=acrossai-addons). Without the add-on both pickers only list the three core abilities WordPress ships by default (core/get-environment-info,core/get-site-info,core/get-user-info); the add-on registers a rich library of built-in abilities that populate both surfaces. Detection is a plainis_plugin_active()check — same message + same link covers both ”not installed” and ”installed-but-off” states. Placed after the existing ”Server is disabled” warning and before thewp_get_abilities()capability check, so the nudge is visible even when the abilities API itself is missing. - UI — AcrossAI brand logo on the AI Connectors placeholder tab. Replaces the hand-rolled interconnected-nodes SVG on the AI Connectors placeholder promo (
?tab=ai-connectorswhen theacrossai-ai-connectorscompanion is missing / inactive) with the same brand SVG the vendor uses on the shared Add-ons page (https://acrossai.co/wp-content/uploads/2026/07/acrossai-logo-2.svg). NewLOGO_URLclass constant onAIConnectorsPromoTab; icon markup swapped from an inline<svg>inside a gradient tile to a plain<img alt="AcrossAI">tag; deleted the privaterender_network_svg()method (dead code). CSS: dropped.acai-aic-promo__icon(gradient background + colored SVG) in favor of.acai-aic-promo__logo(height: 48px; max-width: 180px; object-fit: contain) so the brand mark sits cleanly without a decorative background box. - Refactor — Renamed the ”MCP Tracker” tab to ”Logs”. The per-server tab formerly reached at
?tab=mcp-trackeris now?tab=mcp-log, and the tab-bar label reads Logs instead of MCP Tracker. Priority slot 80 preserved so the tab-bar ordering is unchanged. Class nameMcpTrackerTabkept (internal identifier) along with the body copy that identifies the third-party MCP Tracker plugin on WordPress.org (WPVMCPT) product name — those aren’t the tab label, they’re a specific product reference. Deep links to the old?tab=mcp-trackerfall through to Registry’s ”first surviving tab” default (Overview) rather than 404. Test fixture updated: five'mcp-tracker'occurrences inRegistryTest.phpmigrated to'mcp-log'. - Docs — Rewrote
README.txtas a lean docs-hub pointer. The plugin’s WordPress.org readme now defers to acrossai.co/doc-category/mcp-manager as the source of truth for every feature description — copy lives in one place instead of drifting between two. Description condensed to a two-line multi-client pitch; Key Features reshaped to reflect the current feature set (multiple servers per site, per-server tool/ability curation, per-server access control, frontend embeds, CLI + WP-CLI STDIO transports) with each bullet linking to its docs page; How It Works trimmed to the 6-step get-started path; new Connection Types section calls out the four supported paths (MCP Client, CLI Connections, WP-CLI STDIO, and the paid AI Connectors add-on); Requirements bumped to WordPress 7.0+ / PHP 8.1+ (matches the plugin header — old readme had drifted to 5.9 / 7.4); FAQ trimmed from 7 questions to 5 with a new ”Do I need the paid AI Connectors add-on?” entry; new Support section links to docs hub, FAQ page, and GitHub issue tracker. Header tags expanded (chatgpt,cursor,geminiadded). Deleted the stale post-F040 Experimental Direct Claude Connectors section, the CLI-flow deep dive, and the Provider Configuration Paths list — those live in the docs now. - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant +Stable tagbumped to0.2.3matching the plugin header.
0.2.2
- Notices — migrated persistent-condition banners to the cross-plugin
acrossai_noticesfilter. The ”MCP adapter package missing” and ”wpb-access-control library missing” warnings no longer render as inlineadmin_noticesbanners on every screen. They’re pushed into the shared collection introduced inacrossai-co/main-menu0.0.30, which surfaces them in two consolidated places: (1) a Notices submenu under the AcrossAI parent menu (with a count bubble; the page also stays reachable when the count is zero and renders an ”All clear” empty state per the 0.0.31 fix) and (2) a single WP-native dismissible summary on every other admin page. Dismissal is now fingerprint-based (per-user meta_acrossai_notices_summary_fp) — adding, resolving, or renaming a notice re-shows the summary automatically. Deletions:Notices::render_missing_adapter_notice,Notices::handle_adapter_notice_dismissal,ADAPTER_DISMISS_META_KEY,ADAPTER_DISMISS_NONCE_ACTION,AcrossAI_MCP_Access_Control::maybe_show_library_notice, and the US4 dismiss-persistence handler insrc/js/backend.js— all obsoleted by the shared summary. Additions:Notices::register_shared_notices()returns records with idsacrossai_mcp_manager_adapter_missing(typeerror) andacrossai_mcp_manager_wpb_access_control_missing(typewarning), both scoped withsource: 'MCP Manager'. One-shot action-result flashes (?notice=<slug>) stay on the standardadmin_noticeshook — page-scoped transient messages don’t fit the shared collection model. - UI — Redesigned the AI Connectors placeholder tab as a centered sales card. When the
acrossai-ai-connectorscompanion add-on is not installed or not active, the AI Connectors tab on the server-edit page (?page=acrossai_mcp_manager&action=edit&server=<id>&tab=ai-connectors) now renders a vertically-centered polished card sourced from https://acrossai.co/ai-connectors/ — headline (”Connect WordPress to Claude, ChatGPT & Grok in one click”), supported-client pills (Claude · ChatGPT · Grok), four benefit bullets, a purple CTA (”Install add-on” / ”Activate add-on” depending on companion state), a ”Learn more” link, and a 14-day money-back trust line. State resolution unchanged — Registry’s last-wins dedup at priority 35 still swaps the placeholder out for the companion’s realAIConnectorsTabthe moment the add-on activates. - Dependencies: bump
acrossai-co/main-menu0.0.290.0.31. 0.0.30 shipped the sharedacrossai_noticesfilter + Notices submenu +SummaryNoticeEmitter. 0.0.31 fixed a ”Sorry, you are not allowed to access this page.” error on direct visits toadmin.php?page=acrossai-noticeswhen the notice count was zero (page callback is now always wired; empty-state sidebar row is hidden via inline<style>onadmin_headrather thanremove_submenu_page(), which had desynced$_registered_pages). - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant +Stable tagbumped to0.2.2matching the plugin header (backfills theStable tagdrift that persisted since 0.2.0).
0.2.1
- Security — Defended REST + AJAX response paths against full-page cache poisoning. Full-page caches (LiteSpeed Cache, WP Rocket, W3 Total Cache, WP Super Cache, host-level FastCGI cache) don’t honor arbitrary
Cache-Control: no-storeheaders when making caching decisions — they gate onDONOTCACHEPAGE(WordPress-community convention) and their admin exclusion list. Companion fix toacrossai-ai-connectors0.5.3 PR #13 (DEC-OAUTH-DONOTCACHEPAGE-PATTERN). Newincludes/Utilities/CacheHeaders.php— port of the utility fromacrossai-ai-connectors— applies a three-pronged defense (constant + headers + WP filter) on every per-session and per-server response emission surface:GET /servers/{id}/abilities,GET /servers/{id}/tools,GET /auth/status,GET /servers,POST /auth/start,POST /auth/exchange,POST /generate-app-password, and thewp_ajax_acrossai_mcp_dismiss_adapter_noticeAJAX endpoint. Prevents cross-server data leaks (per-server ability/tool rosters bleeding into other sessions) and stale-response classes (cached{approved:false}served after the flip totrue). Also fixes plugin-header vsACROSSAI_MCP_MANAGER_VERSIONconstant drift — B5 bug pattern (constant lagged at 0.1.9 while header sat at 0.2.0). Both now aligned at 0.2.1.
0.2.0
- Dependencies: bump
acrossai-co/main-menu0.0.270.0.29. Picks up the shared main-menu package’s latest baseline for the 0.2.0 release cycle. - Feature 040 — Migrated the AI Connectors + OAuth stack to the companion plugin
acrossai-ai-connectors(v0.5.0+). MCP Manager now ships only the free-tiertab=npmandtab=clientsconnection paths; the OAuth click-to-connect flow (Claude Web, ChatGPT connectors, Grok) plus the AI Connectors admin tab now live in the paidacrossai-ai-connectorsadd-on. Token / client / auth_code storage is unchanged — same table names (wp_acrossai_mcp_oauth_clients,_tokens,_auth_codes,wp_acrossai_mcp_connector_approved_users), same BerlinDBdb_version_keys, no data migration. REST namespace kept asacrossai-mcp-manager/v1for RFC 8414 discovery compatibility. Existing Claude/ChatGPT/Grok OAuth connections continue to authenticate transparently when the add-on is installed — zero re-authorization required. Free users updating without the add-on are undisturbed (mcp-manager remains standalone-activatable; the AI Connectors tab simply doesn’t appear). Deletions: entireincludes/OAuth/,includes/Connectors/,includes/Database/{OAuthClients,OAuthTokens,OAuthAuthCodes,ConnectorApprovedUsers}/,admin/Partials/ServerTabs/AIConnectorsTab.php,templates/oauth/consent.php,src/js/ai-connectors.js,src/scss/ai-connectors.scss, allbuild/js/ai-connectors.*artifacts, and all associated PHPUnit tests. Modifications:Activator.php,Deactivator.php(retains unconditional cron-clear as belt-and-suspenders per FR-004),Main.php(drops all OAuth REST route + infra wiring + 4 OAuth-table bootstrap/reconcile calls),admin/Main.php(dropsmaybe_enqueue_ai_connectors_app()),admin/Partials/ServerTabs/Registry.php(drops built-inAIConnectorsTabentry — companion re-registers via existingacrossai_mcp_manager_server_tabsfilter at priority 35),uninstall.php(drops OAuth DROP TABLE lines + cron-clear + narrows theacrossai_mcp_%option sweep to excludeacrossai_mcp_connector_%),webpack.config.js(dropsjs/ai-connectorsentry), andpublic/Discovery/ConnectionMethodRegistry.php(FR-019: swapsConnectorProfileRegistryFQN to the companion namespace and guards withclass_exists()so the discovery API returns an emptyai_connectorcategory when the add-on is absent). Coordination invariant: the companion at v0.5.0+ has been audited across 44 checks (23 structural readiness + 21 wiring counterparts) and is deployable — the migration is atomic via the companion’sclass_exists( '\AcrossAI_MCP_Manager\Includes\OAuth\AuthorizationController' )self-disable probe. No compat shim, noRequires Plugins:header, no admin notice — per clarifications Q4/Q5/Q6, this feature adds ZERO new code (pure deletions + header version bump). Durable lesson captured: when a subsystem gets its own plugin, prefer code-only migration (identical table names, identical version keys, byte-identical BerlinDB Table subclass declarations) over data-migration.
0.1.9
-
Feature 038 — User-accessible MCP servers shortcode + reusable base class. New shortcode
[acrossai_mcp_servers]lists every MCP server the current logged-in user can reach (F015 access-control gate) whose F037 Embeds tab has the master toggle ON and at least one enabled connection method — surfacing per server every enabled NPM / MCP Client / AI Connector DTO from F035. Attributes:heading="",show_description="1",empty_message="…"(all optional). Ships with a data-only abstract base class\AcrossAI_MCP_Manager\Public\Renderers\UserServers\AbstractUserServersRendererunderpublic/Renderers/UserServers/so companion plugins (planned BuddyBoss add-on, WooCommerce My Account, WPUM, MemberPress) can subclass and consume the enumeration primitiveget_accessible_servers( ?int $user_id = null ): arraywithout re-implementing the F015 + F037 gate cascade. ConcreteUserServersBlockshortcode child isfinalper D36 (extend by filter, not subclass). Two new extension filters:acrossai_mcp_user_accessible_servers(reshape the payload per context; NOT a gate-bypass surface — consumers appending entries MUST replay the gate cascade themselves per SEC-004) andacrossai_mcp_servers_shortcode_html(override markup without subclassing; NOT re-sanitized — listener plugins trusted at filter boundary per SEC-002). Anonymous visitors get silent no-render (empty string). Logged-in users with zero accessible servers get an empty-state wrapper with a translatable message. Inline scoped<style>block emitted at most once per request via a private static flag (FR-016); CSS content is a static literal, no dynamic interpolation permitted (SEC-005 invariant). Icons render as<img>forhttp:///https://URLs and asesc_htmltext otherwise. Escape-at-render discipline mandated at every seam (FR-014). Pure composition on top of F011 MCPServerQuery + F015 access-control wrapper + F035 ConnectionMethodRegistry + F037 AbstractEmbedTransport (memoized per-DTO gate); zero new DB tables / REST endpoints / admin surfaces / JS. Consumer responsibility (SEC-001): when a companion plugin callsget_accessible_servers( $target_user_id )with a target other than the current viewer, the consumer MUST independently verify the current viewer’s authority to see the target user’s info — F038 evaluates the F015 gate FOR the target user, not against the caller’s authority. Newuser-serversPHPUnit suite (tests/phpunit/Public/Renderers/UserServers/) registered inphpunit.xml.dist+ CI job; three test files (abstract renderer + concrete block + third-party extensibility) cover the 11 algorithm cases + 12 render cases + 3 extensibility scenarios documented incontracts/*.contract.md§Test contract.@experimentalperDEC-CLIENT-RENDERER-PUBLIC-API— data shape freezes at 1.0.0. -
Feature 037 — Per-server Shortcode + Block Embeds tab. New ”Embeds” admin tab under the server-edit page (
?page=acrossai_mcp_manager&action=edit&server=<id>) lets site administrators enable/disable frontend shortcode + block output per server, with per-transport sub-toggles for NPM Methods, MCP Clients, and AI Connectors. Master toggle default OFF — fresh install ships zero shortcode output for every server (US1). Persists via new BerlinDB junction tablewp_acrossai_mcp_server_embed_transports(presence model perDEC-TOOL-SELECTION-PRESENCE-MODEL) plus newembeds_enabled TINYINT(1)column onwp_acrossai_mcp_servers(D28 3-part schema-drift contract;$versionbump 1.1.2 1.1.3). NewAbstractEmbedTransportbase class underincludes/Embeds/— direct application of D35 self-contained-subsystem-contract, mirrors F034AbstractMCPClient::get_all_registered_clients()line-for-line. Three built-in concrete transports (NpmEmbedTransport,ClientEmbedTransport,AiConnectorEmbedTransport) with transport keys aligned 1:1 with F035 DTOcategoryfield values so consumers holding an F035 DTO can callAbstractEmbedTransport::is_enabled_for_server( $server_id, $dto['category'] )with zero translation. New filteracrossai_mcp_embed_transportsfor third-party transport registration. New[acrossai_mcp_embed server="<slug>" category="<key>" slug="<optional-dto-slug>"]shortcode with 3-gate cascade: master toggle per-transport toggle F015 access control (fail-open per D19 when F015 wrapper absent). Two granular observability actions per FR-024 (acrossai_mcp_embed_master_toggled,acrossai_mcp_embed_transport_toggled) fire ONLY on actual value transitions — audit-log + reactor plugins get first-class integration points. New actionacrossai_mcp_server_deletedfires on server-row deletion; F037 wires cleanup listener that prunes junction rows per FR-017. OptionalAbstractEmbedTransport::garbage_collect_orphans()helper for companion plugins’uninstall.php. Admin UI ships as a React app at#acrossai-mcp-embeds-rootper D37 / DEC-ADMIN-UI-REACT-FIRST (matches F017 Abilities + F020 Tools patterns) — uses@wordpress/components(ToggleControl,Button,Notice,Spinner),@wordpress/element,@wordpress/api-fetchwith nonce middleware only (B25 defense),@wordpress/i18n. Saves via REST endpointPOST /acrossai-mcp-manager/v1/servers/{server_id}/embeds(matches F017/F020 URL shape verbatim); permission_callback verifiesmanage_options(S2) + WP corewp_restnonce. Cross-server bypass structurally impossible — REST URL{server_id}path parameter IS the tenant scope. Fail-forward per-listenertry/catchon observability actions per R3 (broken audit listeners MUST NOT roll back DB writes). NewembedsPHPUnit suite registered inphpunit.xml.dist+ CI job. B1 regex bugfix shipped inline: transport-key regex widened from/\A[a-z0-9-]{1,64}\z/to/\A[a-z0-9_-]{1,64}\z/to accept theai_connectorkey. SEC-037-002 comparator(int)coercion shipped. Marked@experimental until plugin 1.0.0perDEC-CLIENT-RENDERER-PUBLIC-APIinheritance. ConsumesConnectionMethodRegistry::get_all()(F035) as its DTO source; NEVER re-fires F034/F021/F035 filters (verified by SC-005 grep gate). DEV5 no longer applies post-pivot (F037 dropped from consumer count). -
Feature 035 — Public connection-method discovery API. New singleton
AcrossAI_MCP_Manager\Public\Discovery\ConnectionMethodRegistryexposes every registered NPM method, MCP client, and AI connector as a unified list of plain-associative-array DTOs — one canonical entry point (get_all()) replaces three separate registries with three different shapes. Third-party plugins (motivating consumer: planned BuddyBoss add-on) can now enumerate every connection method the site supports without re-implementing per-category lookup loops. Every DTO across all three categories carries the same six top-level keys (category,slug,name,description,icon,meta) plus category-specific extras inmeta;wp_json_encode()round-trips losslessly so consumers can safely persist to their own storage. Adds two new extensibility filters:acrossai_mcp_npm_methods(closes the NPM extension-seam gap — NPM had no filter surface before this release) andacrossai_mcp_connection_methods(fires once on the assembledget_all()result for cross-category concerns without duplicating three separate filter registrations). Delegates transparently toAbstractMCPClient::get_all_registered_clients()(F034) andConnectorProfileRegistry::get_profiles()(F021) — never re-fires their filters, verified by two grep gates (SC-005 for delegation, SC-006 for one-waypublic/↛includes/layering).NpmClientBlockgrows a newget_default_npm_method(): arraystatic helper so the NPM template + option gate has a single source of truth; NPM tab render remains byte-identical (SC-007 automated regression guarded by dedicatedNpmDefaultHelperTest). NPM filter contributions dedup by slug later-wins (matches F034 semantics) and are validated against the six-key + value-type contract per SEC-035-001 — malformed entries (slug => array(),meta => 'string', etc.) silently dropped +_doing_it_wrongunderWP_DEBUG(SEC-013-008 pattern inheritance). Malformedacrossai_mcp_connection_methodscallback returns fall back to the pre-filter assembled result — consumers always receive a well-shaped three-category array regardless of companion-plugin bugs. NewdiscoveryPHPUnit suite (tests/phpunit/Public/Discovery/) registered inphpunit.xml.dist+ CI job; ~20 test methods across two test files covering singleton shape, DTO invariants, JSON round-trip,find()lookup, memoization +flush_cache(), NPM filter fire + dedup + type-drift dropped, cross-category filter fires-once-only-in-get_all + malformed-return fallback. Zero admin UI, zero REST routes, zero database changes. Marked@experimental until plugin 1.0.0perDEC-CLIENT-RENDERER-PUBLIC-API. -
Dependencies: bump
acrossai-co/main-menu0.0.230.0.27. Picks up the shared main-menu package’s latest baseline (Add-ons page metadata, submenu policy refinements). - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant bumped to0.1.9matching the plugin header.
0.1.8
- Feature 034 — MCP client subsystem refactor: metadata methods + canonical filter-aware enumeration. Each concrete MCP client class (
ClaudeDesktopClient,ClaudeCodeClient,VSCodeClient,GitHubCopilotClient,CodexClient,CursorClient,GeminiClient,CustomClient) now declares its own display metadata via six new methods onAbstractMCPClient—get_icon(),get_description(),get_config_file(),get_top_level_key(),get_instructions(), plusget_priority(): int(default100, built-ins pre-assigned10, 20, 30, ..., 80to preserve pre-refactor sub-nav order). Replaces the privateCLIENT_METAconst inMCPClientsBlock(deleted). Enumeration collapses to a single canonical entry pointAbstractMCPClient::get_all_registered_clients()that fires the existingacrossai_mcp_client_classesfilter with aDEFAULT_CLIENT_CLASSESseed, validates FQNs per SEC-013-008 (silent-skip on invalid), validates slugs against/[a-z0-9-]{1,64}/(_doing_it_wrongunderWP_DEBUGon violators), dedups by slug with later-wins, and sorts by(priority ASC, slug ASC)— mirroringConnectorProfileRegistry::get_profiles()line-for-line. The pre-F034 glob-basedAbstractMCPClient::get_all_clients()(which ignored the filter) is deleted.MCPClientsBlock::render_body()shrinks from 32 lines to 6 (single call to the canonical enumeration + iteration; no inline default-classes array, no local filter loop, no metadata lookups by slug). Third-party client subclasses contributed via the filter now have a symmetric way to declare their own icon / description / config-file / top-level-key / instructions / sub-nav slot instead of being stranded in the Renderer’s private const. Byte-identical rendered output for the eight built-in clients on the server-edit Clients tab. No breaking changes for existing third-party subclasses — the six new methods default to empty strings (or 100 for priority). Test coverage: newGetAllRegisteredClientsTest.phpcovers default state / filter contribution / invalid FQN skip / bad slug reject / duplicate slug later-wins / priority sort with slug tiebreaker; newConcreteClientMetadataTest.phpdata-provider parameterized over all 8 built-ins asserts each returns the migrated metadata values; newMCPClientsBlockRenderTest.phpunder therendererssuite verifies FR-016 render byte-identity via DOM markers AND exercises the SEC-034-001 preservation invariant (hostile third-party subclass returning<script>payloads MUST be escaped at render).mcpclientsPHPUnit suite grows to 86 tests / 181 assertions (up from 74 pre-F034). Durable memory captured asD35 / DEC-F034-SELF-CONTAINED-SUBSYSTEM-CONTRACT— generalizable pattern for every future subsystem with an abstract base + filter-based subclass contribution + per-subclass display metadata.
0.1.7
- Feature 033 — Security fix: F030 permission_callback wrapper dropped args and coerced
WP_Errortotrue. Two bugs inPermissionOverrideProcessor::inject_overridecombined into a plugin-widepermission_callbackbypass. The wrapper closure was declaredstatic function () use ( ... )— zero parameters — so every arg the caller passed was silently discarded. Downstream callbacks that read their input (notablyExecute::check_permissionlooking up$input['ability_name']) saw an empty array and returnedWP_Error( 'missing_ability_name', ... ). The wrapper’scall_originalhelper then didreturn (bool) call_user_func( $original );— casting theWP_Errorobject to booleantrue(PHP casts every object to true). The vendor’sif ( true !== $permission )check inToolsHandler::call_tool(vendor/wordpress/mcp-adapter/includes/Handlers/Tools/ToolsHandler.php:148) read that as ”permission granted” and proceeded toexecute(). Impact: any authenticated user with any role (includingsubscriber) could invoke any registered ability viamcp-adapter/execute-abilityon the default MCP server, even when the Abilities tab had explicitly disabled the ability (is_exposed=0row inwp_acrossai_mcp_server_abilities) and the ability itself declaredmeta.mcp.public = false. Fix: closure is nowstatic function ( ...$callback_args ) use ( ... )and forwards$callback_argson every fall-through path;call_originalreturnsbool|WP_Error—WP_Errorresults propagate unchanged, only scalar returns are coerced. The six-layer allow-path semantics (DEC-F030-PERMISSION-CALLBACK-OPERATOR-OPT-IN-BYPASS) are unchanged — only the fall-through path is affected. Test coverage: three new regression tests inPermissionOverrideProcessorTest.php— args forwarding,WP_Errorpreservation, and a@dataProvider-parameterised role sweep acrosssubscriber/contributor/author/editor/administratorproving low-privilege roles are correctly denied post-fix. Durable memory captured asB40 / B-WRAPPER-CLOSURE-MUST-FORWARD-ARGS-AND-PRESERVE-WP-ERROR— generalizable pattern for any closure wrapping a user callback (permission_callback, execute_callback, filter/action decorators, plugin bridges). Follow-up tracked as issue #46: filter-time eligibility gate refactor to skip installing the wrapper entirely for abilities that could never satisfy F030’s six defensive layers — eliminates the wrapper-bug class for the vast majority of abilities. - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant bumped to0.1.7matching the plugin header.
0.1.5
- Feature 031 — Add Google Gemini CLI as a supported MCP client. The server-edit Clients tab now surfaces a Gemini card (💎 pill) alongside the existing 7. Uses the same npx
@automattic/mcp-wordpress-remote@latestbridge + WP Application Password Basic auth as Claude Desktop / Cursor / other stdio-based clients; config paste target is~/.gemini/settings.jsonunder the standardmcpServerskey.GeminiClientis a near-verbatim mirror ofClaudeDesktopClient(sluggemini, nameGemini CLI, byte-for-byte identicalget_config_snippetshape) — no new auth mechanism, no new abstraction, no new render path. Registered inMCPClientsBlock::$default_classes+CLIENT_META['gemini']. Test suite canary bumped from 7 8 concrete clients;mcpclientsPHPUnit suite now runs 74 tests / 124 assertions (up from 67/111 pre-F031). - Assets — Refreshed WordPress.org plugin-directory banners (1544×500 + 772×250 PNGs in
.wordpress-org/). No code change; visual update only. - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant bumped to0.1.5matching the plugin header.
0.1.4
- Feature 030 — Per-server ability permission_callback override. The MCP-server-edit ”Access Control” tab now hosts a second section (below the existing wpb-access-control React panel, separated by
<hr>) with a single toggle: when enabled, every ability exposed to this MCP server via the Abilities tab bypasses its ownpermission_callbackfor MCP requests routed to this server. Site-wide ability callers (WP admin, non-MCP REST namespaces, WP-CLI) see the originalpermission_callbackunchanged — the closure short-circuits whenCurrentServerHolderis empty. Runtime filter registers onwp_register_ability_argsat priority999999, strictly higher than siblingacrossai-abilities-manager’s P100000 injector and this plugin’s ownCallbackReplacerP10, so the operator toggle wins deterministically. Gated by six defensive layers documented inDEC-F030-PERMISSION-CALLBACK-OPERATOR-OPT-IN-BYPASS:manage_optionscapability + per-server nonce (acrossai_mcp_manager_permission_override_{server_id}) + persistent warning banner when ON + nativeconfirm()prompt on submit-to-ON +CurrentServerHolderscope +ExposureResolver::resolve()gate. Adds one column via D28 3-part BerlinDB contract (MCPServer\Table1.1.1 → 1.1.2+upgrade_to_1_1_2callback, idempotent perINFORMATION_SCHEMA.COLUMNS). Fires new observability actionacrossai_mcp_permission_override_toggled( $server_id, $value, $user_id, $timestamp )on every save — operators can attach any logger (Query Monitor, custom audit table, syslog) without a hard dependency. Also adds a promotional card for the siblingacrossai-abilities-managerplugin (already inacrossai-co/main-menu’s baseline addon list — no double-register) with links to install/activate via the shared Add-ons page or edit abilities when active, plus a<details>”Prefer to use code?” fallback documenting the filter name + priority for developers who prefer not to install another plugin. - Feature 030 (bonus) — Test-infrastructure fix.
tests/phpunit/{Abilities,Database,MCP}/were orphaned inphpunit.xml.dist— 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 (abilities,database,mcp) + 3 matching CI workflow steps in.github/workflows/phpunit.yml. All previously-orphaned tests + all F030 new tests now execute in CI on every push. - Feature 030 — Durable memory captured. Five new entries in
docs/memory/:D29(six-layer defensive gating framework for any futurepermission_callbackbypass — scoped carve-out fromD24),D30(F030 intentionally passes empty$metatoExposureResolver::resolve()— scoped carve-out fromDEC-ABILITY-OVERRIDE-RESOLUTION),B35(wp_register_ability_argsfilter-priority slot map: P10 CallbackReplacer, P100000 sibling, P999999 F030),B36(inline<script>string-interpolation requireswp_json_encode(), notesc_html/esc_attr— generalizable JS-context escaping rule),DEV5(per-server-edit tab hand-rolled admin form exception to §IV DataForm mandate per D13 escalation ≥ 2 features). - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant bumped to0.1.4matching the plugin header.
0.1.3
- Feature 029 (OAuth) — RFC 6749 §2.3.1 HTTP Basic auth accepted on
/token+client_secret_postsoftening.TokenControllernow parsesAuthorization: Basic base64(client_id:client_secret)with CGI fallback (REDIRECT_HTTP_AUTHORIZATION) and applies header-first-then-body credential resolution to bothauthorization_codeandrefresh_tokengrants. When a client registered asclient_secret_postsubmits NO secret at exchange (header AND body both empty), the endpoint now falls through to PKCE-only verification instead of hard-rejecting withinvalid_client. Modern MCP hosts (Claude.ai, ChatGPT, Cursor, Cline) frequently register asclient_secret_postbut behave as public+PKCE at exchange; the softening keeps them interoperable. Confidential clients that DO send a secret are still verified via constant-timeClientRepository::verify_secret(unchanged). Codified as durable decisionD27. Residual risk bounded by mandatory PKCE S256 + RFC 8707 audience binding + single-use auth codes + refresh-family revocation. - Feature 029 (OAuth) — DCR-registered clients now attributed to their connector profile at registration time.
ClientRegistrationController::handle_register()walksConnectorProfileRegistry::get_profiles()and callsmatches_dcr_client( $client_name, $redirect_uris )on each — first matching profile’s slug is persisted asconnector_slug(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 asB33(admin-gate silent-bypass on data-field left empty). - Feature 029 (DB) — BerlinDB schema-drift reconciliation for
wp_acrossai_mcp_cli_auth_logs+wp_acrossai_mcp_servers. Two live tables had drifted from theirSchema.phpwhile storeddb_versionstill matched code —parent::maybe_upgrade()short-circuited forever, and any INSERT referencing a Schema column missing from the actual table returnedfalse, which callers cast toint(0)and treated as success (silent write-loss; identical shape took down Claude OAuth onprocureco.ukbefore F029). BumpsCliAuthLog\Table1.0.01.0.1(addsupgrade_to_1_0_1callback that ALTER MODIFYsstatusvarchar(20)varchar(32),failure_codevarchar(100)varchar(64),app_password_uuidvarchar(64)varchar(36)) andMCPServer\Table1.1.01.1.1(addsupgrade_to_1_1_1callback that ALTER ADD COLUMN for the three F025 protocol flagstool_discover_abilities,tool_get_ability_info,tool_execute_ability). Both callbacks idempotent per-column viaINFORMATION_SCHEMAexistence/width check. Codified asD28(BerlinDB$upgradesreconciliation pattern) +B34(silent write-loss bug pattern). - Feature 029 (Boot) —
Main::reconcile_database_schemas()onadmin_init@3. New Loader-wired admin hook firesmaybe_upgrade()on all 7 BerlinDB Tables on every admin request. Before F029,maybe_upgrade()only ran fromActivator::activate()— 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 BEFORESettings::maybe_seed_default_server(4) andSettings::handle_actions(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). - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant bumped to0.1.3matching the plugin header.
0.1.2
- Feature 027 — Fix: DCR
token_endpoint_auth_methoddefault flipped tononefor public+PKCE clients.ClientRegistrationController::handle_register()(includes/OAuth/ClientRegistrationController.php:310) previously defaulted the RFC 7591 Dynamic Client Registrationtoken_endpoint_auth_methodfield toclient_secret_postwhen the caller omitted it. Modern MCP hosts (Claude.ai, ChatGPT, Cursor, Cline) register as public+PKCE clients — they omit the field in DCR and never carry aclient_secretthrough the/tokenexchange. The old default silently stored these clients as confidential; the follow-up authorization-code exchange then failed atTokenController::handle_authorization_code()(includes/OAuth/TokenController.php:106-111) withinvalid_clientHTTP 401 after the auth code had already been consumed atomically atAuthCodeRepository::consume_atomicline 89 — so the client saw a generic ”Authorization failed” page with no ability to retry. Default now flips tonone, matching RFC 8252 §8.4 for public+PKCE clients. Confidential-client callers can still passtoken_endpoint_auth_method=client_secret_postexplicitly in the DCR body; admin-generated clients athandle_admin_generateare unaffected (they continue to hardcodeclient_secret_post). New phpunit casetest_omitted_auth_method_defaults_to_none_public_clientintests/phpunit/OAuth/DCRRegisterFreshTest.phplocks the invariant.
0.1.1
- Feature 028 — Retire Freemius integration; consume
acrossai-co/main-menu0.0.22+ filter-driven Add-ons page. The bundledfreemius/wordpress-sdktransitive dependency is dropped entirely (vendor removed it fromacrossai-co/main-menu0.0.22’srequireblock along with theAcrossAI_Addon\PSR-4 namespace). This plugin’s Freemius integration inMain::define_admin_hooks()— the\AcrossAI_Addon\AddonsPageinstantiation withfs_product_id => '34418'/fs_public_key/fs_slug => 'acrossai-add-ons'/fs_menu/fs_has_addonsconfig, itsclass_exists+try/catchguards, and its admin-notice fallback closure — is removed in full (94 lines). No opt-in card, noapi.freemius.comoutbound requests, no umbrella-product license state. Bumpsacrossai-co/main-menu0.0.180.0.23. - New consumer self-exclusion filter. A new singleton
admin/Partials/AddonsFilterhooks the vendor’sacrossai_addonsfilter and drops the entry withslug === 'acrossai-mcp-manager'from the array — an already-active plugin should not advertise itself as an installable add-on on the shared Add-ons page. Codified asD26 / DEC-CONSUMER-SELF-EXCLUSION-VIA-VENDOR-FILTER(paired withD20on the subtractive side). Every future AcrossAI plugin whose slug appears inAddonsPageRenderer::ADDONSMUST ship the same pattern. - User-visible behavior change: the AcrossAI Add-ons submenu no longer renders from this plugin. The Add-ons submenu is now rendered by whichever consumer of
acrossai-co/main-menu0.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. - Related durable memory flipped to Superseded (F028):
DEC-ADDONS-PAGE-VENDOR-CTOR-BOOT(external-package self-registering-in-constructor exception to A1 — obsolete because\AcrossAI_Addon\AddonsPageno longer exists),DEC-FREEMIUS-DOUBLE-OPTIN-GATES-ACCOUNT(opt-in state-machine diagnosis — no live surface here anymore), andB28(Freemius two-levelmenu.<key>+has_<key>enablement pattern — SDK is gone). Entry bodies retained per PATTERN-MEMORY-SUPERSESSION-VS-ANNOTATION. - Internal:
ACROSSAI_MCP_MANAGER_VERSIONconstant resynced. Drifted at0.0.9across the 0.1.0 release; now correctly reads0.1.1matching the plugin header. - Operator recipe for prior installs (optional cleanup): Freemius’ SDK previously wrote
fs_accounts,fs_active_plugins,fs_api_cache,fs_cache_*, andfs_debug_moderows towp_options. Nothing this plugin loads reads or writes them post-F028. To purge:DELETE FROM wp_options WHERE option_name LIKE 'fs_%';. The plugin does NOT ship this as an automatic migration (perD21fresh-install-only retirement pattern established by F016).
0.1.6
-
Feature 032 — OAuth per-server scoping (SECURITY FIX + BREAKING CHANGE for legacy DCR sessions).
⚠️ BEFORE UPGRADE — READ THIS: this release deletes any pre-F032 DCR-registered OAuth client rows (those without a
server-{id}-prefix — 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) snapshottingwp_acrossai_mcp_oauth_{clients,tokens,auth_codes}before upgrade, and (b) notifying users with active AI-host connections that they will need to re-authorize once after upgrade.Security fix: 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
client_idin the outbound REST body. Also closes a read-side display leak in the ”authorized users” listing on the AI Connectors tab.What ships: adds
server_id BIGINT UNSIGNED NOT NULLcolumn (final state) towp_acrossai_mcp_oauth_clients,wp_acrossai_mcp_oauth_tokens, andwp_acrossai_mcp_oauth_auth_codesvia the D28 3-part BerlinDB$upgradescontract (each Table bumps$version1.0.0 1.0.1 with matchingupgrade_to_1_0_1()callback). Replaces standaloneUNIQUE(client_id)onoauth_clientswith compositeUNIQUE(client_id, server_id)so the same DCR connector can be registered on multiple MCP servers as independent rows. Every mutating REST endpoint (revoke-client-tokens,delete-client,revoke-connector-tokens) now requires + validates …










