Changeset 3490060
- Timestamp:
- 03/24/2026 01:35:27 PM (12 days ago)
- Location:
- webmcp-bridge/trunk
- Files:
-
- 5 edited
-
admin/class-admin.php (modified) (2 diffs)
-
includes/class-rest-api.php (modified) (2 diffs)
-
includes/class-tools-core.php (modified) (7 diffs)
-
readme.txt (modified) (1 diff)
-
webmcp-bridge.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
webmcp-bridge/trunk/admin/class-admin.php
r3489235 r3490060 45 45 'enable_woo' => ! empty( $input['enable_woo'] ) ? 1 : 0, 46 46 'enable_nav' => ! empty( $input['enable_nav'] ) ? 1 : 0, 47 'rate_limit' => max( 10, min( 1000, (int) ( $input['rate_limit'] ?? 120 ) ) ), 48 'rate_window' => max( 10, min( 3600, (int) ( $input['rate_window'] ?? 60 ) ) ), 47 49 ]; 48 50 } … … 150 152 </tr> 151 153 </table> 154 <!-- Rate limiting --> 155 <tr> 156 <th scope="row"><?php esc_html_e( 'Rate limit (calls)', 'webmcp-bridge' ); ?></th> 157 <td> 158 <input type="number" name="webmcp_bridge_options[rate_limit]" min="10" max="1000" 159 value="<?php echo esc_attr( $options['rate_limit'] ?? 120 ); ?>" style="width:80px"> 160 <p class="description"><?php esc_html_e( 'Max /execute calls allowed in the time window (global, not per-IP). Default: 120.', 'webmcp-bridge' ); ?></p> 161 </td> 162 </tr> 163 <tr> 164 <th scope="row"><?php esc_html_e( 'Rate window (seconds)', 'webmcp-bridge' ); ?></th> 165 <td> 166 <input type="number" name="webmcp_bridge_options[rate_window]" min="10" max="3600" 167 value="<?php echo esc_attr( $options['rate_window'] ?? 60 ); ?>" style="width:80px"> 168 <p class="description"><?php esc_html_e( 'Time window in seconds for the rate limit counter. Default: 60.', 'webmcp-bridge' ); ?></p> 169 </td> 170 </tr> 152 171 <?php submit_button( esc_html__( 'Save Settings', 'webmcp-bridge' ), 'primary' ); ?> 153 172 </form> -
webmcp-bridge/trunk/includes/class-rest-api.php
r3489235 r3490060 18 18 19 19 /** 20 * Global rate limit for /execute endpoint. 21 * 22 * Why global and not per-IP? 23 * Per-IP limits are trivially bypassed with proxy rotation. 24 * A global counter limits the total server load regardless of source. 25 * The window and limit are filterable for sites with different needs. 26 * 27 * Defaults: 120 execute calls per 60 seconds across ALL visitors. 28 * Adjust via filters: webmcp_bridge_rate_limit and webmcp_bridge_rate_window. 29 */ 30 private function check_global_rate_limit(): bool { 31 $opts = get_option( 'webmcp_bridge_options', [] ); 32 $limit = (int) apply_filters( 'webmcp_bridge_rate_limit', $opts['rate_limit'] ?? 120 ); // max calls 33 $window = (int) apply_filters( 'webmcp_bridge_rate_window', $opts['rate_window'] ?? 60 ); // seconds 34 $key = 'webmcp_bridge_rate_' . gmdate( 'YmdHi' ) . '_' . (int) floor( gmdate( 's' ) / $window ); 35 36 $count = (int) get_transient( $key ); 37 if ( $count >= $limit ) { 38 return false; // rate limit exceeded 39 } 40 41 // Increment atomically via transient (best-effort — not a strict semaphore, 42 // but sufficient to throttle aggressive automated traffic) 43 set_transient( $key, $count + 1, $window * 2 ); 44 return true; 45 } 46 47 /** 20 48 * Tools that require a logged-in user or a valid WP REST nonce to execute. 21 49 * Filterable via webmcp_bridge_protected_tools so other plugins can extend the list. … … 108 136 109 137 public function execute_tool( WP_REST_Request $request ) { 138 // Global rate limit — checked before any processing. 139 if ( ! $this->check_global_rate_limit() ) { 140 return new WP_Error( 141 'rate_limited', 142 'Too many requests. Please slow down.', 143 [ 'status' => 429 ] 144 ); 145 } 146 110 147 // Tool name is already sanitized by the 'sanitize_callback' arg above. 111 148 $tool_name = $request->get_param( 'tool' ); -
webmcp-bridge/trunk/includes/class-tools-core.php
r3489235 r3490060 91 91 92 92 // ------------------------------------------------------------------------- 93 // Enhanced tools — only available when Mescio for Agents plugin is active. 94 // We check the specific classes used, not just the main class, so these 95 // tools are safely skipped if Mescio is present but in an unexpected state. 93 // Enhanced tools — only when Mescio for Agents plugin is active. 96 94 // ------------------------------------------------------------------------- 97 95 if ( class_exists( 'Mescio_For_Agents_Markdown' ) && class_exists( 'Mescio_For_Agents_Rest' ) ) { … … 173 171 'type' => $post->post_type, 174 172 'date' => $post->post_date, 175 'author' => get_the_author_meta( 'display_name', $post->post_author ), 173 // Note: author display_name intentionally omitted — not needed by agents 174 // and exposes internal user information. 176 175 ]; 177 176 } … … 216 215 public function tool_get_site_info( $params ) { 217 216 return [ 218 'name' => get_bloginfo( 'name' ),219 'description' => get_bloginfo( 'description' ),220 'url' => get_home_url(),221 ' admin_email' => get_bloginfo( 'admin_email' ),222 ' language' => get_bloginfo( 'language' ),223 'wp_version' => get_bloginfo( 'version' ),217 'name' => get_bloginfo( 'name' ), 218 'description' => get_bloginfo( 'description' ), 219 'url' => get_home_url(), 220 'language' => get_bloginfo( 'language' ), 221 'wp_version' => get_bloginfo( 'version' ), 222 // admin_email intentionally omitted — sensitive data, not needed by agents. 224 223 'mescio_for_agents' => class_exists( 'Mescio_For_Agents' ), 225 224 ]; … … 248 247 249 248 public function tool_get_markdown_content( $params ) { 250 // Guard on the specific Mescio classes actually used — keeps the two plugins decoupled.251 249 if ( ! class_exists( 'Mescio_For_Agents_Markdown' ) ) { 252 250 throw new Exception( 'Mescio for Agents plugin is not active or is outdated (Mescio_For_Agents_Markdown missing).' ); … … 271 269 } 272 270 273 // Mescio_For_Agents_Markdown::post_to_markdown( WP_Post ): string274 271 $markdown = Mescio_For_Agents_Markdown::post_to_markdown( $post ); 275 272 276 // Mescio_For_Agents_I18n::detect_post_language( WP_Post ): string — graceful fallback if missing277 273 $language = class_exists( 'Mescio_For_Agents_I18n' ) 278 274 ? Mescio_For_Agents_I18n::detect_post_language( $post ) 279 275 : get_bloginfo( 'language' ); 280 276 281 // Mescio_For_Agents_Markdown::estimate_tokens( string ): int — use real estimate if available282 277 $tokens = method_exists( 'Mescio_For_Agents_Markdown', 'estimate_tokens' ) 283 278 ? Mescio_For_Agents_Markdown::estimate_tokens( $markdown ) … … 297 292 298 293 public function tool_get_llms_txt( $params ) { 299 // Guard on the specific Mescio REST class.300 294 if ( ! class_exists( 'Mescio_For_Agents_Rest' ) ) { 301 295 throw new Exception( 'Mescio for Agents plugin is not active or is outdated (Mescio_For_Agents_Rest missing).' ); 302 296 } 303 297 304 $variant = strtolower( sanitize_key( $params['variant'] ?? 'index' ) ); 305 306 // Mescio_For_Agents_Rest::context_callback( WP_REST_Request ): WP_REST_Response 298 $variant = strtolower( sanitize_key( $params['variant'] ?? 'index' ) ); 307 299 $response = Mescio_For_Agents_Rest::context_callback( new WP_REST_Request( 'GET' ) ); 308 300 $context = $response->get_data(); … … 313 305 } 314 306 315 // Mescio_For_Agents_Llms::build_full(): string — pure PHP, no HTTP loopback316 307 $body = Mescio_For_Agents_Llms::build_full(); 317 308 -
webmcp-bridge/trunk/readme.txt
r3489247 r3490060 1 1 === WebMCP Bridge === 2 Contributors: vinsmach 2 Contributors: vinsmach, mescio 3 3 Tags: ai, mcp, webmcp, ai-agent, woocommerce 4 4 Requires at least: 6.0 5 5 Tested up to: 6.9 6 Stable tag: 1. 2.06 Stable tag: 1.3.0 7 7 Requires PHP: 8.0 8 8 License: GPLv2 or later -
webmcp-bridge/trunk/webmcp-bridge.php
r3489235 r3490060 4 4 * Plugin URI: https://wordpress.org/plugins/webmcp-bridge/ 5 5 * Description: Exposes WordPress functionality as WebMCP tools so AI agents can interact with your site natively in the browser — no backend MCP server required. 6 * Version: 1. 2.06 * Version: 1.3.0 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 8.0 … … 17 17 if ( ! defined( 'ABSPATH' ) ) exit; 18 18 19 define( 'WEBMCP_BRIDGE_VERSION', '1. 2.0' );19 define( 'WEBMCP_BRIDGE_VERSION', '1.3.0' ); 20 20 define( 'WEBMCP_BRIDGE_DIR', plugin_dir_path( __FILE__ ) ); 21 21 define( 'WEBMCP_BRIDGE_URL', plugin_dir_url( __FILE__ ) );
Note: See TracChangeset
for help on using the changeset viewer.