diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
index 0bd3d6a..f8b4479 100644
--- a/src-tauri/capabilities/default.json
+++ b/src-tauri/capabilities/default.json
@@ -11,6 +11,7 @@
     { "identifier": "dialog:allow-open" },
     { "identifier": "shell:default" },
     { "identifier": "shell:allow-open" },
+    { "identifier": "shell:allow-execute" },
     { "identifier": "fs:default" },
     {
       "identifier": "fs:allow-read-dir",
diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs
index 72ca321..612a6d0 100644
--- a/src-tauri/src/commands/mod.rs
+++ b/src-tauri/src/commands/mod.rs
@@ -1,2 +1,3 @@
 pub mod plugin_commands;
-pub mod scan_commands;
\ No newline at end of file
+pub mod scan_commands;
+pub mod util_commands;
\ No newline at end of file
diff --git a/src-tauri/src/commands/plugin_commands.rs b/src-tauri/src/commands/plugin_commands.rs
index ead4b3e..d38b761 100644
--- a/src-tauri/src/commands/plugin_commands.rs
+++ b/src-tauri/src/commands/plugin_commands.rs
@@ -129,7 +129,8 @@ pub async fn update_plugin(
 pub async fn check_plugin_updates(
     app_handle: AppHandle,
     plugins: Vec<Plugin>,
-    repositories: Vec<String>
+    repositories: Vec<String>,
+    server_path: String
 ) -> Result<Vec<Plugin>, String> {
     // Convert repository strings to RepositorySource
     let repos: Vec<RepositorySource> = repositories.into_iter()
@@ -143,7 +144,26 @@ pub async fn check_plugin_updates(
         })
         .collect();
 
-    crate::services::update_manager::check_for_plugin_updates(app_handle, plugins, repos).await
+    // Get server info from the path for compatibility checking
+    let scan_result = match crate::services::plugin_scanner::perform_scan(&app_handle, &server_path).await {
+        Ok(result) => result,
+        Err(e) => {
+            println!("Warning: Could not get server info for compatibility check: {}", e);
+            // Create a minimal result with default server info
+            let server_info = crate::models::server::ServerInfo {
+                server_type: crate::models::server::ServerType::Unknown,
+                minecraft_version: None,
+                plugins_directory: format!("{}/plugins", server_path),
+                plugins_count: 0
+            };
+            crate::models::server::ScanResult {
+                server_info,
+                plugins: Vec::new()
+            }
+        }
+    };
+
+    crate::services::update_manager::check_for_plugin_updates(app_handle, plugins, repos, &scan_result.server_info).await
 }
 
 /// Check for updates for a single plugin
@@ -151,7 +171,8 @@ pub async fn check_plugin_updates(
 pub async fn check_single_plugin_update_command(
     app_handle: AppHandle,
     plugin: Plugin,
-    repositories: Vec<String>
+    repositories: Vec<String>,
+    server_path: Option<String>
 ) -> Result<(), String> {
     // Convert repository strings to RepositorySource
     let repos: Vec<RepositorySource> = repositories.into_iter()
@@ -165,7 +186,21 @@ pub async fn check_single_plugin_update_command(
         })
         .collect();
 
-    crate::services::update_manager::check_single_plugin_update(app_handle, plugin, repos).await
+    // Get server info if a path was provided
+    let server_info = if let Some(path) = server_path {
+        match crate::services::plugin_scanner::perform_scan(&app_handle, &path).await {
+            Ok(result) => Some(result.server_info),
+            Err(e) => {
+                println!("Warning: Could not get server info for compatibility check: {}", e);
+                None
+            }
+        }
+    } else {
+        None
+    };
+
+    // Pass the optional server info to the update function
+    crate::services::update_manager::check_single_plugin_update(app_handle, plugin, repos, server_info.as_ref()).await
 }
 
 /// Create a backup of a plugin file
diff --git a/src-tauri/src/commands/util_commands.rs b/src-tauri/src/commands/util_commands.rs
new file mode 100644
index 0000000..5bbd3b1
--- /dev/null
+++ b/src-tauri/src/commands/util_commands.rs
@@ -0,0 +1,17 @@
+use serde::Serialize;
+use tauri::command;
+use crate::*;
+
+// We will use this to return the app version from Cargo.toml
+#[derive(Debug, Serialize)]
+pub struct AppInfo {
+    pub version: String,
+}
+
+#[command]
+pub fn get_app_version() -> AppInfo {
+    // Return the crate version from Cargo.toml
+    AppInfo {
+        version: env!("CARGO_PKG_VERSION").to_string(),
+    }
+}
\ No newline at end of file
diff --git a/src-tauri/src/crawlers/github.rs b/src-tauri/src/crawlers/github.rs
index 316226b..b528ca4 100644
--- a/src-tauri/src/crawlers/github.rs
+++ b/src-tauri/src/crawlers/github.rs
@@ -7,6 +7,7 @@ use async_trait::async_trait;
 use std::sync::Arc;
 use crate::models::repository::RepositoryPlugin;
 use crate::crawlers::Repository;
+use regex;
 
 // GitHub API response structures (Based on https://docs.github.com/en/rest/releases/releases)
 
@@ -112,6 +113,82 @@ impl GitHubCrawler {
     }
 }
 
+// Helper function to extract Minecraft versions from text
+fn extract_minecraft_versions(body: Option<&str>, description: &str) -> Vec<String> {
+    let mut versions = Vec::new();
+
+    // Common version patterns
+    let version_pattern = regex::Regex::new(r"(?i)(1\.\d{1,2}(?:\.\d{1,2})?)").unwrap();
+
+    // Check release body
+    if let Some(text) = body {
+        for cap in version_pattern.captures_iter(text) {
+            if let Some(version) = cap.get(1) {
+                versions.push(version.as_str().to_string());
+            }
+        }
+    }
+
+    // Check description if we didn't find any versions
+    if versions.is_empty() {
+        for cap in version_pattern.captures_iter(description) {
+            if let Some(version) = cap.get(1) {
+                versions.push(version.as_str().to_string());
+            }
+        }
+    }
+
+    // If still empty, add a default
+    if versions.is_empty() {
+        versions.push("Unknown".to_string());
+    }
+
+    versions
+}
+
+// Helper function to extract supported loaders from text
+fn extract_loaders(body: Option<&str>, description: &str) -> Vec<String> {
+    let mut loaders = Vec::new();
+
+    // Check for common loader keywords
+    let mut check_for_loader = |text: &str, loader_name: &str| {
+        if text.to_lowercase().contains(&loader_name.to_lowercase()) {
+            loaders.push(loader_name.to_string());
+        }
+    };
+
+    // Process both body and description
+    let empty_string = String::new();
+    let body_str = body.unwrap_or("");
+
+    check_for_loader(body_str, "Paper");
+    check_for_loader(body_str, "Spigot");
+    check_for_loader(body_str, "Bukkit");
+    check_for_loader(body_str, "Forge");
+    check_for_loader(body_str, "Fabric");
+    check_for_loader(body_str, "Velocity");
+    check_for_loader(body_str, "BungeeCord");
+    check_for_loader(body_str, "Waterfall");
+
+    check_for_loader(description, "Paper");
+    check_for_loader(description, "Spigot");
+    check_for_loader(description, "Bukkit");
+    check_for_loader(description, "Forge");
+    check_for_loader(description, "Fabric");
+    check_for_loader(description, "Velocity");
+    check_for_loader(description, "BungeeCord");
+    check_for_loader(description, "Waterfall");
+
+    // If no loaders detected, assume Bukkit/Spigot/Paper as most common
+    if loaders.is_empty() {
+        loaders.push("Bukkit".to_string());
+        loaders.push("Spigot".to_string());
+        loaders.push("Paper".to_string());
+    }
+
+    loaders
+}
+
 #[async_trait]
 impl Repository for GitHubCrawler {
     fn get_repository_name(&self) -> String {
@@ -180,7 +257,7 @@ impl Repository for GitHubCrawler {
                     id: repo_full_name.to_string(),
                     name: repo.name,
                     version: release.tag_name,
-                    description: repo.description,
+                    description: repo.description.clone(),
                     authors: vec![repo.owner.login],
                     download_url: asset.browser_download_url.clone(),
                     repository: RepositorySource::GitHub,
@@ -188,12 +265,23 @@ impl Repository for GitHubCrawler {
                     download_count: Some(asset.download_count),
                     last_updated: Some(release.published_at),
                     icon_url: repo.owner.avatar_url,
-                    minecraft_versions: Vec::new(),
+                    minecraft_versions: extract_minecraft_versions(
+                        release.body.as_deref(),
+                        &repo.description.clone().unwrap_or_default()
+                    ),
                     categories: Vec::new(),
                     rating: Some(repo.stargazers_count as f32),
                     file_size: Some(asset.size),
                     file_hash: None,
-                    changelog: release.body,
+                    changelog: release.body.clone(),
+                    loaders: extract_loaders(
+                        release.body.as_deref(),
+                        &repo.description.clone().unwrap_or_default()
+                    ),
+                    supported_versions: extract_minecraft_versions(
+                        release.body.as_deref(),
+                        &repo.description.clone().unwrap_or_default()
+                    ),
                 })
             } else {
                  Err(format!("No suitable JAR asset found in the latest valid release for {}", repo_full_name))
diff --git a/src-tauri/src/crawlers/hangar.rs b/src-tauri/src/crawlers/hangar.rs
index e04534d..0c4f3e5 100644
--- a/src-tauri/src/crawlers/hangar.rs
+++ b/src-tauri/src/crawlers/hangar.rs
@@ -34,6 +34,9 @@ struct HangarProject {
     icon_url: Option<String>,
     created_at: String,
     visibility: String,
+    game_versions: Vec<String>,
+    platform: String,
+    categories: Vec<String>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -138,12 +141,14 @@ impl Repository for HangarCrawler {
                 download_count: Some(proj.stats.downloads),
                 last_updated: Some(proj.last_updated),
                 icon_url: proj.icon_url.clone(),
-                minecraft_versions: Vec::new(),
-                categories: vec![proj.category.to_string()],
+                minecraft_versions: proj.game_versions.clone(),
+                categories: proj.categories.clone(),
                 rating: Some(proj.stats.stars as f32),
                 file_size: None,
                 file_hash: None,
                 changelog: None,
+                loaders: vec![proj.platform.clone()],
+                supported_versions: proj.game_versions.clone(),
             }
         }).collect();
 
@@ -184,12 +189,14 @@ impl Repository for HangarCrawler {
             download_count: Some(project.stats.downloads),
             last_updated: Some(project.last_updated),
             icon_url: project.icon_url.clone(),
-            minecraft_versions: versions.first().map_or(Vec::new(), |v| v.platform_versions.clone()),
-            categories: vec![project.category.to_string()],
+            minecraft_versions: project.game_versions.clone(),
+            categories: project.categories.clone(),
             rating: Some(project.stats.stars as f32),
             file_size: versions.first().map(|v| v.file_size),
             file_hash: None,
             changelog: None,
+            loaders: vec![project.platform.clone()],
+            supported_versions: project.game_versions.clone(),
         })
     }
 
diff --git a/src-tauri/src/crawlers/modrinth.rs b/src-tauri/src/crawlers/modrinth.rs
index cdb98c4..4943915 100644
--- a/src-tauri/src/crawlers/modrinth.rs
+++ b/src-tauri/src/crawlers/modrinth.rs
@@ -217,6 +217,8 @@ impl ModrinthCrawler {
             file_size: primary_file.map(|f| f.size),
             file_hash: primary_file.map(|f| f.hashes.sha512.clone()), // Use SHA512
             changelog,
+            loaders: latest_version_opt.map_or(Vec::new(), |v| v.loaders.clone()),
+            supported_versions: latest_version_opt.map_or(project.game_versions.clone(), |v| v.game_versions.clone()),
         })
     }
 
