@@ -485,6 +485,76 @@ def validate_protocol_version(version: Optional[str], strict: bool = False) -> s
485485
486486
487487# MCP Protocol Handlers
488+
489+ def _compact_alert (alert : dict ) -> dict :
490+ """Strip a raw Wazuh alert to essential fields for MCP output."""
491+ compact = {}
492+ if "timestamp" in alert :
493+ compact ["timestamp" ] = alert ["timestamp" ]
494+ agent = alert .get ("agent" , {})
495+ if agent :
496+ compact ["agent" ] = {"id" : agent .get ("id" , "" ), "name" : agent .get ("name" , "" )}
497+ rule = alert .get ("rule" , {})
498+ if rule :
499+ compact ["rule" ] = {
500+ "id" : rule .get ("id" , "" ),
501+ "level" : rule .get ("level" , 0 ),
502+ "description" : rule .get ("description" , "" ),
503+ "groups" : rule .get ("groups" , []),
504+ }
505+ if rule .get ("mitre" ):
506+ compact ["rule" ]["mitre" ] = rule ["mitre" ]
507+ src = alert .get ("data" , {})
508+ if src .get ("srcip" ):
509+ compact ["srcip" ] = src ["srcip" ]
510+ if src .get ("dstip" ):
511+ compact ["dstip" ] = src ["dstip" ]
512+ if alert .get ("syscheck" ):
513+ sc = alert ["syscheck" ]
514+ compact ["syscheck" ] = {"path" : sc .get ("path" , "" ), "event" : sc .get ("event" , "" )}
515+ if alert .get ("full_log" ):
516+ log = alert ["full_log" ]
517+ compact ["full_log" ] = (log [:300 ] + "..." ) if len (log ) > 300 else log
518+ return compact
519+
520+
521+ def _compact_alerts_result (result : dict ) -> dict :
522+ """Apply compaction to a standard alerts result dict."""
523+ data = result .get ("data" , {})
524+ items = data .get ("affected_items" , [])
525+ data ["affected_items" ] = [_compact_alert (a ) for a in items ]
526+ return result
527+
528+
529+ def _compact_vulnerability (vuln : dict ) -> dict :
530+ """Strip a raw Wazuh vulnerability to essential fields for MCP output."""
531+ compact = {}
532+ for key in ("id" , "severity" ):
533+ if key in vuln :
534+ compact [key ] = vuln [key ]
535+ if "description" in vuln :
536+ desc = vuln ["description" ]
537+ compact ["description" ] = (desc [:120 ] + "..." ) if len (desc ) > 120 else desc
538+ if "published_at" in vuln :
539+ compact ["published_at" ] = vuln ["published_at" ]
540+ pkg = vuln .get ("package" , {})
541+ if pkg :
542+ compact ["package" ] = {"name" : pkg .get ("name" , "" ), "version" : pkg .get ("version" , "" )}
543+ agent = vuln .get ("agent" , {})
544+ if agent :
545+ compact ["agent" ] = {"id" : agent .get ("id" , "" ), "name" : agent .get ("name" , "" )}
546+ return compact
547+
548+
549+ def _compact_vulns_result (result : dict ) -> dict :
550+ """Apply compaction to a standard vulnerabilities result dict."""
551+ data = result .get ("data" , {})
552+ items = data .get ("affected_items" , [])
553+ if items :
554+ data ["affected_items" ] = [_compact_vulnerability (v ) for v in items ]
555+ return result
556+
557+
488558async def handle_initialize (params : Dict [str , Any ], session : MCPSession ) -> Dict [str , Any ]:
489559 """Handle MCP initialize method per MCP specification."""
490560 client_protocol_version = params .get ("protocolVersion" , "2025-03-26" )
@@ -940,7 +1010,8 @@ async def handle_tools_list(params: Dict[str, Any], session: MCPSession) -> Dict
9401010 "level" : {"type" : "string" , "description" : "Filter by alert level (e.g., '12', '10+')" },
9411011 "agent_id" : {"type" : "string" , "description" : "Filter by agent ID" },
9421012 "timestamp_start" : {"type" : "string" , "description" : "Start timestamp (ISO format)" },
943- "timestamp_end" : {"type" : "string" , "description" : "End timestamp (ISO format)" }
1013+ "timestamp_end" : {"type" : "string" , "description" : "End timestamp (ISO format)" },
1014+ "compact" : {"type" : "boolean" , "default" : True , "description" : "Return compact alerts with essential fields only (recommended to avoid token limits)" }
9441015 },
9451016 "required" : []
9461017 }
@@ -977,7 +1048,8 @@ async def handle_tools_list(params: Dict[str, Any], session: MCPSession) -> Dict
9771048 "properties" : {
9781049 "query" : {"type" : "string" , "description" : "Search query or pattern" },
9791050 "time_range" : {"type" : "string" , "enum" : ["1h" , "6h" , "24h" , "7d" ], "default" : "24h" },
980- "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 1000 , "default" : 100 }
1051+ "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 1000 , "default" : 100 },
1052+ "compact" : {"type" : "boolean" , "default" : True , "description" : "Return compact events with essential fields only (recommended to avoid token limits)" }
9811053 },
9821054 "required" : ["query" ]
9831055 }
@@ -1062,7 +1134,8 @@ async def handle_tools_list(params: Dict[str, Any], session: MCPSession) -> Dict
10621134 "properties" : {
10631135 "agent_id" : {"type" : "string" , "description" : "Filter by specific agent ID" },
10641136 "severity" : {"type" : "string" , "enum" : ["low" , "medium" , "high" , "critical" ], "description" : "Filter by severity level" },
1065- "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 500 , "default" : 100 }
1137+ "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 500 , "default" : 100 },
1138+ "compact" : {"type" : "boolean" , "default" : True , "description" : "Return compact vulnerabilities with essential fields only (recommended to avoid token limits)" }
10661139 },
10671140 "required" : []
10681141 }
@@ -1073,7 +1146,8 @@ async def handle_tools_list(params: Dict[str, Any], session: MCPSession) -> Dict
10731146 "inputSchema" : {
10741147 "type" : "object" ,
10751148 "properties" : {
1076- "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 500 , "default" : 50 }
1149+ "limit" : {"type" : "integer" , "minimum" : 1 , "maximum" : 500 , "default" : 50 },
1150+ "compact" : {"type" : "boolean" , "default" : True , "description" : "Return compact vulnerabilities with essential fields only (recommended to avoid token limits)" }
10771151 },
10781152 "required" : []
10791153 }
@@ -1287,12 +1361,15 @@ async def handle_tools_call(params: Dict[str, Any], session: MCPSession) -> Dict
12871361 agent_id = arguments .get ("agent_id" )
12881362 timestamp_start = arguments .get ("timestamp_start" )
12891363 timestamp_end = arguments .get ("timestamp_end" )
1364+ compact = arguments .get ("compact" , True )
12901365 result = await wazuh_client .get_alerts (
1291- limit = limit , rule_id = rule_id , level = level ,
1292- agent_id = agent_id , timestamp_start = timestamp_start ,
1366+ limit = limit , rule_id = rule_id , level = level ,
1367+ agent_id = agent_id , timestamp_start = timestamp_start ,
12931368 timestamp_end = timestamp_end
12941369 )
1295- return {"content" : [{"type" : "text" , "text" : f"Wazuh Alerts:\n { json .dumps (result , indent = 2 )} " }]}
1370+ if compact :
1371+ result = _compact_alerts_result (result )
1372+ return {"content" : [{"type" : "text" , "text" : f"Wazuh Alerts:\n { json .dumps (result , indent = 2 if not compact else None )} " }]}
12961373
12971374 elif tool_name == "get_wazuh_alert_summary" :
12981375 time_range = arguments .get ("time_range" , "24h" )
@@ -1310,8 +1387,11 @@ async def handle_tools_call(params: Dict[str, Any], session: MCPSession) -> Dict
13101387 query = arguments .get ("query" )
13111388 time_range = arguments .get ("time_range" , "24h" )
13121389 limit = arguments .get ("limit" , 100 )
1390+ compact = arguments .get ("compact" , True )
13131391 result = await wazuh_client .search_security_events (query , time_range , limit )
1314- return {"content" : [{"type" : "text" , "text" : f"Security Events:\n { json .dumps (result , indent = 2 )} " }]}
1392+ if compact :
1393+ result = _compact_alerts_result (result )
1394+ return {"content" : [{"type" : "text" , "text" : f"Security Events:\n { json .dumps (result , indent = 2 if not compact else None )} " }]}
13151395
13161396 # Agent Management Tools
13171397 elif tool_name == "get_wazuh_agents" :
@@ -1352,13 +1432,19 @@ async def handle_tools_call(params: Dict[str, Any], session: MCPSession) -> Dict
13521432 agent_id = arguments .get ("agent_id" )
13531433 severity = arguments .get ("severity" )
13541434 limit = arguments .get ("limit" , 100 )
1435+ compact = arguments .get ("compact" , True )
13551436 result = await wazuh_client .get_vulnerabilities (agent_id = agent_id , severity = severity , limit = limit )
1356- return {"content" : [{"type" : "text" , "text" : f"Vulnerabilities:\n { json .dumps (result , indent = 2 )} " }]}
1437+ if compact :
1438+ result = _compact_vulns_result (result )
1439+ return {"content" : [{"type" : "text" , "text" : f"Vulnerabilities:\n { json .dumps (result , indent = 2 if not compact else None )} " }]}
13571440
13581441 elif tool_name == "get_wazuh_critical_vulnerabilities" :
13591442 limit = arguments .get ("limit" , 50 )
1443+ compact = arguments .get ("compact" , True )
13601444 result = await wazuh_client .get_critical_vulnerabilities (limit )
1361- return {"content" : [{"type" : "text" , "text" : f"Critical Vulnerabilities:\n { json .dumps (result , indent = 2 )} " }]}
1445+ if compact :
1446+ result = _compact_vulns_result (result )
1447+ return {"content" : [{"type" : "text" , "text" : f"Critical Vulnerabilities:\n { json .dumps (result , indent = 2 if not compact else None )} " }]}
13621448
13631449 elif tool_name == "get_wazuh_vulnerability_summary" :
13641450 time_range = arguments .get ("time_range" , "7d" )
0 commit comments