2020from fastmcp .server .dependencies import get_http_request
2121from utils .query_helpers import create_standard_response
2222from utils .sysdig .client_config import get_configuration
23- from utils .app_config import get_app_config
23+ from utils .app_config import AppConfig
2424from utils .sysdig .api import initialize_api_client
2525
26- logging .basicConfig (format = "%(asctime)s-%(process)d-%(levelname)s- %(message)s" , level = os .environ .get ("LOGLEVEL" , "ERROR" ))
27- log = logging .getLogger (__name__ )
28-
29- # Load app config (expects keys: mcp.host, mcp.port, mcp.transport)
30- app_config = get_app_config ()
31-
3226
3327class EventsFeedTools :
3428 """
3529 A class to encapsulate the tools for interacting with the Sysdig Secure Events Feed API.
3630 This class provides methods to retrieve event information and list runtime events.
3731 """
3832
33+ def __init__ (self , app_config : AppConfig ):
34+ self .app_config = app_config
35+ logging .basicConfig (format = "%(asctime)s-%(process)d-%(levelname)s- %(message)s" , level = self .app_config .log_level ())
36+ self .log = logging .getLogger (__name__ )
37+
3938 def init_client (self , old_api : bool = False ) -> SecureEventsApi | OldSysdigApi :
4039 """
4140 Initializes the SecureEventsApi client from the request state.
@@ -48,16 +47,16 @@ def init_client(self, old_api: bool = False) -> SecureEventsApi | OldSysdigApi:
4847 """
4948 secure_events_api : SecureEventsApi = None
5049 old_sysdig_api : OldSysdigApi = None
51- transport = os . environ . get ( "MCP_TRANSPORT" , app_config [ "mcp" ][ "transport" ]). lower ()
50+ transport = self . app_config . transport ()
5251 if transport in ["streamable-http" , "sse" ]:
5352 # Try to get the HTTP request
54- log .debug ("Attempting to get the HTTP request to initialize the Sysdig API client." )
53+ self . log .debug ("Attempting to get the HTTP request to initialize the Sysdig API client." )
5554 request : Request = get_http_request ()
5655 secure_events_api = request .state .api_instances ["secure_events" ]
5756 old_sysdig_api = request .state .api_instances ["old_sysdig_api" ]
5857 else :
5958 # If running in STDIO mode, we need to initialize the API client from environment variables
60- log .debug ("Running in STDIO mode, initializing the Sysdig API client from environment variables." )
59+ self . log .debug ("Running in STDIO mode, initializing the Sysdig API client from environment variables." )
6160 cfg = get_configuration ()
6261 api_client = initialize_api_client (cfg )
6362 secure_events_api = SecureEventsApi (api_client )
@@ -167,15 +166,15 @@ def tool_list_runtime_events(
167166 to = to_ts , var_from = from_ts , filter = filter_expr , limit = limit , cursor = cursor
168167 )
169168 duration_ms = (time .time () - start_time ) * 1000
170- log .debug (f"Execution time: { duration_ms :.2f} ms" )
169+ self . log .debug (f"Execution time: { duration_ms :.2f} ms" )
171170
172171 response = create_standard_response (
173172 results = api_response ,
174173 execution_time_ms = duration_ms ,
175174 )
176175 return response
177176 except ToolError as e :
178- log .error (f"Exception when calling SecureEventsApi->get_events_v1: { e } \n " )
177+ self . log .error (f"Exception when calling SecureEventsApi->get_events_v1: { e } \n " )
179178 raise e
180179
181180 # A tool to retrieve all the process-tree information for a specific event.Add commentMore actions
@@ -199,26 +198,39 @@ def tool_get_event_process_tree(self, event_id: str) -> dict:
199198 # Get process tree
200199 tree = old_api_client .request_process_tree_trees (event_id )
201200
202- # Parse the response
203- branches = create_standard_response (results = branches , execution_time_ms = (time .time () - start_time ) * 1000 )
204- tree = create_standard_response (results = tree , execution_time_ms = (time .time () - start_time ) * 1000 )
201+ # Parse the response (tolerates empty bodies)
202+ branches_std = create_standard_response (results = branches , execution_time_ms = (time .time () - start_time ) * 1000 )
203+ tree_std = create_standard_response (results = tree , execution_time_ms = (time .time () - start_time ) * 1000 )
205204
206205 execution_time = (time .time () - start_time ) * 1000
207206
208- response = (
209- {
210- "branches" : branches .get ("results" , []),
211- "tree" : tree .get ("results" , []),
212- "metadata" : {
213- "execution_time_ms" : execution_time ,
214- "timestamp" : datetime .utcnow ().isoformat () + "Z" ,
215- },
207+ response = {
208+ "branches" : branches_std .get ("results" , {}),
209+ "tree" : tree_std .get ("results" , {}),
210+ "metadata" : {
211+ "execution_time_ms" : execution_time ,
212+ "timestamp" : datetime .utcnow ().isoformat () + "Z" ,
216213 },
217- )
214+ }
218215
219216 return response
217+ except ApiException as e :
218+ if e .status == 404 :
219+ # Process tree not available for this event
220+ return {
221+ "branches" : {},
222+ "tree" : {},
223+ "metadata" : {
224+ "execution_time_ms" : (time .time () - start_time ) * 1000 ,
225+ "timestamp" : datetime .utcnow ().isoformat () + "Z" ,
226+ "note" : "Process tree not available for this event"
227+ },
228+ }
229+ else :
230+ self .log .error (f"Exception when calling process tree API: { e } " )
231+ raise ToolError (f"Failed to get process tree: { e } " )
220232 except ToolError as e :
221- log .error (f"Exception when calling Sysdig Sage API to get process tree: { e } " )
233+ self . log .error (f"Exception when calling Sysdig Sage API to get process tree: { e } " )
222234 raise e
223235
224236 # Prompts
0 commit comments