@@ -334,6 +336,8 @@ impl Repository for ModrinthCrawler {
                 file_size: None,
                 file_hash: None,
                 changelog: None,
+                loaders: Vec::new(),
+                supported_versions: Vec::new(),
             };
             results.push(repo_plugin);
         }
diff --git a/src-tauri/src/crawlers/spigotmc.rs b/src-tauri/src/crawlers/spigotmc.rs
index 708a6e3..89e8376 100644
--- a/src-tauri/src/crawlers/spigotmc.rs
+++ b/src-tauri/src/crawlers/spigotmc.rs
@@ -172,6 +172,8 @@ impl SpigotMCCrawler {
             file_size: file_size_bytes,
             file_hash: None, // SpiGet does not provide hashes
             changelog: None, // Needs separate call to /updates/latest
+            loaders: vec!["Spigot".to_string(), "Paper".to_string()], // SpigotMC resources typically work on Spigot and Paper
+            supported_versions: resource.tested_versions.clone(), // Same as minecraft_versions
         }
     }
 
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index c61e9e2..7e36d8a 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -28,6 +28,7 @@ pub use services::update_manager::{check_for_plugin_updates, check_single_plugin
 // Import our commands
 pub use commands::plugin_commands::*;
 pub use commands::scan_commands::*;
+pub use commands::util_commands::*;
 
 // Import our crawlers
 pub use crawlers::HangarCrawler;
@@ -142,7 +143,7 @@ pub async fn lib_search_plugins_in_repositories(
     Ok(plugins)
 }
 
-/// Generate search variations for a plugin name
+/// Generate search variations for a plugin name using advanced techniques
 fn generate_search_variations(plugin_name: &str) -> Vec<String> {
     let mut variations = Vec::new();
 
@@ -155,31 +156,272 @@ fn generate_search_variations(plugin_name: &str) -> Vec<String> {
         variations.push(name_lower.clone());
     }
 
+    // Normalize whitespace and separators
+    let normalized = normalize_separators(&name_lower);
+    if normalized != name_lower {
+        variations.push(normalized.clone());
+    }
+
+    // Extract core name by removing common prefixes/suffixes
+    let core_name = extract_core_name(&normalized);
+    if !core_name.is_empty() && core_name != normalized {
+        variations.push(core_name.clone());
+    }
+
+    // Handle common abbreviations and full forms
+    variations.extend(expand_abbreviations(&core_name));
+
+    // Handle word re-ordering for multi-word plugin names
+    if core_name.contains(' ') {
+        let words: Vec<&str> = core_name.split_whitespace().collect();
+        if words.len() > 1 && words.len() <= 4 { // Only try reordering for 2-4 word names
+            // Add key words without modifiers
+            let significant_words: Vec<&str> = words.iter()
+                .filter(|w| w.len() > 3 && !is_common_modifier(w))
+                .copied()
+                .collect();
+
+            if significant_words.len() > 0 && significant_words.len() < words.len() {
+                variations.push(significant_words.join(" "));
+            }
+        }
+    }
+
+    // Special handling for plugins that often include terms like "API", "Core", etc.
+    if core_name.contains("api") {
+        variations.push(core_name.replace("api", "").trim().to_string());
+    }
+
+    if core_name.contains("core") {
+        variations.push(core_name.replace("core", "").trim().to_string());
+    }
+
+    // Handle plugins that might be searched by acronym
+    // (e.g., "WorldEditCUI" -> "WECUI")
+    if let Some(acronym) = generate_acronym(&core_name) {
+        if acronym.len() >= 2 {
+            variations.push(acronym);
+        }
+    }
+
     // Add variations with common prefixes/suffixes removed
-    let prefixes = ["plugin", "mc", "minecraft"];
-    let suffixes = ["plugin", "spigot", "bukkit", "paper", "mc"];
+    // This is more comprehensive than the original
+    let prefixes = ["plugin", "mc", "minecraft", "bukkit", "spigot", "paper", "forge", "fabric"];
+    let suffixes = ["plugin", "spigot", "bukkit", "paper", "mc", "forge", "fabric", "addon", "plus", "+", "mod"];
 
     for prefix in prefixes.iter() {
-        let prefix_str = format!("{} ", prefix);
-        if name_lower.starts_with(&prefix_str) {
-            variations.push(name_lower[prefix_str.len()..].to_string());
+        // Check for space or separator after prefix
+        let prefix_patterns = [
+            format!("{} ", prefix),      // "prefix "
+            format!("{}-", prefix),      // "prefix-"
+            format!("{}:", prefix),      // "prefix:"
+            format!("{}core", prefix),   // "prefixcore"
+        ];
+
+        for pattern in prefix_patterns {
+            if name_lower.starts_with(&pattern) {
+                variations.push(name_lower[pattern.len()..].trim().to_string());
+            }
         }
     }
 
     for suffix in suffixes.iter() {
-        let suffix_str = format!(" {}", suffix);
-        if name_lower.ends_with(&suffix_str) {
-            variations.push(name_lower[0..name_lower.len() - suffix_str.len()].to_string());
+        // Check for space or separator before suffix
+        let suffix_patterns = [
+            format!(" {}", suffix),      // " suffix"
+            format!("-{}", suffix),      // "-suffix"
+            format!(":{}", suffix),      // ":suffix"
+            format!("for{}", suffix),    // "forsuffix"
+        ];
+
+        for pattern in suffix_patterns {
+            if name_lower.ends_with(&pattern) {
+                variations.push(name_lower[0..name_lower.len() - pattern.len()].trim().to_string());
+            }
         }
     }
 
-    // Remove duplicates
+    // Remove duplicates and empty strings
+    variations.retain(|s| !s.is_empty());
     variations.sort();
     variations.dedup();
 
+    // Debug: print variations
+    println!("Generated {} search variations for '{}':", variations.len(), plugin_name);
+    for (i, v) in variations.iter().enumerate() {
+        println!("  {}: '{}'", i+1, v);
+    }
+
     variations
 }
 
+/// Normalize separators in a plugin name
+fn normalize_separators(name: &str) -> String {
+    let mut result = name.to_lowercase();
+
+    // Replace various separators with spaces
+    result = result.replace('-', " ");
+    result = result.replace('_', " ");
+    result = result.replace('.', " ");
+
+    // Normalize spaces (multiple spaces to single space)
+    while result.contains("  ") {
+        result = result.replace("  ", " ");
+    }
+
+    result.trim().to_string()
+}
+
+/// Extract the core name by removing common prefixes/suffixes
+fn extract_core_name(name: &str) -> String {
+    let mut result = name.to_lowercase();
+
+    // Common prefixes to remove
+    let prefixes = [
+        "the ", "a ", "an ", "official ", "premium ", "free ",
+        "minecraft ", "mc ", "bukkit ", "spigot ", "paper ",
+    ];
+
+    // Common suffixes to remove
+    let suffixes = [
+        " plugin", " mod", " addon", " plus", " ++", " +", " pro",
+        " free", " premium", " lite", " light", " full", " version",
+    ];
+
+    // Remove prefixes
+    for prefix in &prefixes {
+        if result.starts_with(prefix) {
+            result = result[prefix.len()..].to_string();
+        }
+    }
+
+    // Remove suffixes
+    for suffix in &suffixes {
+        if result.ends_with(suffix) {
+            result = result[..result.len() - suffix.len()].to_string();
+        }
+    }
+
+    // Remove version numbers at the end
+    // Examples: "Plugin 1.0", "Plugin v2", "Plugin 2.0.1"
+    if let Some(index) = result.rfind(|c: char| c == ' ' || c == 'v') {
+        let potential_version = &result[index+1..];
+        if potential_version.chars().all(|c| c.is_digit(10) || c == '.') {
+            result = result[..index].to_string();
+        }
+    }
+
+    result.trim().to_string()
+}
+
+/// Generate possible expansions of abbreviations
+fn expand_abbreviations(name: &str) -> Vec<String> {
+    let mut expansions = Vec::new();
+
+    // Common abbreviations in plugin names
+    let abbreviations = [
+        ("gui", vec!["graphical user interface"]),
+        ("ui", vec!["user interface"]),
+        ("api", vec!["application programming interface", "interface"]),
+        ("cmds", vec!["commands"]),
+        ("cmd", vec!["command"]),
+        ("mgr", vec!["manager"]),
+        ("mgmt", vec!["management"]),
+        ("auth", vec!["authentication", "authenticator"]),
+        ("eco", vec!["economy"]),
+        ("tp", vec!["teleport", "teleporter"]),
+        ("inv", vec!["inventory"]),
+        ("prot", vec!["protection", "protector"]),
+        ("chat", vec!["chatter"]),
+        ("admin", vec!["administrator", "administration"]),
+        ("perms", vec!["permissions"]),
+        ("essentials", vec!["ess"]),
+        ("warp", vec!["warps"]),
+        ("spawn", vec!["spawner", "spawns"]),
+        ("we", vec!["worldedit", "world edit"]),
+        ("wb", vec!["worldborder", "world border"]),
+        ("wg", vec!["worldguard", "world guard"]),
+        ("lb", vec!["logblock", "log block"]),
+        ("gui", vec!["menu", "interface"]),
+    ];
+
+    let words: Vec<&str> = name.split_whitespace().collect();
+
+    // Try replacing abbreviations in each word
+    for (abbr, expansions_list) in &abbreviations {
+        for (i, word) in words.iter().enumerate() {
+            if word == abbr {
+                for expansion in expansions_list {
+                    // Replace this word with the expansion
+                    let mut new_words = words.clone();
+                    new_words[i] = expansion;
+                    expansions.push(new_words.join(" "));
+                }
+            }
+        }
+    }
+
+    // Also try abbreviating common terms
+    for (abbr, expansions_list) in &abbreviations {
+        for expansion in expansions_list {
+            if name.contains(expansion) {
+                expansions.push(name.replace(expansion, abbr));
+            }
+        }
+    }
+
+    expansions
+}
+
+/// Generate an acronym from a plugin name (e.g., "WorldEditCUI" -> "WECUI")
+fn generate_acronym(name: &str) -> Option<String> {
+    // Method 1: CamelCase splitting
+    let mut acronym = String::new();
+    let chars: Vec<char> = name.chars().collect();
+
+    // Special handling for CamelCase
+    for i in 0..chars.len() {
+        if i == 0 {
+            // Always include first character
+            acronym.push(chars[i].to_ascii_uppercase());
+        } else if chars[i].is_uppercase() && (i == 0 || !chars[i-1].is_uppercase()) {
+            // Include uppercase letters that start a new word
+            acronym.push(chars[i]);
+        }
+    }
+
+    // Method 2: Word splitting
+    if acronym.len() <= 1 {
+        acronym.clear();
+        let words: Vec<&str> = name.split(|c: char| c == ' ' || c == '-' || c == '_').collect();
+
+        // Take first letter of each word
+        for word in words {
+            if !word.is_empty() {
+                if let Some(c) = word.chars().next() {
+                    acronym.push(c.to_ascii_uppercase());
+                }
+            }
+        }
+    }
+
+    if acronym.len() >= 2 {
+        Some(acronym)
+    } else {
+        None
+    }
+}
+
+/// Check if a word is a common modifier that doesn't add much meaning
+fn is_common_modifier(word: &str) -> bool {
+    let modifiers = [
+        "the", "a", "an", "of", "for", "with", "and", "or", "in", "on", "by",
+        "to", "from", "lite", "pro", "premium", "free", "plus"
+    ];
+
+    modifiers.contains(&word.to_lowercase().as_str())
+}
+
 /// Search for plugin variations
 pub async fn search_with_variations(plugin_name: &str, repositories: &[RepositorySource]) -> Result<Vec<RepositoryPlugin>, String> {
     let variations = generate_search_variations(plugin_name);
@@ -332,6 +574,7 @@ pub fn run() {
       get_potential_plugin_matches,
       compare_versions,
       is_plugin_compatible,
+      get_app_version,
       greet
     ])
     .run(tauri::generate_context!())
diff --git a/src-tauri/src/models/plugin.rs b/src-tauri/src/models/plugin.rs
index b798b0f..11d2781 100644
--- a/src-tauri/src/models/plugin.rs
+++ b/src-tauri/src/models/plugin.rs
@@ -2,6 +2,15 @@ use serde::{Serialize, Deserialize};
 
 use super::repository::RepositorySource;
 
+/// Enum representing plugin compatibility status with a server
+#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
+pub enum PluginCompatibilityStatus {
+    Compatible,
+    IncompatibleLoader,
+    IncompatibleMinecraftVersion,
+    Unknown
+}
+
 /// Represents a Minecraft plugin with detailed information
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct Plugin {
@@ -22,6 +31,9 @@ pub struct Plugin {
     pub file_path: String,
     pub file_hash: String,
     pub changelog: Option<String>, // Changelog for the latest version
+    // Compatibility fields
+    pub compatibility_status: Option<PluginCompatibilityStatus>,
+    pub platform_compatibility: Option<Vec<String>>, // List of compatible platforms/loaders
     // Fields for persistence
     pub repository_source: Option<RepositorySource>,
     pub repository_id: Option<String>,
diff --git a/src-tauri/src/models/repository.rs b/src-tauri/src/models/repository.rs
index 04c6169..eab1973 100644
--- a/src-tauri/src/models/repository.rs
+++ b/src-tauri/src/models/repository.rs
@@ -34,6 +34,8 @@ pub struct RepositoryPlugin {
     pub file_size: Option<u64>,
     pub file_hash: Option<String>,
     pub changelog: Option<String>, // Changelog information for latest version
+    pub loaders: Vec<String>,      // Platforms/loaders this plugin supports (Paper, Spigot, etc.)
+    pub supported_versions: Vec<String>, // Minecraft versions this plugin supports
 }
 
 /// Trait for crawler implementors with object safety
diff --git a/src-tauri/src/services/plugin_scanner/scanner.rs b/src-tauri/src/services/plugin_scanner/scanner.rs
index c2390e0..cb22640 100644
--- a/src-tauri/src/services/plugin_scanner/scanner.rs
+++ b/src-tauri/src/services/plugin_scanner/scanner.rs
@@ -153,6 +153,8 @@ pub async fn perform_scan(app_handle: &AppHandle, path: &str) -> Result<ScanResu
                     file_path: meta.file_path,
                     file_hash: meta.file_hash,
                     changelog: None, // Will be populated during update check
+                    compatibility_status: None, // Will be populated during update check
+                    platform_compatibility: None, // Will be populated during update check
                     repository_source: None, // Will be populated during update check
                     repository_id: None, // Will be populated during update check
                     repository_url: None, // Will be populated during update check
diff --git a/src-tauri/src/services/update_manager/update_checker.rs b/src-tauri/src/services/update_manager/update_checker.rs
index fa39387..696f061 100644
--- a/src-tauri/src/services/update_manager/update_checker.rs
+++ b/src-tauri/src/services/update_manager/update_checker.rs
@@ -1,15 +1,17 @@
 use tauri::{AppHandle, Emitter};
-use futures::stream::StreamExt;
 
-use crate::models::plugin::Plugin;
+use crate::models::plugin::{Plugin, PluginCompatibilityStatus};
 use crate::models::repository::{RepositorySource, RepositoryPlugin, BulkUpdateProgress, SingleUpdateResult};
-use super::version_utils::compare_plugin_versions;
+use crate::models::server::{ServerInfo, ServerType};
+use super::version_utils::is_version_compatible;
+use crate::platform_matcher::is_version_compatible_with_server;
 
 /// Check for updates for multiple plugins
 pub async fn check_for_plugin_updates(
     app_handle: AppHandle,
     installed_plugins: Vec<Plugin>,
-    repositories_to_check: Vec<RepositorySource>
+    repositories_to_check: Vec<RepositorySource>,
+    server_info: &ServerInfo,
 ) -> Result<Vec<Plugin>, String> {
     if installed_plugins.is_empty() {
         return Ok(Vec::new());
@@ -37,6 +39,7 @@ pub async fn check_for_plugin_updates(
             let app_handle_clone = app_handle.clone();
             let repos_clone = repositories_to_check.clone();
             let plugin_clone = plugin.clone();
+            let server_info_clone = server_info.clone();
 
             // Report progress
             let progress = BulkUpdateProgress {
@@ -53,7 +56,7 @@ pub async fn check_for_plugin_updates(
             batch_futures.push(async move {
                 // Process plugin
                 println!("Processing update for plugin {}/{}: {}", index + 1, total, plugin_clone.name);
-                let result = process_plugin_update(plugin_clone.clone(), &repos_clone).await;
+                let result = process_plugin_update(plugin_clone.clone(), &repos_clone, &server_info_clone).await;
                 (index, result)
             });
         }
@@ -97,6 +100,7 @@ pub async fn check_single_plugin_update(
     app_handle: AppHandle,
     plugin_to_check: Plugin,
     repositories_to_check: Vec<RepositorySource>,
+    server_info: Option<&ServerInfo>,
 ) -> Result<(), String> { // Returns Result<(), String> because result is sent via event
     // Begin check
     if let Err(e) = app_handle.emit("single_update_check_started", plugin_to_check.name.clone()) {
@@ -104,7 +108,19 @@ pub async fn check_single_plugin_update(
     }
 
     // Process update
-    let updated_plugin = process_plugin_update(plugin_to_check.clone(), &repositories_to_check).await;
+    let updated_plugin = match server_info {
+        Some(info) => process_plugin_update(plugin_to_check.clone(), &repositories_to_check, info).await,
+        None => {
+            // Create a minimal server info if none provided
+            let default_info = ServerInfo {
+                server_type: ServerType::Unknown,
+                minecraft_version: None,
+                plugins_directory: String::new(),
+                plugins_count: 0
+            };
+            process_plugin_update(plugin_to_check.clone(), &repositories_to_check, &default_info).await
+        }
+    };
 
     // Create result
     let result = SingleUpdateResult {
@@ -122,26 +138,57 @@ pub async fn check_single_plugin_update(
 }
 
 /// Process update check for a single plugin
-async fn process_plugin_update(plugin: Plugin, repositories: &[RepositorySource]) -> Plugin {
+async fn process_plugin_update(plugin: Plugin, repositories: &[RepositorySource], server_info: &ServerInfo) -> Plugin {
     let mut updated_plugin = plugin.clone();
     println!("Checking for updates for plugin: {}", plugin.name);
 
     // If plugin already has repository info, check that specific repo
     if let (Some(repo_source), Some(repo_id)) = (&plugin.repository_source, &plugin.repository_id) {
         println!("Plugin has existing repository info: {:?}, ID: {}", repo_source, repo_id);
-        match crate::lib_get_plugin_details_from_repository(repo_id, repo_source.clone(), None).await {
+        let result = crate::lib_get_plugin_details_from_repository(repo_id, repo_source.clone(), Some(&server_info.server_type)).await;
+
+        match result {
             Ok(repo_plugin) => {
                 println!("Successfully got details from repository for {}", plugin.name);
-                update_plugin_from_repo(&mut updated_plugin, &repo_plugin);
+                // Verify that the retrieved plugin still matches
+                if is_likely_match(&plugin, &repo_plugin) {
+                    update_plugin_from_repo(&mut updated_plugin, &repo_plugin, server_info);
+                } else {
+                    println!("Warning: Retrieved plugin no longer matches! Clearing repository info and trying again");
+                    // Clear repository info and try smart matching
+                    updated_plugin.repository_source = None;
+                    updated_plugin.repository_id = None;
+                    updated_plugin = retry_with_smart_matching(updated_plugin, repositories, server_info).await;
+                }
             },
             Err(e) => {
                 println!("Failed to get update details for {}: {}", plugin.name, e);
+                // If we failed with the saved repository, try smart matching instead
+                updated_plugin = retry_with_smart_matching(updated_plugin, repositories, server_info).await;
             }
         }
+
+        // If we have no latest_version set but we have a version, set the latest_version
+        // to the current version to show it's up-to-date
+        if updated_plugin.latest_version.is_none() {
+            updated_plugin.latest_version = Some(updated_plugin.version.clone());
+            updated_plugin.has_update = false;
+        }
+
         return updated_plugin;
     }
 
     // Otherwise, try smart matching with repositories
+    updated_plugin = retry_with_smart_matching(updated_plugin, repositories, server_info).await;
+
+    println!("Update check complete for plugin: {}", plugin.name);
+    updated_plugin
+}
+
+/// Helper function to perform smart matching when no repository info exists or previous check failed
+async fn retry_with_smart_matching(plugin: Plugin, repositories: &[RepositorySource], server_info: &ServerInfo) -> Plugin {
+    let mut updated_plugin = plugin.clone();
+
     println!("No repository info for {}. Trying smart matching...", plugin.name);
     let matches = match crate::search_with_variations(&plugin.name, repositories).await {
         Ok(matches) => {
@@ -150,94 +197,636 @@ async fn process_plugin_update(plugin: Plugin, repositories: &[RepositorySource]
         },
         Err(e) => {
             println!("Error searching for plugin {}: {}", plugin.name, e);
+            // If we failed to find matches, set latest_version to current version
+            // to indicate it's up-to-date as far as we know
+            updated_plugin.latest_version = Some(updated_plugin.version.clone());
+            updated_plugin.has_update = false;
             return updated_plugin;
         }
     };
 
     // Find best match
-    for repo_plugin in matches {
-        if is_likely_match(&plugin, &repo_plugin) {
-            println!("Found likely match for {} in {:?}: {} ({})",
-                     plugin.name, repo_plugin.repository, repo_plugin.name, repo_plugin.version);
-            update_plugin_from_repo(&mut updated_plugin, &repo_plugin);
-            break;
+    let mut found_match = false;
+    let mut best_match_score = 0.0f32;
+    let mut best_match_index = 0;
+
+    // First pass: evaluate all matches to find the best one
+    for (i, repo_plugin) in matches.iter().enumerate() {
+        let match_score = calculate_match_score(&plugin, repo_plugin);
+        if match_score > best_match_score {
+            best_match_score = match_score;
+            best_match_index = i;
         }
     }
 
-    println!("Update check complete for plugin: {}", plugin.name);
+    // Second pass: if we found a likely match, use it
+    if best_match_score >= 3.0f32 && best_match_index < matches.len() {
+        let repo_plugin = &matches[best_match_index];
+
+        println!("Found likely match for {} in {:?}: {} ({})",
+                 plugin.name, repo_plugin.repository, repo_plugin.name, repo_plugin.version);
+
+        update_plugin_from_repo(&mut updated_plugin, repo_plugin, server_info);
+        found_match = true;
+    }
+
+    // If no match was found, set latest_version to current version
+    if !found_match {
+        updated_plugin.latest_version = Some(updated_plugin.version.clone());
+        updated_plugin.has_update = false;
+    }
+
     updated_plugin
 }
 
+/// Calculate a match score between an installed plugin and a repository plugin
+fn calculate_match_score(installed: &Plugin, repo: &RepositoryPlugin) -> f32 {
+    if is_likely_match(installed, repo) {
+        // Get detailed score for debugging and sorting purposes
+        let mut score = 0.0f32;
+
+        // Name similarity
+        let similarity = calculate_name_similarity(&installed.name, &repo.name);
+        if similarity == 1.0f32 {
+            score += 5.0f32; // Exact name match
+        } else if similarity > 0.9f32 {
+            score += 3.0f32; // Strong name match
+        } else if similarity > 0.7f32 {
+            score += 2.0f32; // Moderate name match
+        } else if similarity > 0.5f32 {
+            score += 1.0f32; // Weak name match
+        }
+
+        // Main class match
+        if let Some(main_class) = &installed.main_class {
+            if main_class.to_lowercase().contains(&repo.name.to_lowercase()) {
+                score += 3.0f32;
+            }
+        }
+
+        // Author match
+        if !installed.authors.is_empty() && !repo.authors.is_empty() {
+            for installed_author in &installed.authors {
+                for repo_author in &repo.authors {
+                    if installed_author.to_lowercase() == repo_author.to_lowercase() {
+                        score += 2.0f32;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Website match
+        if let Some(website) = &installed.website {
+            if website.contains(&repo.page_url) || repo.page_url.contains(website) {
+                score += 2.0f32;
+            }
+        }
+
+        // Check for matching plugin name and author
+        let repo_name_lower = repo.name.to_lowercase();
+
+        // Handle the case where installed.depend is an Option<Vec<String>>
+        if let Some(depend) = &installed.depend {
+            if !depend.is_empty() && depend.len() > 1 {
+                // Score bump if repo_name appears in dependencies
+                let depend_str = depend.join(",").to_lowercase();
+                if depend_str.contains(&repo_name_lower) {
+                    score += 3.0f32;
+                }
+            }
+
+            // Score bump if the plugin name matches or is contained in any dependency
+            if depend.iter().any(|dep| repo_name_lower.contains(&dep.to_lowercase())) {
+                score += 5.0f32;
+            }
+        }
+
+        // More detailed scoring can be added here
+
+        return score;
+    }
+
+    0.0f32 // Not a match
+}
+
 /// Update plugin with repository information
-fn update_plugin_from_repo(plugin: &mut Plugin, repo_plugin: &RepositoryPlugin) {
+fn update_plugin_from_repo(plugin: &mut Plugin, repo_plugin: &RepositoryPlugin, server_info: &ServerInfo) {
+    // Get server platform information
+    let server_loader = server_type_to_loader_name(&server_info.server_type);
+
+    // Extract platform suffixes from repo version
+    let repo_platform = crate::services::update_manager::version_utils::extract_platform_suffix(&repo_plugin.version);
+
     // Set repository information
     plugin.repository_source = Some(repo_plugin.repository.clone());
     plugin.repository_id = Some(repo_plugin.id.clone());
     plugin.repository_url = Some(repo_plugin.page_url.clone());
 
+    // Set platform compatibility information
+    if !repo_plugin.loaders.is_empty() {
+        // Clean and format the loader names for display
+        let formatted_loaders: Vec<String> = repo_plugin.loaders.iter()
+            .map(|loader| {
+                let loader_lower = loader.to_lowercase();
+                // Standard naming conversion
+                if loader_lower == "paper" { "Paper".to_string() }
+                else if loader_lower == "spigot" { "Spigot".to_string() }
+                else if loader_lower == "bukkit" { "Bukkit".to_string() }
+                else if loader_lower == "forge" { "Forge".to_string() }
+                else if loader_lower == "neoforge" { "NeoForge".to_string() }
+                else if loader_lower == "fabric" { "Fabric".to_string() }
+                else if loader_lower == "quilt" { "Quilt".to_string() }
+                else if loader_lower == "velocity" { "Velocity".to_string() }
+                else if loader_lower == "bungeecord" { "BungeeCord".to_string() }
+                else if loader_lower == "waterfall" { "Waterfall".to_string() }
+                else if loader_lower == "sponge" { "Sponge".to_string() }
+                else { loader.clone() } // Just use original if not recognized
+            })
+            .collect();
+
+        plugin.platform_compatibility = Some(formatted_loaders);
+        println!("  Setting platform compatibility for {}: {:?}", plugin.name, plugin.platform_compatibility);
+    }
+
+    // If repo version has a specific platform suffix, check against server type
+    let is_platform_specific = if let Some(platform) = repo_platform {
+        // Check if platform suffix is compatible with server type
+        let platform_compatible =
+            if let Some(server_platform) = server_loader {
+                // Both have specified platforms, check if compatible
+                is_platform_compatible(&platform, server_platform)
+            } else {
+                // Server platform unknown, be conservative
+                false
+            };
+
+        if !platform_compatible {
+            println!("  Repo version {} has incompatible platform suffix: {}",
+                     repo_plugin.version, platform);
+            // Mark as incompatible but still track the version
+            plugin.compatibility_status = Some(PluginCompatibilityStatus::IncompatibleLoader);
+        }
+
+        // Return whether this version is platform-specific
+        true
+    } else {
+        false
+    };
+
     // For Modrinth, check if the version looks like an ID instead of a version number
     let latest_version = if repo_plugin.repository == RepositorySource::Modrinth &&
                           repo_plugin.version.len() >= 8 &&
                           !repo_plugin.version.contains('.') {
         // This looks like an ID rather than a version, use "Latest" as a fallback
+        // TODO: Potentially fetch actual version number if needed later
         "Latest".to_string()
     } else {
         repo_plugin.version.clone()
     };
 
-    // Set latest version if newer
-    if latest_version != plugin.version {
-        let has_update = compare_plugin_versions(&plugin.version, &latest_version);
+    // Set latest version and check compatibility
+    let has_newer_version = crate::services::update_manager::version_utils::compare_plugin_versions(
+        &plugin.version, &latest_version);
+
+    if has_newer_version {
+        println!("  Detected newer version for {}: {} -> {}", plugin.name, plugin.version, latest_version);
+
+        // Check loader compatibility using the platform matcher
+        let is_loader_compatible = if is_platform_specific {
+            // We already checked platform compatibility above
+            plugin.compatibility_status != Some(PluginCompatibilityStatus::IncompatibleLoader)
+        } else {
+            // No platform suffix in version, check loaders list
+            is_version_compatible_with_server(
+                &repo_plugin.loaders,
+                &server_info.server_type
+            )
+        };
+
+        // Check Minecraft version compatibility
+        let is_mc_version_compatible = if let Some(mc_version) = &server_info.minecraft_version {
+            // Only check if we have a server Minecraft version
+            is_version_compatible(mc_version, &repo_plugin.supported_versions)
+        } else {
+            // If we don't know the server version, assume it's compatible
+            true
+        };
+
         plugin.latest_version = Some(latest_version);
-        plugin.has_update = has_update;
+        // Only set has_update to true if all compatibility checks pass
+        plugin.has_update = is_loader_compatible && is_mc_version_compatible;
         plugin.changelog = repo_plugin.changelog.clone();
+
+        // Set compatibility status based on checks
+        if !is_loader_compatible {
+            plugin.compatibility_status = Some(PluginCompatibilityStatus::IncompatibleLoader);
+            println!("  Update found ({}) for {}, but loader is incompatible with server type {:?}",
+                plugin.latest_version.as_deref().unwrap_or("?"),
+                plugin.name,
+                server_info.server_type
+            );
+        } else if !is_mc_version_compatible {
+            plugin.compatibility_status = Some(PluginCompatibilityStatus::IncompatibleMinecraftVersion);
+             println!("  Update found ({}) for {}, but it's incompatible with MC version {:?}",
+                plugin.latest_version.as_deref().unwrap_or("?"),
+                plugin.name,
+                server_info.minecraft_version.as_deref().unwrap_or("?")
+            );
+        } else {
+            plugin.compatibility_status = Some(PluginCompatibilityStatus::Compatible);
+            println!("  Compatible update found ({}) for {}",
+                plugin.latest_version.as_deref().unwrap_or("?"),
+                plugin.name
+            );
+        }
+
     } else {
+        // Plugin version matches or is newer than repo - treat as up-to-date
+        plugin.latest_version = Some(plugin.version.clone());
         plugin.has_update = false;
+        plugin.compatibility_status = Some(PluginCompatibilityStatus::Compatible); // Assume compatible if up-to-date
+    }
+
+    // If status wasn't set (e.g., error during check before this point), mark as Unknown
+    if plugin.compatibility_status.is_none() {
+         plugin.compatibility_status = Some(PluginCompatibilityStatus::Unknown);
     }
 }
 
-/// Determine if a repository plugin is likely a match for the installed plugin
+/// Convert server type to loader name
+fn server_type_to_loader_name(server_type: &ServerType) -> Option<&'static str> {
+    match server_type {
+        ServerType::Paper => Some("paper"),
+        ServerType::Spigot => Some("spigot"),
+        ServerType::Bukkit => Some("bukkit"),
+        ServerType::Forge => Some("forge"),
+        ServerType::Fabric => Some("fabric"),
+        ServerType::Velocity => Some("velocity"),
+        ServerType::BungeeCord => Some("bungeecord"),
+        ServerType::Waterfall => Some("waterfall"),
+        ServerType::Vanilla => None, // Vanilla doesn't support plugins
+        ServerType::Unknown => None,
+    }
+}
+
+/// Check if version platform is compatible with server platform
+fn is_platform_compatible(version_platform: &str, server_platform: &str) -> bool {
+    // Direct platform match
+    if version_platform.eq_ignore_ascii_case(server_platform) {
+        return true;
+    }
+
+    // Platform compatibility matrix
+    match server_platform {
+        "paper" => {
+            // Paper is compatible with Spigot and Bukkit plugins
+            version_platform == "spigot" ||
+            version_platform == "bukkit"
+        },
+        "spigot" => {
+            // Spigot is compatible with Bukkit plugins
+            version_platform == "bukkit"
+        },
+        "bungeecord" => {
+            // BungeeCord is compatible with Waterfall plugins and vice versa
+            version_platform == "waterfall"
+        },
+        "waterfall" => {
+            version_platform == "bungeecord"
+        },
+        _ => false // No other cross-compatibility
+    }
+}
+
+/// Determine if a repository plugin is likely a match for an installed plugin
+/// Uses multiple weighted factors and confidence scoring
 fn is_likely_match(installed: &Plugin, repo: &RepositoryPlugin) -> bool {
-    // Require multiple criteria to match to avoid false positives
-    let mut match_points = 0;
+    println!("Evaluating match: '{}' (installed) vs '{}' (repo)", installed.name, repo.name);
 
-    // Name similarity check
+    // Multi-factor weighted scoring system
+    let mut confidence_score = 0.0f32;
+    let mut factor_count = 0;
+    let mut applied_weights = 0.0f32;
+
+    // Track applied factors for debugging
+    let mut applied_factors = Vec::new();
+
+    // ====== NAME SIMILARITY (HIGHEST WEIGHT) ======
     let name_similarity = calculate_name_similarity(&installed.name, &repo.name);
+    let name_weight = 10.0f32;
+    applied_weights += name_weight;
+    factor_count += 1;
+    confidence_score += name_similarity * name_weight;
+    applied_factors.push(format!("Name similarity: {:.2} (weight: {:.1})", name_similarity, name_weight));
 
-    // Strong name match (over 0.9 similarity)
-    if name_similarity > 0.9 {
-        match_points += 2;
-    }
-    // Moderate name match
-    else if name_similarity > 0.7 {
-        match_points += 1;
+    // Exact name match is very strong signal
+    if name_similarity > 0.95f32 {
+        applied_factors.push("STRONG SIGNAL: Nearly exact name match".to_string());
     }
 
-    // Author check - if any author matches
+    // ====== DESCRIPTION SIMILARITY ======
+    if let (Some(installed_desc), Some(repo_desc)) = (&installed.description, &repo.description) {
+        if !installed_desc.is_empty() && !repo_desc.is_empty() {
+            let desc_similarity = calculate_text_similarity(installed_desc, repo_desc);
+            let desc_weight = 3.0f32;
+            applied_weights += desc_weight;
+            factor_count += 1;
+            confidence_score += desc_similarity * desc_weight;
+            applied_factors.push(format!("Description similarity: {:.2} (weight: {:.1})", desc_similarity, desc_weight));
+        }
+    }
+
+    // ====== MAIN CLASS MATCH (VERY STRONG SIGNAL) ======
+    if let Some(main_class) = &installed.main_class {
+        let main_class_lower = main_class.to_lowercase();
+        let repo_name_lower = repo.name.to_lowercase();
+
+        // Check if repository plugin name is contained in the main class
+        // This is a very strong signal that they are the same plugin
+        let main_class_signal = if main_class_lower.contains(&repo_name_lower) {
+            // Direct containment is strongest
+            let weight = 8.0f32;
+            applied_weights += weight;
+            factor_count += 1;
+            confidence_score += 1.0f32 * weight;
+            applied_factors.push(format!("Main class contains repo name (weight: {:.1})", weight));
+            true
+        } else if repo_name_lower.contains(&main_class_lower.split('.').last().unwrap_or("").to_lowercase()) {
+            // Final component of package matches
+            let weight = 6.0f32;
+            applied_weights += weight;
+            factor_count += 1;
+            confidence_score += 0.9f32 * weight;
+            applied_factors.push(format!("Repo name contains last part of main class (weight: {:.1})", weight));
+            true
+        } else {
+            // Check for partial matching (e.g., WordlEdit matches com.sk89q.worldedit)
+            let main_class_parts: Vec<&str> = main_class_lower.split('.').collect();
+            for part in main_class_parts {
+                if part.len() > 3 && repo_name_lower.contains(part) {
+                    let weight = 5.0f32;
+                    applied_weights += weight;
+                    factor_count += 1;
+                    confidence_score += 0.8f32 * weight;
+                    applied_factors.push(format!("Main class part '{}' found in repo name (weight: {:.1})", part, weight));
+                    return true;
+                }
+            }
+            false
+        };
+
+        if main_class_signal {
+            applied_factors.push("STRONG SIGNAL: Main class match".to_string());
+        }
+    }
+
+    // ====== AUTHOR MATCH ======
     if !installed.authors.is_empty() && !repo.authors.is_empty() {
+        let mut best_author_match = 0.0f32;
+        let mut matched_author = String::new();
+
         for installed_author in &installed.authors {
+            let installed_author_lower = installed_author.to_lowercase();
+
             for repo_author in &repo.authors {
-                if installed_author.to_lowercase() == repo_author.to_lowercase() {
-                    match_points += 2;
+                let repo_author_lower = repo_author.to_lowercase();
+
+                // Try different author name formats and variations
+                if installed_author_lower == repo_author_lower {
+                    best_author_match = 1.0f32;
+                    matched_author = repo_author.clone();
                     break;
                 }
+
+                // Handle partial name matches (e.g., "JohnDoe" vs "John Doe" or "jdoe")
+                let similarity = calculate_name_similarity(&installed_author_lower, &repo_author_lower);
+                if similarity > best_author_match {
+                    best_author_match = similarity;
+                    matched_author = repo_author.clone();
+                }
+            }
+
+            if best_author_match > 0.0f32 {
+                break;
+            }
+        }
+
+        if best_author_match > 0.0f32 {
+            let author_weight = if best_author_match >= 0.9f32 { 6.0f32 } else { 3.0f32 };
+            applied_weights += author_weight;
+            factor_count += 1;
+            confidence_score += best_author_match * author_weight;
+            applied_factors.push(format!("Author match: {} ({:.2} similarity, weight: {:.1})",
+                matched_author, best_author_match, author_weight));
+
+            if best_author_match >= 0.9f32 {
+                applied_factors.push("STRONG SIGNAL: Author exact match".to_string());
+            }
+        }
+    }
+
+    // ====== WEBSITE MATCH ======
+    if let Some(website) = &installed.website {
+        let website_lower = website.to_lowercase();
+        let repo_url_lower = repo.page_url.to_lowercase();
+
+        if website_lower.contains(&repo_url_lower) || repo_url_lower.contains(&website_lower) {
+            let weight = 4.0f32;
+            applied_weights += weight;
+            factor_count += 1;
+            confidence_score += 1.0f32 * weight;
+            applied_factors.push(format!("Website match (weight: {:.1})", weight));
+            applied_factors.push("STRONG SIGNAL: Website match".to_string());
+        } else {
+            // Try to extract domains for partial matching
+            let website_domain = extract_domain(&website_lower);
+            let repo_domain = extract_domain(&repo_url_lower);
+
+            if let (Some(w_domain), Some(r_domain)) = (website_domain, repo_domain) {
+                if w_domain == r_domain {
+                    let weight = 3.0f32;
+                    applied_weights += weight;
+                    factor_count += 1;
+                    confidence_score += 0.9f32 * weight;
+                    applied_factors.push(format!("Domain match: {} (weight: {:.1})", w_domain, weight));
+                }
             }
         }
     }
 
-    // Website match
-    if let Some(website) = &installed.website {
-        if website.contains(&repo.page_url) || repo.page_url.contains(website) {
-            match_points += 2;
+    // ====== DEPENDENCY CHECKS ======
+    // Check if plugins have similar dependencies
+    // This helps distinguish plugins with similar names but different functionality
+    if let Some(depend) = &installed.depend {
+        if !depend.is_empty() {
+            // Create a string of dependencies for matching
+            let depend_str = depend.join(",").to_lowercase();
+            let repo_name_lower = repo.name.to_lowercase();
+
+            // Watch for potential false matches where repo name matches a dependency
+            // This prevents matching a plugin to its dependency (like WorldEdit to FastAsyncWorldEdit)
+            let mut dependency_penalty = false;
+            for dep in depend {
+                if repo_name_lower.contains(&dep.to_lowercase()) {
+                    dependency_penalty = true;
+                    let weight = -5.0f32; // Strong negative signal
+                    applied_weights += weight.abs();
+                    confidence_score += weight; // Negative score
+                    applied_factors.push(format!("NEGATIVE: Repo name matches dependency: {} (weight: {:.1})", dep, weight));
+                    break;
+                }
+            }
+
+            // Check if description contains dependency references
+            if !dependency_penalty && !repo_name_lower.contains("api") && !repo_name_lower.contains("lib") {
+                if let Some(desc) = &repo.description {
+                    let desc_lower = desc.to_lowercase();
+
+                    // Check if any dependencies are mentioned in the description
+                    let mut found_dependencies = Vec::new();
+                    for dep in depend {
+                        let dep_lower = dep.to_lowercase();
+                        if desc_lower.contains(&dep_lower) {
+                            found_dependencies.push(dep.clone());
+                        }
+                    }
+
+                    if !found_dependencies.is_empty() {
+                        let weight = 3.0f32;
+                        let match_score = (found_dependencies.len() as f32 / depend.len() as f32).min(1.0);
+                        applied_weights += weight;
+                        factor_count += 1;
+                        confidence_score += match_score * weight;
+                        applied_factors.push(format!("Dependencies in description: {} (weight: {:.1})",
+                            found_dependencies.join(", "), weight));
+                    }
+                }
+            }
         }
     }
 
-    // Require at least 2 match points to consider it a likely match
-    // This helps avoid incorrect matches
-    match_points >= 2
+    // ====== FINAL CONFIDENCE CALCULATION ======
+    let normalized_confidence = if applied_weights > 0.0f32 {
+        confidence_score / applied_weights
+    } else {
+        0.0f32
+    };
+
+    // Calculate a weighted score that considers both total confidence and breadth of signals
+    let signal_breadth_factor = (factor_count as f32 / 5.0).min(1.0); // Normalize to max of 5 factors
+    let final_confidence = normalized_confidence * 0.7 + signal_breadth_factor * 0.3;
+
+    // Threshold for likely match
+    let is_match = final_confidence >= 0.6 && factor_count >= 2;
+
+    // Debug output
+    println!("Match analysis for '{}' vs '{}':", installed.name, repo.name);
+    for factor in &applied_factors {
+        println!("  {}", factor);
+    }
+    println!("  Factors: {}, Applied weights: {:.1}, Confidence score: {:.1}",
+        factor_count, applied_weights, confidence_score);
+    println!("  Normalized confidence: {:.2}, Signal breadth: {:.2}, Final confidence: {:.2}",
+        normalized_confidence, signal_breadth_factor, final_confidence);
+    println!("  MATCH RESULT: {}", if is_match { "LIKELY MATCH ✓" } else { "NOT A MATCH ✗" });
+
+    is_match
 }
 
-/// Calculate similarity between plugin names (simple implementation)
+/// Extract domain from a URL for website matching
+fn extract_domain(url: &str) -> Option<String> {
+    // Strip protocol
+    let without_protocol = if url.starts_with("http://") {
+        &url[7..]
+    } else if url.starts_with("https://") {
+        &url[8..]
+    } else {
+        url
+    };
+
+    // Find end of domain (first slash or end of string)
+    let domain_end = without_protocol.find('/').unwrap_or(without_protocol.len());
+    let domain = &without_protocol[0..domain_end];
+
+    // Remove www. prefix if present
+    let domain = if domain.starts_with("www.") {
+        &domain[4..]
+    } else {
+        domain
+    };
+
+    if domain.is_empty() || !domain.contains('.') {
+        None
+    } else {
+        Some(domain.to_string())
+    }
+}
+
+/// Calculate similarity between two text fields
+fn calculate_text_similarity(text1: &str, text2: &str) -> f32 {
+    let t1 = text1.to_lowercase();
+    let t2 = text2.to_lowercase();
+
+    // For short texts, use character-level similarity
+    if t1.len() < 10 || t2.len() < 10 {
+        return calculate_levenshtein_similarity(&t1, &t2);
+    }
+
+    // Otherwise use a bag-of-words approach
+    let words1: Vec<&str> = t1.split_whitespace().collect();
+    let words2: Vec<&str> = t2.split_whitespace().collect();
+
+    if words1.is_empty() || words2.is_empty() {
+        return 0.0;
+    }
+
+    // Count word occurrences
+    let mut word_counts1 = std::collections::HashMap::new();
+    let mut word_counts2 = std::collections::HashMap::new();
+
+    for word in &words1 {
+        *word_counts1.entry(*word).or_insert(0) += 1;
+    }
+
+    for word in &words2 {
+        *word_counts2.entry(*word).or_insert(0) += 1;
+    }
+
+    // Calculate intersection size
+    let mut intersection = 0;
+    let mut important_word_matches = 0;
+
+    for (word, count1) in &word_counts1 {
+        if word.len() <= 3 {
+            continue; // Skip short common words
+        }
+
+        if let Some(count2) = word_counts2.get(word) {
+            intersection += count1.min(count2);
+
+            // Consider longer words more important
+            if word.len() >= 5 {
+                important_word_matches += 1;
+            }
+        }
+    }
+
+    // Calculate Jaccard similarity
+    let union = words1.len() + words2.len() - intersection;
+    let jaccard = if union > 0 {
+        intersection as f32 / union as f32
+    } else {
+        0.0
+    };
+
+    // Boost score if important words match
+    let importance_bonus = (important_word_matches as f32 * 0.1).min(0.3);
+
+    (jaccard + importance_bonus).min(1.0)
+}
+
+/// Calculate similarity between plugin names using an improved algorithm
 fn calculate_name_similarity(name1: &str, name2: &str) -> f32 {
     let name1_lower = name1.to_lowercase();
     let name2_lower = name2.to_lowercase();
@@ -247,30 +836,184 @@ fn calculate_name_similarity(name1: &str, name2: &str) -> f32 {
         return 1.0;
     }
 
-    // Contains check
-    if name1_lower.contains(&name2_lower) || name2_lower.contains(&name1_lower) {
-        return 0.9;
+    // First, normalize the names by removing common irrelevant words
+    let name1_normalized = normalize_plugin_name(&name1_lower);
+    let name2_normalized = normalize_plugin_name(&name2_lower);
+
+    // Check normalized equality
+    if name1_normalized == name2_normalized {
+        return 0.95; // Almost perfect match after normalization
     }
 
-    // Simple word matching
-    let words1: Vec<&str> = name1_lower.split_whitespace().collect();
-    let words2: Vec<&str> = name2_lower.split_whitespace().collect();
+    // Contains check with improved weighting
+    if name1_normalized.contains(&name2_normalized) || name2_normalized.contains(&name1_normalized) {
+        // Calculate containment score based on length ratios
+        let length_ratio = name1_normalized.len() as f32 / name2_normalized.len().max(1) as f32;
+        let normalized_ratio = if length_ratio > 1.0 { 1.0 / length_ratio } else { length_ratio };
 
-    let mut matched_words = 0;
-    let total_words = words1.len().max(words2.len());
+        // Higher score for closer length ratios
+        return 0.7 + (normalized_ratio * 0.2);
+    }
+
+    // Split by common separators and compute word-level similarity
+    let words1: Vec<&str> = name1_normalized
+        .split(|c| c == ' ' || c == '-' || c == '_')
+        .filter(|w| !w.is_empty() && w.len() > 2)
+        .collect();
+
+    let words2: Vec<&str> = name2_normalized
+        .split(|c| c == ' ' || c == '-' || c == '_')
+        .filter(|w| !w.is_empty() && w.len() > 2)
+        .collect();
+
+    if words1.is_empty() || words2.is_empty() {
+        // Fallback to character-level similarity for short names or single words
+        return calculate_levenshtein_similarity(&name1_normalized, &name2_normalized);
+    }
+
+    // Word-level similarity calculation with TF-IDF style weighting
+    let mut similarity_score = 0.0f32;
+    let mut total_weight = 0.0f32;
 
     for word1 in &words1 {
+        // Words with higher length get more weight (similar to IDF)
+        let word_weight = (word1.len() as f32).min(5.0) / 5.0;
+        total_weight += word_weight;
+
+        let mut best_word_match: f32 = 0.0f32;
+
         for word2 in &words2 {
-            if word1 == word2 && word1.len() > 2 {  // Ignore short words
-                matched_words += 1;
-                break;
+            // For each word, find the best matching word in the other name
+            let word_similarity = if word1 == word2 {
+                1.0f32 // Exact word match
+            } else {
+                calculate_levenshtein_similarity(word1, word2)
+            };
+
+            best_word_match = best_word_match.max(word_similarity);
+        }
+
+        similarity_score += best_word_match * word_weight;
+    }
+
+    // Normalize by total weight
+    if total_weight > 0.0 {
+        similarity_score /= total_weight;
+    }
+
+    // Extra boost for plugins with first word matching
+    // This helps for plugins like "WorldEdit" vs "FastWorldEdit"
+    if !words1.is_empty() && !words2.is_empty() && words1[0] == words2[0] {
+        similarity_score = (similarity_score + 0.2).min(0.9);
+    }
+
+    similarity_score
+}
+
+/// Normalize a plugin name by removing common prefixes, suffixes, and irrelevant words
+fn normalize_plugin_name(name: &str) -> String {
+    let mut normalized = name.to_lowercase();
+
+    // Remove common version indicators
+    let version_patterns = [
+        " v1", " v2", " v3", " v4", " v5",
+        " 1.0", " 2.0", " 3.0", " 4.0", " 5.0",
+        " (1.", " (2.", " (3.",
+    ];
+
+    for pattern in &version_patterns {
+        if let Some(pos) = normalized.find(pattern) {
+            normalized = normalized[0..pos].to_string();
+        }
+    }
+
+    // Remove common irrelevant words
+    let irrelevant_words = [
+        "plugin", "mod", "minecraft", "bukkit", "spigot", "paper", "forge", "fabric",
+        "the", "for", "and", "lite", "full", "version", "free", "premium", "pro"
+    ];
+
+    for word in &irrelevant_words {
+        let pattern = format!(" {} ", word);
+        normalized = normalized.replace(&pattern, " ");
+
+        // Also check at the beginning and end
+        let start_pattern = format!("{} ", word);
+        let end_pattern = format!(" {}", word);
+
+        normalized = normalized.replace(&start_pattern, "");
+        normalized = normalized.replace(&end_pattern, "");
+    }
+
+    // Trim and remove duplicate spaces
+    normalized = normalized.trim().to_string();
+    while normalized.contains("  ") {
+        normalized = normalized.replace("  ", " ");
+    }
+
+    normalized
+}
+
+/// Calculate Levenshtein similarity between two strings
+fn calculate_levenshtein_similarity(s1: &str, s2: &str) -> f32 {
+    if s1.is_empty() || s2.is_empty() {
+        return if s1.is_empty() && s2.is_empty() { 1.0 } else { 0.0 };
+    }
+
+    // Optimization for strings with large length difference
+    let len_diff = (s1.len() as isize - s2.len() as isize).abs() as usize;
+    if len_diff > s1.len() / 2 || len_diff > s2.len() / 2 {
+        return 0.2; // Low similarity for strings with very different lengths
+    }
+
+    // Early exact matching check
+    if s1 == s2 {
+        return 1.0;
+    }
+
+    // Convert strings to character vectors for easier access
+    let s1_chars: Vec<char> = s1.chars().collect();
+    let s2_chars: Vec<char> = s2.chars().collect();
+    let len1 = s1_chars.len();
+    let len2 = s2_chars.len();
+
+    // Create matrix for dynamic programming
+    let mut matrix = vec![vec![0; len2 + 1]; len1 + 1];
+
+    // Initialize first row and column
+    for i in 0..=len1 {
+        matrix[i][0] = i;
+    }
+    for j in 0..=len2 {
+        matrix[0][j] = j;
+    }
+
+    // Fill the matrix
+    for i in 1..=len1 {
+        for j in 1..=len2 {
+            let cost = if s1_chars[i-1] == s2_chars[j-1] { 0 } else { 1 };
+
+            matrix[i][j] = [
+                matrix[i-1][j] + 1,            // deletion
+                matrix[i][j-1] + 1,            // insertion
+                matrix[i-1][j-1] + cost,       // substitution
+            ].iter().min().unwrap().clone();
+
+            // Transposition (swap two adjacent characters)
+            if i > 1 && j > 1 && s1_chars[i-1] == s2_chars[j-2] && s1_chars[i-2] == s2_chars[j-1] {
+                matrix[i][j] = matrix[i-2][j-2] + 1;
             }
         }
     }
 
-    if total_words > 0 {
-        matched_words as f32 / total_words as f32
+    // Calculate normalized similarity
+    let distance = matrix[len1][len2] as f32;
+    let max_length = len1.max(len2) as f32;
+
+    // Normalize to a similarity score (1.0 = identical, 0.0 = completely different)
+    if max_length > 0.0 {
+        (max_length - distance) / max_length
     } else {
-        0.0
+        1.0
     }
 }
\ No newline at end of file
diff --git a/src-tauri/src/services/update_manager/version_utils.rs b/src-tauri/src/services/update_manager/version_utils.rs
index 4137a34..336df67 100644
--- a/src-tauri/src/services/update_manager/version_utils.rs
+++ b/src-tauri/src/services/update_manager/version_utils.rs
@@ -3,36 +3,283 @@ use regex::Regex;
 
 /// Normalize a version string to be semver compatible
 pub fn normalize_version(version_str: &str) -> String {
-    // If already starts with a digit, assume semantic version format
-    if version_str.chars().next().map_or(false, |c| c.is_ascii_digit()) {
-        // Clean up any common prefixes like 'v'
-        let cleaned = version_str.trim_start_matches(|c| c == 'v' || c == 'V');
-        return cleaned.to_string();
+    // Handle empty strings or "Latest"
+    if version_str.is_empty() || version_str.eq_ignore_ascii_case("latest") {
+        return "0.0.0".to_string(); // Default version if none provided
     }
 
-    // Return as-is for now
-    version_str.to_string()
+    // Remove 'v' prefix if present
+    let cleaned = version_str.trim_start_matches(|c| c == 'v' || c == 'V');
+
+    // Remove double 'v' prefixes (like "vv1.0.0")
+    let cleaned = if cleaned.starts_with("v") || cleaned.starts_with("V") {
+        cleaned.trim_start_matches(|c| c == 'v' || c == 'V')
+    } else {
+        cleaned
+    };
+
+    cleaned.to_string()
+}
+
+/// Sanitize version string for comparison by removing platform suffixes
+fn sanitize_version_for_comparison(version_str: &str) -> String {
+    // First normalize the version
+    let normalized = normalize_version(version_str);
+
+    // Remove common platform-specific suffixes
+    let platform_suffixes = [
+        "-paper", "-spigot", "-bukkit", "-forge", "-fabric", "-neoforge",
+        "-sponge", "-velocity", "-waterfall", "-bungeecord", "-quilt"
+    ];
+
+    let mut result = normalized.to_string();
+
+    // Case-insensitive suffix removal
+    for suffix in platform_suffixes.iter() {
+        let suffix_lower = suffix.to_lowercase();
+        let version_lower = result.to_lowercase();
+
+        if version_lower.contains(&suffix_lower) {
+            // Find the position of the suffix (case-insensitive)
+            if let Some(pos) = version_lower.find(&suffix_lower) {
+                // Remove the suffix (with original casing)
+                result = result[0..pos].to_string();
+            }
+        }
+    }
+
+    // Remove any build metadata (anything after +)
+    if let Some(plus_pos) = result.find('+') {
+        result = result[0..plus_pos].to_string();
+    }
+
+    // Handle snapshot versions with build numbers
+    if result.contains("-SNAPSHOT") || result.contains("-snapshot") {
+        // Extract just the version part before any build info
+        if let Some(snapshot_pos) = result.to_lowercase().find("-snapshot") {
+            result = result[0..snapshot_pos].to_string();
+        }
+    }
+
+    // Normalize dev build formats that use dash-separated numbers
+    let build_regex = Regex::new(r"-build\d+").unwrap();
+    result = build_regex.replace_all(&result, "").to_string();
+
+    // Handle other common non-numeric suffixes
+    let common_suffixes = ["-RELEASE", "-dev", "-final", "-stable"];
+    for suffix in common_suffixes.iter() {
+        let suffix_lower = suffix.to_lowercase();
+        let version_lower = result.to_lowercase();
+
+        if version_lower.ends_with(&suffix_lower) {
+            let suffix_len = suffix_lower.len();
+            result = result[0..result.len() - suffix_len].to_string();
+        }
+    }
+
+    // If we've removed everything, return the original normalized version
+    if result.is_empty() {
+        return normalized;
+    }
+
+    // Make sure it ends with at least one digit for semver parsing
+    if !result.chars().last().map_or(false, |c| c.is_ascii_digit()) {
+        if let Some(last_digit_pos) = result.rfind(|c: char| c.is_ascii_digit()) {
+            result = result[0..=last_digit_pos].to_string();
+        }
+    }
+
+    // If we've removed version numbers entirely, return the original
+    if !result.chars().any(|c| c.is_ascii_digit()) {
+        return normalized;
+    }
+
+    result
+}
+
+/// Extracts platform suffix from a version string
+pub fn extract_platform_suffix(version_str: &str) -> Option<String> {
+    // Platform suffixes to check for
+    let platform_suffixes = [
+        "-paper", "-spigot", "-bukkit", "-forge", "-fabric", "-neoforge",
+        "-sponge", "-velocity", "-waterfall", "-bungeecord", "-quilt"
+    ];
+
+    let version_lower = version_str.to_lowercase();
+
+    for suffix in platform_suffixes.iter() {
+        let suffix_lower = suffix.to_lowercase();
+        if version_lower.contains(&suffix_lower) {
+            // Return the actual platform with original case
+            return Some(suffix_lower[1..].to_string()); // Remove the leading '-'
+        }
+    }
+
+    None
+}
+
+/// Determine if a version is a pre-release (snapshot, beta, etc.)
+fn is_prerelease_version(version_str: &str) -> bool {
+    let version_lower = version_str.to_lowercase();
+
+    // Check for common pre-release indicators
+    version_lower.contains("-snapshot") ||
+    version_lower.contains("-alpha") ||
+    version_lower.contains("-beta") ||
+    version_lower.contains("-pre") ||
+    version_lower.contains("-rc") ||
+    version_lower.contains("dev") ||
+    version_lower.contains("test") ||
+    version_lower.contains("nightly")
 }
 
 /// Compare two plugin versions to determine if an update is available
+/// Returns true if repo_str represents a newer version than installed_str
 pub fn compare_plugin_versions(installed_str: &str, repo_str: &str) -> bool {
-    // Normalize version strings
-    let installed_version = normalize_version(installed_str);
-    let repo_version = normalize_version(repo_str);
+    // Special case: identical strings are never upgrades
+    if installed_str == repo_str {
+        return false;
+    }
+
+    // Extract platform suffixes
+    let installed_platform = extract_platform_suffix(installed_str);
+    let repo_platform = extract_platform_suffix(repo_str);
+
+    // If platforms differ and both are specified, it's not considered an upgrade
+    // (we don't want to suggest forge versions for paper plugins)
+    if let (Some(installed_p), Some(repo_p)) = (&installed_platform, &repo_platform) {
+        if installed_p != repo_p {
+            println!("Platforms differ: {} vs {}, not an upgrade", installed_p, repo_p);
+            return false;
+        }
+    }
+
+    // Check for downgrades from release to prerelease
+    let installed_is_prerelease = is_prerelease_version(installed_str);
+    let repo_is_prerelease = is_prerelease_version(repo_str);
+
+    // Don't consider a pre-release version an upgrade from a stable version
+    if !installed_is_prerelease && repo_is_prerelease {
+        println!("Not upgrading from release {} to pre-release {}", installed_str, repo_str);
+        return false;
+    }
+
+    // Sanitize versions for comparison by removing platform-specific suffixes
+    let sanitized_installed = sanitize_version_for_comparison(installed_str);
+    let sanitized_repo = sanitize_version_for_comparison(repo_str);
+
+    // Log for debugging
+    println!("Comparing versions: '{}'({}') vs '{}'('{}')",
+             installed_str, sanitized_installed, repo_str, sanitized_repo);
 
     // Try to parse as semver
-    match (Version::parse(&installed_version), Version::parse(&repo_version)) {
+    match (Version::parse(&sanitized_installed), Version::parse(&sanitized_repo)) {
         (Ok(installed), Ok(repo)) => {
-            // Simple semver comparison
+            // Properly formatted semver comparison
+            println!("  Using semver comparison: {} vs {}", installed, repo);
             repo > installed
         },
         _ => {
-            // Fallback to simple string comparison for non-semver versions
-            repo_version != installed_version
+            // Fallback to more sophisticated string comparison for non-semver versions
+            if sanitized_installed == sanitized_repo {
+                // Same base version, check if repo has a higher build number or qualifier
+                compare_version_qualifiers(installed_str, repo_str)
+            } else {
+                // Try numeric component-by-component comparison
+                compare_version_components(&sanitized_installed, &sanitized_repo)
+            }
         }
     }
 }
 
+/// Compare version qualifiers and build numbers when base versions are the same
+fn compare_version_qualifiers(installed_str: &str, repo_str: &str) -> bool {
+    // Try to extract build numbers
+    let installed_build = extract_build_number(installed_str);
+    let repo_build = extract_build_number(repo_str);
+
+    if let (Some(i_build), Some(r_build)) = (installed_build, repo_build) {
+        return r_build > i_build;
+    }
+
+    // If qualifiers differ, use a rank-based system
+    let installed_rank = get_qualifier_rank(installed_str);
+    let repo_rank = get_qualifier_rank(repo_str);
+
+    if installed_rank != repo_rank {
+        return repo_rank > installed_rank;
+    }
+
+    // Default case - not considered an upgrade
+    false
+}
+
+/// Assign rank values to different version qualifiers
+fn get_qualifier_rank(version_str: &str) -> i32 {
+    let lower_str = version_str.to_lowercase();
+
+    if lower_str.contains("alpha") { return 10; }
+    if lower_str.contains("beta") { return 20; }
+    if lower_str.contains("rc") { return 30; }
+    if lower_str.contains("pre") { return 40; }
+    if lower_str.contains("snapshot") { return 50; }
+    if lower_str.contains("nightly") { return 60; }
+    if lower_str.contains("dev") { return 70; }
+    if lower_str.contains("release") { return 100; }
+
+    // Default for stable releases
+    90
+}
+
+/// Extract build number from a version string
+fn extract_build_number(version_str: &str) -> Option<i32> {
+    // Try to find patterns like "build123" or "-b123" or ".123"
+    let build_patterns = [
+        Regex::new(r"build(\d+)").ok()?,
+        Regex::new(r"-b(\d+)").ok()?,
+        Regex::new(r"\.(\d+)$").ok()?,
+        Regex::new(r"-(\d+)$").ok()?,
+    ];
+
+    for pattern in &build_patterns {
+        if let Some(captures) = pattern.captures(version_str) {
+            if let Some(build_match) = captures.get(1) {
+                if let Ok(build) = build_match.as_str().parse::<i32>() {
+                    return Some(build);
+                }
+            }
+        }
+    }
+
+    None
+}
+
+/// Compare version strings component by component
+fn compare_version_components(version1: &str, version2: &str) -> bool {
+    // Split versions into numeric and non-numeric parts
+    let v1_parts: Vec<&str> = version1.split(|c: char| !c.is_ascii_digit()).filter(|s| !s.is_empty()).collect();
+    let v2_parts: Vec<&str> = version2.split(|c: char| !c.is_ascii_digit()).filter(|s| !s.is_empty()).collect();
+
+    // Compare corresponding numeric parts
+    let max_parts = v1_parts.len().max(v2_parts.len());
+
+    for i in 0..max_parts {
+        let n1 = v1_parts.get(i).and_then(|s| s.parse::<i32>().ok()).unwrap_or(0);
+        let n2 = v2_parts.get(i).and_then(|s| s.parse::<i32>().ok()).unwrap_or(0);
+
+        if n2 > n1 {
+            return true;  // Version 2 is higher
+        }
+        if n1 > n2 {
+            return false; // Version 1 is higher
+        }
+    }
+
+    // If all numeric parts are equal, compare by string length
+    // (Consider more segments to be a higher version, like 1.2.3 > 1.2)
+    v2_parts.len() > v1_parts.len()
+}
+
 /// Extract version pattern from a string
 pub fn extract_version_pattern(input: &str) -> Option<String> {
     // Look for version pattern like 1.19.2 in string
@@ -46,15 +293,34 @@ pub fn extract_version_pattern(input: &str) -> Option<String> {
 }
 
 /// Check if a plugin version is compatible with a specific Minecraft version
-pub fn is_version_compatible(plugin_version: &str, minecraft_version: &str) -> bool {
-    // Try to parse the Minecraft version
-    if let Ok(mc_version) = Version::parse(minecraft_version) {
-        // Try to parse as a version requirement
-        if let Ok(req) = VersionReq::parse(plugin_version) {
-            return req.matches(&mc_version);
+pub fn is_version_compatible(plugin_version: &str, minecraft_versions: &Vec<String>) -> bool {
+    // If no versions specified, assume compatible
+    if minecraft_versions.is_empty() {
+        return true;
+    }
+
+    // Check if the Minecraft version is in the list of supported versions
+    for supported_version in minecraft_versions {
+        if plugin_version == supported_version {
+            return true;
+        }
+
+        // Try to parse the Minecraft version
+        if let Ok(mc_version) = semver::Version::parse(plugin_version) {
+            // Try to parse as a version requirement
+            if let Ok(req) = semver::VersionReq::parse(supported_version) {
+                if req.matches(&mc_version) {
+                    return true;
+                }
+            }
+        }
+
+        // If version formats are incompatible, make best guess
+        if plugin_version.contains(supported_version) || supported_version.contains(plugin_version) {
+            return true;
         }
     }
 
-    // If version formats are incompatible, make best guess
-    plugin_version.contains(minecraft_version)
+    // No compatibility match found
+    false
 }
\ No newline at end of file
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 9dee09c..7f3620d 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -40,7 +40,7 @@
   },
   "plugins": {
     "shell": {
-      "open": true
+      "open": "^((mailto:\\w+)|(tel:\\w+)|(https?://\\w+)|(file://.+)).+"
     },
     "dialog": null,
     "fs": null
diff --git a/src/App.tsx b/src/App.tsx
index 30f7f09..832809b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
 import './App.css';
 
 // Import context providers
@@ -38,6 +38,15 @@ import { useServerContext } from './context/ServerContext/useServerContext';
 import { usePluginContext } from './context/PluginContext/usePluginContext';
 import { usePluginActions } from './hooks/usePluginActions';
 
+// Define interfaces for component props
+interface PluginContextWrapperProps {
+  appVersion: string;
+}
+
+interface AppContentProps {
+  appVersion: string;
+}
+
 /**
  * The main application component that serves as the entry point.
  * This component is responsible for setting up the context providers
@@ -45,10 +54,29 @@ import { usePluginActions } from './hooks/usePluginActions';
  */
 function App() {
   console.log("App Component Initialized");
+  const [appVersion, setAppVersion] = useState('1.0.0');
+
+  useEffect(() => {
+    // Get the app version from the backend
+    const getAppVersion = async () => {
+      try {
+        // Use Tauri's invoke to call our Rust command
+        const { invoke } = await import('@tauri-apps/api/core');
+        const appInfo = await invoke('get_app_version');
+        setAppVersion((appInfo as { version: string }).version);
+      } catch (error) {
+        console.error('Failed to get app version:', error);
+        // display unknown version
+        setAppVersion('unknown');
+      }
+    };
+
+    getAppVersion();
+  }, []);
 
   return (
     <ServerProvider>
-      <PluginContextWrapper />
+      <PluginContextWrapper appVersion={appVersion} />
     </ServerProvider>
   );
 }
@@ -56,7 +84,7 @@ function App() {
 /**
  * Wrapper to ensure PluginProvider has access to ServerContext
  */
-function PluginContextWrapper() {
+function PluginContextWrapper({ appVersion }: PluginContextWrapperProps) {
   const { serverPath, serverInfo } = useServerContext();
 
   useEffect(() => {
@@ -66,7 +94,7 @@ function PluginContextWrapper() {
   return (
     <PluginProvider>
       <UIProvider>
-        <AppContent />
+        <AppContent appVersion={appVersion} />
       </UIProvider>
     </PluginProvider>
   );
@@ -76,7 +104,7 @@ function PluginContextWrapper() {
  * The main application content that uses context hooks.
  * This is separate from App to ensure the contexts are available.
  */
-function AppContent() {
+function AppContent({ appVersion }: AppContentProps) {
   const {
     serverInfo,
     serverPath,
@@ -201,7 +229,7 @@ function AppContent() {
         )}
       </MainContent>
 
-      <Footer />
+      <Footer appVersion={appVersion} />
     </div>
   );
 }
diff --git a/src/components/plugins/PluginList/PluginList.tsx b/src/components/plugins/PluginList/PluginList.tsx
index c3f1917..ad35e22 100644
--- a/src/components/plugins/PluginList/PluginList.tsx
+++ b/src/components/plugins/PluginList/PluginList.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useMemo } from 'react';
 import { usePluginActions } from '../../../hooks/usePluginActions';
 import { usePluginContext } from '../../../context/PluginContext/usePluginContext';
 import { Plugin } from '../../../types/plugin.types';
@@ -12,33 +12,149 @@ export const PluginList: React.FC = () => {
   const [searchTerm, setSearchTerm] = useState<string>('');
   const [sortBy, setSortBy] = useState<'name' | 'version' | 'update'>('name');
   const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');
+  const [filterUpdates, setFilterUpdates] = useState<boolean>(false);
 
-  // Filter plugins based on search term
-  const filteredPlugins = plugins.filter(plugin =>
-    plugin.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
-    plugin.version.toLowerCase().includes(searchTerm.toLowerCase()) ||
-    (plugin.description && plugin.description.toLowerCase().includes(searchTerm.toLowerCase()))
-  );
-
-  // Sort plugins based on sort criteria
-  const sortedPlugins = [...filteredPlugins].sort((a, b) => {
-    let comparison = 0;
-
-    switch (sortBy) {
-      case 'name':
-        comparison = a.name.localeCompare(b.name);
-        break;
-      case 'version':
-        comparison = a.version.localeCompare(b.version);
-        break;
-      case 'update':
-        // Sort by update status (plugins with updates first)
-        comparison = (b.has_update ? 1 : 0) - (a.has_update ? 1 : 0);
-        break;
+  // Advanced search with fuzzy matching and relevance scoring
+  const filteredPlugins = useMemo(() => {
+    if (!searchTerm.trim() && !filterUpdates) {
+      return plugins;
     }
 
-    return sortOrder === 'asc' ? comparison : -comparison;
-  });
+    // Filter by updates if that filter is active
+    let results = filterUpdates ? plugins.filter(plugin => plugin.has_update) : plugins;
+
+    if (!searchTerm.trim()) {
+      return results;
+    }
+
+    const searchLower = searchTerm.toLowerCase().trim();
+    const searchTerms = searchLower.split(/\s+/);
+
+    // If using multiple search terms, match plugins that contain all terms
+    if (searchTerms.length > 1) {
+      return results.filter(plugin => {
+        // Create a searchable text combining all relevant plugin fields
+        const searchableText = [
+          plugin.name,
+          plugin.version,
+          plugin.description || '',
+          plugin.authors?.join(' ') || '',
+          plugin.website || '',
+          plugin.main_class || '',
+        ].join(' ').toLowerCase();
+
+        // Plugin must match all search terms to be included
+        return searchTerms.every(term => searchableText.includes(term));
+      });
+    }
+
+    // For single term search, score each plugin for relevance
+    const scoredPlugins = results.map(plugin => {
+      let score = 0;
+
+      // Exact name match is highest priority
+      if (plugin.name.toLowerCase() === searchLower) {
+        score += 100;
+      }
+      // Name starts with search term
+      else if (plugin.name.toLowerCase().startsWith(searchLower)) {
+        score += 80;
+      }
+      // Name contains search term
+      else if (plugin.name.toLowerCase().includes(searchLower)) {
+        score += 60;
+      }
+
+      // Check if search term is an acronym of the plugin name
+      // E.g., "WE" for "WorldEdit"
+      if (searchLower.length >= 2 && isAcronymMatch(searchLower, plugin.name)) {
+        score += 70;
+      }
+
+      // Secondary matches in other fields
+      if (plugin.description?.toLowerCase().includes(searchLower)) {
+        score += 40;
+      }
+
+      if (plugin.authors?.some(author => author.toLowerCase().includes(searchLower))) {
+        score += 50;
+      }
+
+      if (plugin.main_class?.toLowerCase().includes(searchLower)) {
+        score += 30;
+      }
+
+      if (plugin.version.toLowerCase().includes(searchLower)) {
+        score += 20;
+      }
+
+      if (plugin.website?.toLowerCase().includes(searchLower)) {
+        score += 20;
+      }
+
+      // Tags or categories (if available in your data model)
+      if (plugin.repository_source?.toString().toLowerCase().includes(searchLower)) {
+        score += 30;
+      }
+
+      return { plugin, score };
+    });
+
+    // Filter plugins that have at least some relevance and sort by score
+    const relevantPlugins = scoredPlugins
+      .filter(item => item.score > 0)
+      .sort((a, b) => b.score - a.score)
+      .map(item => item.plugin);
+
+    return relevantPlugins;
+  }, [plugins, searchTerm, filterUpdates]);
+
+  // Memoize sorted plugins for performance
+  const sortedPlugins = useMemo(() => {
+    return [...filteredPlugins].sort((a, b) => {
+      let comparison = 0;
+
+      switch (sortBy) {
+        case 'name':
+          comparison = a.name.localeCompare(b.name);
+          break;
+        case 'version':
+          comparison = a.version.localeCompare(b.version);
+          break;
+        case 'update':
+          // Sort by update status (plugins with updates first)
+          comparison = (b.has_update ? 1 : 0) - (a.has_update ? 1 : 0);
+          break;
+      }
+
+      return sortOrder === 'asc' ? comparison : -comparison;
+    });
+  }, [filteredPlugins, sortBy, sortOrder]);
+
+  // Function to check if search is an acronym of plugin name
+  const isAcronymMatch = (acronym: string, fullName: string): boolean => {
+    // Extract capital letters or the first letter of each word
+    const words = fullName.split(/[\s-_]+/);
+
+    // Method 1: First letter of each word
+    const firstLetters = words.map(word => word.charAt(0).toLowerCase()).join('');
+    if (firstLetters === acronym) {
+      return true;
+    }
+
+    // Method 2: Capital letters in a camel case name
+    const capitals = fullName.replace(/[^A-Z]/g, '').toLowerCase();
+    if (capitals === acronym) {
+      return true;
+    }
+
+    // For shorter search terms, check if it's a substring of the first letters
+    if (acronym.length >= 2 && acronym.length <= 3 && firstLetters.includes(acronym)) {
+      return true;
+    }
+
+    return false;
+  };
 
   const handleSort = (criteria: 'name' | 'version' | 'update') => {
     if (criteria === sortBy) {
@@ -51,64 +167,74 @@ export const PluginList: React.FC = () => {
     }
   };
 
-  const getSortIndicator = (criteria: 'name' | 'version' | 'update'): string => {
-    if (sortBy !== criteria) return '';
-    return sortOrder === 'asc' ? ' ↑' : ' ↓';
+  const toggleUpdateFilter = () => {
+    setFilterUpdates(!filterUpdates);
   };
 
+  const clearFilters = () => {
+    setSearchTerm('');
+    setFilterUpdates(false);
+  };
+
+  // Get stats for UI feedback
+  const updateCount = plugins.filter(p => p.has_update).length;
+
   return (
     <div className="plugin-list-container">
-      <div className="search-container">
-        <input
-          type="text"
-          placeholder="Search plugins..."
-          value={searchTerm}
-          onChange={(e) => setSearchTerm(e.target.value)}
-          className="search-input"
-        />
-        {searchTerm && (
-          <button
-            className="clear-search"
-            onClick={() => setSearchTerm('')}
-            aria-label="Clear search"
-          >
-            ×
-          </button>
-        )}
-      </div>
+      <div className="plugin-list-header">
+        <div className="search-and-filter">
+          <input
+            type="text"
+            className="search-input"
+            placeholder="Search plugins by name, author, description..."
+            value={searchTerm}
+            onChange={(e) => setSearchTerm(e.target.value)}
+          />
+          <div className="filter-options">
+            <Button
+              variant={filterUpdates ? "primary" : "secondary"}
+              size="small"
+              onClick={toggleUpdateFilter}
+            >
+              {filterUpdates ? "Showing Updates" : "Show Updates Only"}
+              {updateCount > 0 && `(${updateCount})`}
+            </Button>
+            {(searchTerm || filterUpdates) && (
+              <Button
+                variant="secondary"
+                size="small"
+                onClick={clearFilters}
+              >
+                Clear Filters
+              </Button>
+            )}
+          </div>
+        </div>
 
-      <div className="plugin-list-controls">
         <div className="sort-controls">
           <span className="sort-label">Sort by:</span>
           <Button
-            variant="text"
+            variant={sortBy === 'name' ? 'primary' : 'secondary'}
             size="small"
-            className={`sort-button ${sortBy === 'name' ? 'active' : ''}`}
             onClick={() => handleSort('name')}
           >
-            Name{getSortIndicator('name')}
+            Name {sortBy === 'name' && (sortOrder === 'asc' ? '↑' : '↓')}
           </Button>
           <Button
-            variant="text"
+            variant={sortBy === 'version' ? 'primary' : 'secondary'}
             size="small"
-            className={`sort-button ${sortBy === 'version' ? 'active' : ''}`}
             onClick={() => handleSort('version')}
           >
-            Version{getSortIndicator('version')}
+            Version {sortBy === 'version' && (sortOrder === 'asc' ? '↑' : '↓')}
           </Button>
           <Button
-            variant="text"
+            variant={sortBy === 'update' ? 'primary' : 'secondary'}
             size="small"
-            className={`sort-button ${sortBy === 'update' ? 'active' : ''}`}
             onClick={() => handleSort('update')}
           >
-            Updates{getSortIndicator('update')}
+            Update Status {sortBy === 'update' && (sortOrder === 'asc' ? '↓' : '↑')}
           </Button>
         </div>
-
-        <div className="filter-info">
-          Showing {filteredPlugins.length} of {plugins.length} plugins
-        </div>
       </div>
 
       <div className="plugin-list">
@@ -122,8 +248,8 @@ export const PluginList: React.FC = () => {
           ))
         ) : (
           <div className="no-results">
-            <p>No plugins match your search.</p>
-            <Button variant="secondary" onClick={() => setSearchTerm('')}>Clear search</Button>
+            <p>No plugins match your search criteria.</p>
+            <Button variant="secondary" onClick={clearFilters}>Clear All Filters</Button>
           </div>
         )}
       </div>
diff --git a/src/components/server/ServerInfo/ServerInfo.tsx b/src/components/server/ServerInfo/ServerInfo.tsx
index fc4c663..d581b5d 100644
--- a/src/components/server/ServerInfo/ServerInfo.tsx
+++ b/src/components/server/ServerInfo/ServerInfo.tsx
@@ -2,7 +2,7 @@ import React from 'react';
 import { ServerInfo as ServerInfoType } from '../../../types/server.types';
 import Badge from '../../common/Badge/Badge';
 import './ServerInfo.css';
-// Import only shell open as it's the primary method
+// Use the shell.open for opening directories
 import { open } from '@tauri-apps/plugin-shell';
 import { useServerContext } from '../../../context/ServerContext/useServerContext';
 
@@ -58,13 +58,30 @@ export const ServerInfo: React.FC<ServerInfoProps> = ({ serverInfo }) => {
   // Function to open the server directory in file explorer
   const handleOpenDirectory = async () => {
     try {
-      console.log('Attempting to open directory using shell.open:', serverPath);
-      // Use shell.open directly - it's generally more robust, especially for UNC
-      await open(serverPath);
-      console.log('Successfully opened directory via shell.open');
+      console.log('Attempting to open directory:', serverPath);
+
+      // Format the path as a proper file:// URL
+      let dirPath = serverPath;
+
+      // Convert to the proper URL format based on path type
+      if (dirPath.startsWith('\\\\')) {
+        // UNC path (network location)
+        // Format: file:////server/share/path (4 slashes)
+        dirPath = `file:////` + dirPath.replace(/\\/g, '/').substring(2);
+      } else {
+        // Local path
+        // Format: file:///C:/path/to/dir (3 slashes)
+        dirPath = `file:///${dirPath.replace(/\\/g, '/')}`;
+      }
+
+      console.log('Opening directory with path:', dirPath);
+
+      // Open the directory in system's file explorer
+      await open(dirPath);
+
+      console.log('Successfully opened directory');
     } catch (error) {
       console.error('Failed to open directory:', error);
-      // Optionally add user feedback here (e.g., toast notification)
     }
   };
 
diff --git a/src/context/PluginContext/PluginContext.tsx b/src/context/PluginContext/PluginContext.tsx
index 485508a..e451090 100644
--- a/src/context/PluginContext/PluginContext.tsx
+++ b/src/context/PluginContext/PluginContext.tsx
@@ -261,6 +261,7 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({
       const updatedPlugins = await invoke<Plugin[]>("check_plugin_updates", {
         plugins: pluginsToSend,
         repositories: repositoriesToCheck,
+        serverPath: currentServerPath
       });
 
       console.log("Bulk update check completed successfully, updating state.");