Three PRs merged into main since 0.2.7 ship in this release; two are ⚠️ security behavior-changes surfaced by the 2026-08-13 adversarial review of the MCP two-gate access-control stack.
PRs included
| PR | Kind | Title |
|---|---|---|
| #77 | ⚠️ security | fix(access-control): close resource/prompt bypass + fail-closed on missing vendor |
| #76 | admin UX | feat(admin): server list — drop Slug/Version, merge Route, Edit + tab quick-links |
| #75 | UI copy | feat(admin): rename AI Connectors tab label to Connectors/Integrations |
⚠️ Security — F1: MCP resources & prompts now gated (was silently bypassed)
Before 0.2.8 the plugin only hooked mcp_adapter_pre_tool_call. The vendor's sibling pre-dispatch filters — mcp_adapter_pre_resource_read (ResourcesHandler.php:138) and mcp_adapter_pre_prompt_get (PromptsHandler.php:157) — had no subscriber.
Combined with F042 deliberately returning 'read' at the transport layer for rule-configured servers (so any authenticated user passes the transport gate, on the assumption that F015 would then enforce), any authenticated user could POST {"method":"resources/read","params":{"uri":"…"}} or {"method":"prompts/get"} against a server configured "Editors only" and the operator's rule was never consulted.
Fix: extracted the enforcement body of gate_mcp_tool_call into a private apply_ac_gate() helper. Added two sibling public callbacks — gate_mcp_resource_read + gate_mcp_prompt_get — wired adjacent to the existing tool-call filter in Main::define_public_hooks(). Deny path returns WP_Error with a gate value of mcp_resource_read / mcp_prompt_get. Observability hooks (acrossai_mcp_access_control_denied, acrossai_mcp_access_control_missing_server) now fire from three MCP boundary sites — $context arg discriminates; $subject arg is polymorphic (tool name / resource URI / prompt name).
Operator action: audit any server that exposes MCP resources or prompts AND has a rule configured. Non-privileged users who previously succeeded on resources/read / prompts/get will now receive HTTP 403 with the same acrossai_mcp_access_denied error code the tool-call gate has emitted since 0.0.7.
⚠️ Security — F2: F042 fails CLOSED on missing wpb-access-control (was fail-open)
Before 0.2.8 both AC gates failed OPEN under the same condition: F015 returned $args (allow) when class_exists( AccessControlManager::class ) was false; F042 returned the vendor 'read' default under the mirror condition (class_exists( RuleQuery::class )). Because both degraded in the same direction, a single dependency failure — composer breakage, autoloader race, missed dependency after site clone, vendor package rename — collapsed the entire two-gate stack, letting every authenticated user reach every tool on every server.
Fix: F042's missing-vendor branch now returns 'manage_options'. Paired with F015's fail-open on the same condition, the stack degrades to admin-only rather than "wide open." Class docblock on TransportPermissionDefault explicitly documents the intentional asymmetry — "F015 fails open + F042 fails closed = admin-only when the vendor breaks" — so the invariant survives future refactors. Class-exists check moved behind a protected has_access_control_library() seam for direct test coverage.
Operator action: none in the healthy-vendor case. If your deploy pipeline can produce a missing-vendor state, non-admin MCP traffic will get 401 instead of full access until the vendor package is restored.
Admin — Server list redesigned
Server list at ?page=acrossai_mcp_manager gets a tighter, more actionable layout.
Column changes:
- Removed Slug (redundant with Route/Route Namespace and the Name column's inline edit link)
- Merged Route Namespace + Route into a single
Routecolumn (<namespace>/<route>, duplicate slashes at the join collapsed) - Removed Version (still surfaced on the per-server-edit Overview tab)
- Final column order:
☐ | Name | Status | Registered From | Route | Actions
Actions column extended — the existing Enable/Disable toggle is now bundled with 5 quick-access buttons:
- Edit (primary-styled) — links to the server-edit page
- Enable / Disable — existing per-row nonce'd toggle
- Connectors →
tab=ai-connectors - Access Control →
tab=access-control - Abilities →
tab=abilities - MCP Clients →
tab=clients
Quick-links render as subtle rounded pill-badges with dashicon prefixes (admin-plugins / shield / superhero-alt / admin-users). New .acrossai-actions-cell flex wrapper keeps the button cluster wrapping cleanly on narrow viewports; Status + Registered From columns capped at 120px so the freed horizontal space flows to Route + Actions.
UI — AI Connectors tab renamed to "Connectors/Integrations"
The per-server-edit tab label at ?page=acrossai_mcp_manager&action=edit&server=<id>&tab=ai-connectors now reads Connectors/Integrations instead of "AI Connectors". Tab slug (ai-connectors) is intentionally unchanged so the last-wins tab-registration override from the acrossai-ai-connectors companion plugin keeps landing on the same placeholder — no companion-plugin coordination required.
Internal: ACROSSAI_MCP_MANAGER_VERSION constant + Stable tag bumped to 0.2.8 matching the plugin header.
Full changelog: main…v0.2.8