> $registry Registry. * @return array> */ function aafm_register_plugins_definitions( array $registry ): array { $registry['aafm/list-plugins'] = array( 'label' => __( 'List plugins', 'agent-abilities-for-mcp' ), 'description' => __( 'Lists installed plugins with their name, version, and active state. Read-only - it can never activate, deactivate, or change a plugin. Requires the activate-plugins capability.', 'agent-abilities-for-mcp' ), 'group' => 'reads', 'risk' => 'read', 'subject' => 'site', 'args_builder' => 'aafm_args_list_plugins', ); return $registry; } /** * Permission for aafm/list-plugins: activate_plugins. * * The same capability WordPress gates the Plugins screen behind. The check is object- * independent, so discovery can fall through to this callback with no server.php case. * * @return bool */ function aafm_perm_list_plugins(): bool { return current_user_can( 'activate_plugins' ); } /** * Args for aafm/list-plugins. * * @return array */ function aafm_args_list_plugins(): array { return array( 'label' => aafm_ability_label( 'aafm/list-plugins' ), 'description' => aafm_ability_description( 'aafm/list-plugins' ), 'category' => 'aafm-reads', 'input_schema' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => false, ), 'output_schema' => array( 'type' => 'object', 'properties' => array( 'plugins' => array( 'type' => 'array' ), ), ), 'execute_callback' => 'aafm_exec_list_plugins', 'permission_callback' => 'aafm_perm_list_plugins', 'meta' => array( 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true, ), ), ); } /** * Execute aafm/list-plugins. * * Returns the installed-plugin inventory. Each entry exposes the RELATIVE basename * (get_plugins() keys are relative to the plugins directory), the name, the version, and * the active state - never an absolute filesystem path. * * @return array */ function aafm_exec_list_plugins(): array { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $out = array(); foreach ( get_plugins() as $file => $data ) { $out[] = array( 'plugin' => $file, // Relative basename (e.g. akismet/akismet.php) - never an absolute path. 'name' => isset( $data['Name'] ) ? (string) $data['Name'] : '', 'version' => isset( $data['Version'] ) ? (string) $data['Version'] : '', 'active' => is_plugin_active( $file ), ); } return array( 'plugins' => $out ); }