Skip to content

Commit 6e74633

Browse files
committed
Fixed get_wazuh_log_collector_stats mcp tool
1 parent e160888 commit 6e74633

2 files changed

Lines changed: 67 additions & 25 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repository = "https://github.com/gbrigandi/mcp-server-wazuh"
99
readme = "README.md"
1010

1111
[dependencies]
12-
wazuh-client = "0.1.5"
12+
wazuh-client = "0.1.6"
1313
rmcp = { version = "0.1.5", features = ["server", "transport-io"] }
1414
tokio = { version = "1", features = ["full"] }
1515
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }

src/main.rs

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,44 +1332,86 @@ impl WazuhToolsServer {
13321332
let mut logs_client = self.wazuh_logs_client.lock().await;
13331333

13341334
match logs_client.get_logcollector_stats(&agent_id).await {
1335-
Ok(stats) => {
1336-
let targets_info: String = stats.targets.iter()
1337-
.map(|target| format!(" - Name: {}, Drops: {}", target.name, target.drops))
1338-
.collect::<Vec<String>>()
1339-
.join("\n");
1335+
Ok(stats) => { // stats is wazuh_client::logs::LogCollectorStats
1336+
// Helper closure to format a LogCollectorPeriod
1337+
let format_period = |period_name: &str, period_data: &wazuh_client::logs::LogCollectorPeriod| -> String {
1338+
let files_info: String = period_data.files.iter()
1339+
.map(|file: &wazuh_client::logs::LogFile| {
1340+
let targets_str: String = file.targets.iter()
1341+
.map(|target: &wazuh_client::logs::LogTarget| {
1342+
format!(" - Name: {}, Drops: {}", target.name, target.drops)
1343+
})
1344+
.collect::<Vec<String>>()
1345+
.join("\n");
1346+
let targets_display = if targets_str.is_empty() {
1347+
" (No specific targets with drops for this file)".to_string()
1348+
} else {
1349+
format!(" Targets:\n{}", targets_str)
1350+
};
1351+
format!(
1352+
" - Location: {}\n Events: {}\n Bytes: {}\n{}",
1353+
file.location, file.events, file.bytes, targets_display
1354+
)
1355+
})
1356+
.collect::<Vec<String>>()
1357+
.join("\n\n");
1358+
1359+
let files_display = if files_info.is_empty() {
1360+
" (No files processed in this period)".to_string()
1361+
} else {
1362+
files_info
1363+
};
1364+
1365+
format!(
1366+
"{}:\n Start: {}\n End: {}\n Files:\n{}",
1367+
period_name, period_data.start, period_data.end, files_display
1368+
)
1369+
};
1370+
1371+
let global_period_info = format_period("Global Period", &stats.global);
1372+
let interval_period_info = format_period("Interval Period", &stats.interval);
13401373

13411374
let formatted_text = format!(
1342-
"Log Collector Stats for Agent: {}\nTotal Events: {}\nEvents Dropped: {}\nBytes Processed: {}\nTargets:\n{}",
1343-
stats.agent_id, stats.events, stats.events_dropped, stats.bytes, targets_info
1375+
"Log Collector Stats for Agent: {}\n\n{}\n\n{}",
1376+
agent_id, // Use the agent_id from params
1377+
global_period_info,
1378+
interval_period_info
13441379
);
13451380

1346-
tracing::info!("Successfully retrieved log collector stats for agent {}", agent_id);
1381+
tracing::info!("Successfully retrieved and formatted log collector stats for agent {}", agent_id);
13471382
Ok(CallToolResult::success(vec![Content::text(formatted_text)]))
13481383
}
13491384
Err(e) => {
13501385
// Check if the error is due to agent not found or stats not available
13511386
if let wazuh_client::WazuhApiError::ApiError(msg) = &e {
1352-
if msg.contains(&format!("Log collector stats for agent {} not found", agent_id)) ||
1353-
msg.contains("Agent Not Found") { // General agent not found
1354-
tracing::info!("No log collector stats found for agent {}. Returning standard message.", agent_id);
1387+
// This specific message is returned by the client if affected_items is empty/missing
1388+
if msg.contains(&format!("Log collector stats for agent {} not found", agent_id)) {
1389+
tracing::info!("No log collector stats found for agent {} (API error). Returning standard message.", agent_id);
13551390
return Ok(CallToolResult::success(vec![Content::text(
1356-
format!("No log collector stats found for agent {}. The agent might not exist or stats are unavailable.", agent_id),
1391+
format!("No log collector stats found for agent {}. The agent might not exist, stats are unavailable, or the agent is not active.", agent_id),
13571392
)]));
13581393
}
1359-
}
1360-
match e {
1361-
wazuh_client::WazuhApiError::HttpError { status, .. } if status == StatusCode::NOT_FOUND => {
1362-
tracing::info!("No log collector stats found for agent {} (HTTP 404). Returning standard message.", agent_id);
1363-
Ok(CallToolResult::success(vec![Content::text(
1364-
format!("No log collector stats found for agent {}. The agent might not exist or stats are unavailable.", agent_id),
1365-
)]))
1394+
// General "Agent Not Found" might also come as an ApiError from other layers
1395+
if msg.contains("Agent Not Found") {
1396+
tracing::info!("Agent {} not found (API error). Returning standard message.", agent_id);
1397+
return Ok(CallToolResult::success(vec![Content::text(
1398+
format!("Agent {} not found. Cannot retrieve log collector stats.", agent_id),
1399+
)]));
13661400
}
1367-
_ => {
1368-
let err_msg = format!("Error retrieving log collector stats for agent {} from Wazuh: {}", agent_id, e);
1369-
tracing::error!("{}", err_msg);
1370-
Ok(CallToolResult::error(vec![Content::text(err_msg)]))
1401+
}
1402+
// HTTP 404 can also indicate agent not found or endpoint issues
1403+
if let wazuh_client::WazuhApiError::HttpError { status, .. } = &e {
1404+
if *status == StatusCode::NOT_FOUND {
1405+
tracing::info!("No log collector stats found for agent {} (HTTP 404). Agent might not exist or endpoint unavailable.", agent_id);
1406+
return Ok(CallToolResult::success(vec![Content::text(
1407+
format!("No log collector stats found for agent {}. The agent might not exist, stats are unavailable, or the agent is not active.", agent_id),
1408+
)]));
13711409
}
13721410
}
1411+
// Default error handling for other cases
1412+
let err_msg = format!("Error retrieving log collector stats for agent {} from Wazuh: {}", agent_id, e);
1413+
tracing::error!("{}", err_msg);
1414+
Ok(CallToolResult::error(vec![Content::text(err_msg)]))
13731415
}
13741416
}
13751417
}
@@ -1627,7 +1669,7 @@ impl ServerHandler for WazuhToolsServer {
16271669
- 'get_wazuh_manager_error_logs': Retrieves Wazuh manager error logs. \
16281670
Optional parameter: 'limit' (default 100).\n\
16291671
- 'get_wazuh_log_collector_stats': Retrieves log collector statistics for a specific Wazuh agent. \
1630-
Requires an 'agent_id' parameter (formatted as described for other agent-specific tools).\n\
1672+
Requires an 'agent_id' parameter (formatted as described for other agent-specific tools). Returns detailed information for 'global' and 'interval' periods, including start/end times, and for each log file: location, events processed, bytes, and target-specific drop counts.\n\
16311673
- 'get_wazuh_remoted_stats': Retrieves statistics from the Wazuh remoted daemon (manager-wide).\n\
16321674
- 'get_wazuh_weekly_stats': Retrieves weekly statistics from the Wazuh manager. Returns a JSON object detailing various metrics aggregated over the past week. No parameters required.\n\
16331675
- 'get_wazuh_cluster_health': Checks the health of the Wazuh cluster. Returns a textual summary of the cluster's health status (e.g., enabled, running, connected nodes). No parameters required.\n\

0 commit comments

Comments
 (0)