diff --git a/CLAUDE.md b/CLAUDE.md index 52bc314..6aec737 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ When editing premium-prompts behavior, the plugin code (`includes/admin/class-pr - With Elementor Pro: **127** (124 + 3) — **88** active by default - With Elementor Pro + Elementor 4.0+: **141** (138 + 3) — **102** active by default - With Pro + WooCommerce + Elementor 4.0+: **141** — WooCommerce widgets are reached through `add-pro-widget` (catalog tier `woo`), so they add **no** new tools. -- Low-tools mode (any config): still available but largely obsolete — the consolidation already keeps the surface well under common client caps. +- Low-tools mode: **removed in v3.2.0** (superseded by Compact tool mode, the Tools-tab dispatcher toggle). The catalog-backed consolidation already keeps the surface well under common client caps; clients that still cap tool counts use Compact tool mode. > **v3.1.0 adds the 10 always-on Gutenberg block tools** (`list-blocks`, `get-block-schema`, `get-post-blocks`, `list-patterns`, `add-block`, `update-block`, `remove-block`, `move-block`, `duplicate-block`, `insert-pattern`) — config-independent, **+10 registered and +10 active-by-default in every configuration** (all enabled by default; only `remove-block` is badged destructive). These are the numbers already reflected in the bullets above (each is the prior v3.0.0 total + 10). v3.1.0 also brings the **AI Chat editor FAB to the Gutenberg block editor** (`EMCP_Tools_Gutenberg_Editor`, a Pro AI-Chat-module feature; adds no MCP tools). @@ -109,7 +109,7 @@ emcp-tools/ │ │ └── class-content-abilities.php # v3.0.0: 8 WordPress Content tools (list-post-types, list-taxonomies, create/get/update/list/delete-post, set-post-terms) — WP core only, never touches _elementor_data │ ├── class-admin-bar.php # EMCP_Tools_Admin_Bar (free, loaded unconditionally by the bootstrap — the admin bar renders on the front end too). Admin-bar MCP status node (green/grey/red dot) + one-click nonce toggle of emcp_tools_server_enabled (same option the Connection tab writes); manage_options-gated; `admin_post_emcp_tools_toggle_server` handler flips + redirects back. Pure status() unit-tested (pro/tests/unit/admin/AdminBarTest.php) │ ├── admin/ -│ │ ├── class-admin.php # Admin top-level menu (EMCP Tools) with 4 native submenu pages (Tools, Connection, Prompts, Changelog), stats bar, header, Low-tools mode + Pro-disabled-by-default defaults +│ │ ├── class-admin.php # Admin top-level menu (EMCP Tools) with 4 native submenu pages (Tools, Connection, Prompts, Changelog), stats bar, header, Compact-tool-mode toggle + Pro-disabled-by-default defaults │ │ └── views/ │ │ ├── page-tools.php # Tools tab: category-grouped tool toggles with bulk actions │ │ ├── page-connection.php # Connection tab: status cards, credential form, MCP client configs @@ -172,9 +172,9 @@ The MCP Adapter converts ability names like `emcp-tools/list-widgets` to tool na - **Schema-driven validation**: Widget settings validated against auto-generated JSON schemas before saving - **Catalog-backed widgets (v3.0.0)**: instead of 62 per-widget tools, a curated catalog (`includes/widgets/`) holds each widget's tier/category/curated params as DATA. The flow is discover → inspect → act: `list-widgets` (compact index, `tier`/`category`/`search` filters) → `get-widget-schema` (curated `params`, `types[]` batch, `full:true` for raw control schema) → `add-free-widget` / `add-pro-widget` (catalog defaults merged automatically) → `update-widget`. Per-turn widget tool-list cost drops ~10×; no capability is lost (any valid Elementor control passes through). - **Pro-aware**: Pro widget tools only register when Elementor Pro is active; core tools work with free Elementor -- **`elementor_mcp_ability_names` filter** lives in `Elementor_MCP_Plugin::filter_disabled_tools()` (always loaded — NOT in the admin class, which only loads on `is_admin()`). It reads two options: `elementor_mcp_disabled_tools` (user toggles) and `elementor_mcp_low_tool_mode` (essentials-only). When low-tools mode is on, every name outside `Elementor_MCP_Plugin::get_essential_tool_slugs()` is excluded — this is the runtime path that keeps the count under client tool caps. +- **`emcp_tools_ability_names` filter** lives in `EMCP_Tools_Plugin::filter_disabled_tools()` (always loaded — NOT in the admin class, which only loads on `is_admin()`). It reads the single `emcp_tools_disabled_tools` option (user toggles) and removes those names — the runtime path that honors the per-tool grid. (The old Low-tools-mode essentials filter + `get_essential_tool_slugs()` were **removed in v3.2.0**, superseded by Compact tool mode, which is now the single "stay under the client tool cap" control.) - **Pro widgets disabled-by-default**: on first admin page load (tracked via `elementor_mcp_defaults_applied` marker option), every Pro-badged slug from `get_all_tools()` is merged into `elementor_mcp_disabled_tools`. Users can re-enable individual Pro widgets from the Tools admin screen. -- **Compact tool mode (dispatcher) — v3.2.0, opt-in.** Option `emcp_tools_dispatcher_mode` (Connection tab, default OFF). When ON, `register_mcp_server()` surfaces only **3 meta-tools** — `emcp-tools/list-tools` (compact catalog: name/description/category/destructive, `search`/`category` filters), `emcp-tools/get-tool-schema` (batch input schemas by name), `emcp-tools/call-tool` (run a tool by name+arguments) — instead of the ~141 individual tools, to escape client tool-count caps. `call-tool` **delegates to each target ability's own `check_permissions()`** (no privilege escalation) and refuses disabled/unknown tools; the individual abilities stay registered (reachable via `call-tool`). `EMCP_Tools_Dispatcher_Abilities` (`includes/abilities/class-dispatcher-abilities.php`) with `active_names()`/`resolve_ability()` seams; registered by the ability registrar but kept out of `ability_names`. Obsoletes Low-tools mode. The discovery context (server description + `list-tools`' `context`) also carries an environment + active-plugin inventory via `EMCP_Tools_Site_Context::environment_summary()`. +- **Compact tool mode (dispatcher) — v3.2.0, opt-in.** Option `emcp_tools_dispatcher_mode` (**Tools tab**, default OFF — its toggle replaced the removed Low-tools-mode card, registered under `SETTINGS_GROUP` so it saves with the per-tool grid; the Connection tab shows a "moved to Tools" pointer). When ON, `register_mcp_server()` surfaces only **3 meta-tools** — `emcp-tools/list-tools` (compact catalog: name/description/category/destructive, `search`/`category` filters), `emcp-tools/get-tool-schema` (batch input schemas by name), `emcp-tools/call-tool` (run a tool by name+arguments) — instead of the ~141 individual tools, to escape client tool-count caps. `call-tool` **delegates to each target ability's own `check_permissions()`** (no privilege escalation) and refuses disabled/unknown tools; the individual abilities stay registered (reachable via `call-tool`), and the per-tool toggles still gate what `call-tool` will run (the grid stays interactive). `EMCP_Tools_Dispatcher_Abilities` (`includes/abilities/class-dispatcher-abilities.php`) with `active_names()`/`resolve_ability()` seams; registered by the ability registrar but kept out of `ability_names`. Replaces the removed Low-tools mode. The discovery context (server description + `list-tools`' `context`) also carries an environment + active-plugin inventory via `EMCP_Tools_Site_Context::environment_summary()`. - **Agent-facing Skills (read-side) — v3.2.0, Pro.** `EMCP_Tools_Skill_Catalog` (`pro/includes/class-skill-catalog.php`) parses the bundled `SKILL.md` skills (`pro/skills/*/SKILL.md`, dual-root via `EMCP_Tools_Pro_Loader::path('skills')`) and exposes them to connected MCP agents through **2 Pro-gated tools** — `emcp-tools/list-skills` (catalog: slug/name/description, `search` filter) and `emcp-tools/get-skill` (full body by slug, path-traversal-guarded). Read-only; both self-gate on `can_use_premium_code()` (via `EMCP_Tools_Skill_Abilities`). The free `EMCP_Tools_Site_Context::environment_summary()` gains an `emcp_tools_discovery_skills` filter seam that the catalog hooks (in `EMCP_Tools_Skill_Catalog::init()`, wired by `EMCP_Tools_Pro_Loader::wire_runtime_hooks()`) to inject a `## Skills` catalog into the discovery context — progressive disclosure: the agent sees the catalog, then pulls full bodies on demand. The skill abilities are registered by the ability registrar **outside** the Elementor gate (not Elementor-dependent). A `emcp_tools_skill_sources` filter is the extensibility seam for future sources (Premium Prompts, a user CPT). Free ships only the empty filter seam; the catalog + abilities live in `pro/` (`pro-manifest.txt` guards the leak). Reachable via `call-tool` in dispatcher mode. Tests: `pro/tests/unit/skills/` (a `Skills` suite). ### Modules Framework (v3.1.0) diff --git a/assets/css/admin.css b/assets/css/admin.css index 341d98e..a1d6a15 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -2821,14 +2821,8 @@ .elementor-mcp-tabpanel { display: none; } .elementor-mcp-tabpanel.is-active { display: block; } -/* Low-tools mode: pause/grey the per-tool grid + bulk selects (Save stays active). */ -#elementor-mcp-tools-form.is-low-mode .elementor-mcp-category, -#elementor-mcp-tools-form.is-low-mode .elementor-mcp-enable-all, -#elementor-mcp-tools-form.is-low-mode .elementor-mcp-disable-all { - opacity: .55; - pointer-events: none; -} -.elementor-mcp-lowmode-banner { +/* Compact tool mode: an info banner above the still-interactive per-tool grid. */ +.elementor-mcp-compact-banner { margin: 0 0 14px; padding: 10px 14px; background: #eef0ff; @@ -2836,7 +2830,7 @@ border-left: 3px solid #5145e5; border-radius: 6px; } -.elementor-mcp-lowmode-banner p { margin: 0; font-size: 13px; color: #2b2f44; } +.elementor-mcp-compact-banner p { margin: 0; font-size: 13px; color: #2b2f44; } /* Connection-tab client picker */ .elementor-mcp-client-grid { diff --git a/assets/js/admin.js b/assets/js/admin.js index 40a26e7..ba096f5 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -99,29 +99,6 @@ updateCards( form ); } } ); - - // Low-tools mode — live preview without a save round-trip: pause/grey the - // grid and show the effective (essentials-only) state, then restore the - // stored toggles when switched back off. The stored + essential state of - // each tool is carried in data-* attributes rendered server-side. - var lowToggle = form.querySelector( 'input[type="checkbox"][value="1"][name$="low_tool_mode"]' ); - if ( lowToggle ) { - lowToggle.addEventListener( 'change', function () { - var on = lowToggle.checked; - form.classList.toggle( 'is-low-mode', on ); - form.querySelectorAll( toolCheckboxSelector ).forEach( function ( cb ) { - if ( on ) { - cb.checked = ( '1' === cb.dataset.essential ); - cb.disabled = true; - } else { - cb.checked = ( '1' === cb.dataset.storedEnabled ); - cb.disabled = false; - } - } ); - updateCards( form ); - updateToolCounts( form ); - } ); - } } /** diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index 8b7db3e..fa4952b 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -35,15 +35,6 @@ class EMCP_Tools_Admin { */ const OPTION_DISABLED_TOOLS = 'emcp_tools_disabled_tools'; - /** - * Option name for the low-tools-mode toggle. When set to '1', tools - * outside the curated essentials list are filtered out so clients - * with tight tool caps (e.g. Antigravity) stay under their limit. - * - * @var string - */ - const OPTION_LOW_TOOL_MODE = 'emcp_tools_low_tool_mode'; - /** * Settings group name. * @@ -618,9 +609,13 @@ class EMCP_Tools_Admin { ) ); + // Compact tool mode (dispatcher) — Tools tab. OFF by default; surfaces 3 + // meta-tools (list-tools / get-tool-schema / call-tool) instead of every + // individual tool for clients that cap the tool count. Registered under the + // Tools form group so its toggle lives alongside the per-tool grid. register_setting( self::SETTINGS_GROUP, - self::OPTION_LOW_TOOL_MODE, + EMCP_Tools_Plugin::OPTION_DISPATCHER_MODE, array( 'type' => 'string', 'default' => '0', @@ -658,20 +653,6 @@ class EMCP_Tools_Admin { ) ); - // Compact tool mode (dispatcher). OFF by default; surfaces 3 meta-tools - // instead of every individual tool for clients that cap the tool count. - register_setting( - self::SETTINGS_GROUP_SERVER, - EMCP_Tools_Plugin::OPTION_DISPATCHER_MODE, - array( - 'type' => 'string', - 'default' => '0', - 'sanitize_callback' => static function ( $value ) { - return '1' === (string) $value ? '1' : '0'; - }, - ) - ); - // OpenAI-strict tool schemas (Connection tab). OFF by default — it's only // for OpenAI-compatible strict function-calling clients (CrewAI, etc.) and // would otherwise break Gemini/Antigravity. (GitHub #42) @@ -801,16 +782,6 @@ class EMCP_Tools_Admin { && self::SETTINGS_GROUP === sanitize_text_field( wp_unslash( $_POST['option_page'] ) ); if ( $is_settings_form ) { - // When low-tools mode is saved ON, the per-tool grid is paused and - // rendered disabled, so its checkboxes don't post. Preserve the user's - // stored toggles rather than recomputing them to "all disabled" — the - // toggles resume when low-tools mode is turned off again. - // phpcs:ignore WordPress.Security.NonceVerification.Missing - if ( isset( $_POST[ self::OPTION_LOW_TOOL_MODE ] ) && '1' === (string) wp_unslash( $_POST[ self::OPTION_LOW_TOOL_MODE ] ) ) { - $existing = get_option( self::OPTION_DISABLED_TOOLS, array() ); - return is_array( $existing ) ? array_values( array_intersect( $all_tools, $existing ) ) : array(); - } - $enabled = array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( isset( $_POST[ self::OPTION_DISABLED_TOOLS ] ) && is_array( $_POST[ self::OPTION_DISABLED_TOOLS ] ) ) { @@ -2630,12 +2601,6 @@ class EMCP_Tools_Admin { public function get_enabled_tool_count(): int { $all = $this->get_available_tool_slugs(); - // Low-tools mode overrides the per-tool toggles (see filter_disabled_tools): - // exactly the essentials are active. - if ( '1' === (string) get_option( self::OPTION_LOW_TOOL_MODE, '0' ) ) { - return count( array_intersect( $all, EMCP_Tools_Plugin::get_essential_tool_slugs() ) ); - } - $disabled = get_option( self::OPTION_DISABLED_TOOLS, array() ); if ( ! is_array( $disabled ) ) { $disabled = array(); diff --git a/includes/admin/views/page-connection.php b/includes/admin/views/page-connection.php index 7fa2374..4144a24 100644 --- a/includes/admin/views/page-connection.php +++ b/includes/admin/views/page-connection.php @@ -186,25 +186,14 @@ $emcp_tools_server_enabled = class_exists( 'EMCP_Tools_Plugin' )

- - - -
-

- - -

- + ' . esc_html__( 'Tools', 'emcp-tools' ) . '' + ); + ?>

diff --git a/includes/admin/views/page-tools.php b/includes/admin/views/page-tools.php index 5fa314e..fedc812 100644 --- a/includes/admin/views/page-tools.php +++ b/includes/admin/views/page-tools.php @@ -18,16 +18,14 @@ $emcp_tools_disabled = get_option( EMCP_Tools_Admin::OPTION_DISABLED_TOOLS, $emcp_tools_disabled = is_array( $emcp_tools_disabled ) ? $emcp_tools_disabled : array(); $emcp_tools_enabled_count = $this->get_enabled_tool_count(); $emcp_tools_total_count = $this->get_total_tool_count(); -$emcp_tools_low_mode = '1' === (string) get_option( EMCP_Tools_Admin::OPTION_LOW_TOOL_MODE, '0' ); -$emcp_tools_essentials = EMCP_Tools_Plugin::get_essential_tool_slugs(); +$emcp_tools_compact_mode = '1' === (string) get_option( EMCP_Tools_Plugin::OPTION_DISPATCHER_MODE, '0' ); $emcp_tools_tabs = EMCP_Tools_Admin::platform_tabs(); $emcp_tools_buckets = EMCP_Tools_Admin::partition_by_platform( $emcp_tools_all_tools ); $emcp_tools_elementor_active = EMCP_Tools_Bootstrap::elementor_active(); /** - * Per-tab enabled/total counts, computed with the same effective-state logic - * the category headers use (essentials in low-tools mode, else the stored set). + * Per-tab enabled/total counts, computed from the stored disabled set. */ $emcp_tools_tab_counts = array(); foreach ( $emcp_tools_buckets as $emcp_tools_tab_id => $emcp_tools_tab_cats ) { @@ -36,10 +34,7 @@ foreach ( $emcp_tools_buckets as $emcp_tools_tab_id => $emcp_tools_tab_cats ) { foreach ( $emcp_tools_tab_cats as $emcp_tools_cat ) { foreach ( $emcp_tools_cat['tools'] as $emcp_tools_s => $emcp_tools_unused ) { $emcp_tools_t_total++; - $emcp_tools_eff = $emcp_tools_low_mode - ? in_array( $emcp_tools_s, $emcp_tools_essentials, true ) - : ! in_array( $emcp_tools_s, $emcp_tools_disabled, true ); - if ( $emcp_tools_eff ) { + if ( ! in_array( $emcp_tools_s, $emcp_tools_disabled, true ) ) { $emcp_tools_t_enabled++; } } @@ -59,27 +54,27 @@ $emcp_tools_badge_labels = array( ); ?> -
+
@@ -111,16 +106,10 @@ $emcp_tools_badge_labels = array(
- -
+ +

- +

@@ -194,10 +183,7 @@ $emcp_tools_badge_labels = array( $emcp_tools_cat_total = count( $emcp_tools_category['tools'] ); $emcp_tools_cat_enabled = 0; foreach ( $emcp_tools_category['tools'] as $emcp_tools_slug => $emcp_tools_tool ) { - $emcp_tools_eff = $emcp_tools_low_mode - ? in_array( $emcp_tools_slug, $emcp_tools_essentials, true ) - : ! in_array( $emcp_tools_slug, $emcp_tools_disabled, true ); - if ( $emcp_tools_eff ) { + if ( ! in_array( $emcp_tools_slug, $emcp_tools_disabled, true ) ) { $emcp_tools_cat_enabled++; } } @@ -235,19 +221,16 @@ $emcp_tools_badge_labels = array(
$emcp_tools_tool ) : ?>