mcp-instana 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. mcp_instana-0.1.1.dist-info/METADATA +908 -0
  2. mcp_instana-0.1.1.dist-info/RECORD +30 -0
  3. {mcp_instana-0.1.0.dist-info → mcp_instana-0.1.1.dist-info}/WHEEL +1 -1
  4. mcp_instana-0.1.1.dist-info/entry_points.txt +4 -0
  5. mcp_instana-0.1.0.dist-info/LICENSE → mcp_instana-0.1.1.dist-info/licenses/LICENSE.md +3 -3
  6. src/application/__init__.py +1 -0
  7. src/{client/application_alert_config_mcp_tools.py → application/application_alert_config.py} +251 -273
  8. src/application/application_analyze.py +415 -0
  9. src/application/application_catalog.py +153 -0
  10. src/{client/application_metrics_mcp_tools.py → application/application_metrics.py} +107 -129
  11. src/{client/application_resources_mcp_tools.py → application/application_resources.py} +128 -150
  12. src/application/application_settings.py +1135 -0
  13. src/application/application_topology.py +107 -0
  14. src/core/__init__.py +1 -0
  15. src/core/server.py +436 -0
  16. src/core/utils.py +213 -0
  17. src/event/__init__.py +1 -0
  18. src/{client/events_mcp_tools.py → event/events_tools.py} +128 -136
  19. src/infrastructure/__init__.py +1 -0
  20. src/{client/infrastructure_analyze_mcp_tools.py → infrastructure/infrastructure_analyze.py} +200 -203
  21. src/{client/infrastructure_catalog_mcp_tools.py → infrastructure/infrastructure_catalog.py} +194 -264
  22. src/infrastructure/infrastructure_metrics.py +167 -0
  23. src/{client/infrastructure_resources_mcp_tools.py → infrastructure/infrastructure_resources.py} +192 -223
  24. src/{client/infrastructure_topology_mcp_tools.py → infrastructure/infrastructure_topology.py} +105 -106
  25. src/log/__init__.py +1 -0
  26. src/log/log_alert_configuration.py +331 -0
  27. src/prompts/mcp_prompts.py +900 -0
  28. src/prompts/prompt_loader.py +29 -0
  29. src/prompts/prompt_registry.json +21 -0
  30. mcp_instana-0.1.0.dist-info/METADATA +0 -649
  31. mcp_instana-0.1.0.dist-info/RECORD +0 -19
  32. mcp_instana-0.1.0.dist-info/entry_points.txt +0 -3
  33. src/client/What is the sum of queue depth for all q +0 -55
  34. src/client/instana_client_base.py +0 -93
  35. src/client/log_alert_configuration_mcp_tools.py +0 -316
  36. src/client/show the top 5 services with the highest +0 -28
  37. src/mcp_server.py +0 -343
@@ -4,95 +4,88 @@ Agent Monitoring Events MCP Tools Module
4
4
  This module provides agent monitoring events-specific MCP tools for Instana monitoring.
5
5
  """
6
6
 
7
- import sys
8
- from typing import Dict, Any, Optional, List, Union
7
+ import logging
9
8
  from datetime import datetime
9
+ from typing import Any, Dict, Optional
10
10
 
11
11
  # Import the correct class name (EventsApi with lowercase 'i')
12
12
  from instana_client.api.events_api import EventsApi
13
13
 
14
- from .instana_client_base import BaseInstanaClient, register_as_tool
14
+ from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
15
+
16
+ # Configure logger for this module
17
+ logger = logging.getLogger(__name__)
15
18
 
16
19
  class AgentMonitoringEventsMCPTools(BaseInstanaClient):
17
20
  """Tools for agent monitoring events in Instana MCP."""
18
-
21
+
19
22
  def __init__(self, read_token: str, base_url: str):
20
23
  """Initialize the Agent Monitoring Events MCP tools client."""
21
24
  super().__init__(read_token=read_token, base_url=base_url)
22
-
23
- # Configure the API client with the correct base URL and authentication
24
- from instana_client.configuration import Configuration
25
- configuration = Configuration()
26
- configuration.host = base_url
27
- configuration.api_key['ApiKeyAuth'] = read_token
28
- configuration.api_key_prefix['ApiKeyAuth'] = 'apiToken'
29
-
30
- # Create an API client with this configuration
31
- from instana_client.api_client import ApiClient
32
- api_client = ApiClient(configuration=configuration)
33
-
34
- # Initialize the Instana SDK's EventsApi with our configured client
35
- self.events_api = EventsApi(api_client=api_client)
36
-
37
-
25
+
38
26
  @register_as_tool
39
- async def get_event(self, event_id: str, ctx=None) -> Dict[str, Any]:
27
+ @with_header_auth(EventsApi)
28
+ async def get_event(self, event_id: str, ctx=None, api_client=None) -> Dict[str, Any]:
40
29
  """
41
30
  Get a specific event by ID.
42
-
31
+
43
32
  Args:
44
33
  event_id: The ID of the event to retrieve
45
34
  ctx: The MCP context (optional)
46
-
35
+ api_client: API client for testing (optional)
36
+
47
37
  Returns:
48
38
  Dictionary containing the event data or error information
49
39
  """
50
40
  try:
51
41
  # Call the get_event method from the SDK
52
- result = self.events_api.get_event(event_id=event_id)
53
-
42
+ result = api_client.get_event(event_id=event_id)
43
+
54
44
  return result
55
45
  except Exception as e:
56
- return {"error": f"Failed to get event: {str(e)}"}
46
+ logger.error(f"Error in get_event: {e}", exc_info=True)
47
+ return {"error": f"Failed to get event: {e!s}"}
57
48
 
58
49
  @register_as_tool
50
+ @with_header_auth(EventsApi)
59
51
  async def get_kubernetes_info_events(self,
60
- from_time: Optional[int] = None,
61
- to_time: Optional[int] = None,
62
- time_range: Optional[str] = None,
63
- max_events: Optional[int] = 50, # Added parameter to limit events
64
- ctx=None) -> Dict[str, Any]:
52
+ from_time: Optional[int] = None,
53
+ to_time: Optional[int] = None,
54
+ time_range: Optional[str] = None,
55
+ max_events: Optional[int] = 50, # Added parameter to limit events
56
+ ctx=None, api_client=None) -> Dict[str, Any]:
65
57
  """
66
58
  Get Kubernetes info events based on the provided parameters and return a detailed analysis.
67
-
59
+
68
60
  This tool retrieves Kubernetes events from Instana and provides a detailed analysis focusing on top problems,
69
61
  their details, and actionable fix suggestions. You can specify a time range using timestamps or natural language
70
62
  like "last 24 hours" or "last 2 days".
71
-
63
+
72
64
  Args:
73
65
  from_time: Start timestamp in milliseconds since epoch (optional)
74
66
  to_time: End timestamp in milliseconds since epoch (optional)
75
67
  time_range: Natural language time range like "last 24 hours", "last 2 days", "last week" (optional)
76
68
  max_events: Maximum number of events to process (default: 50)
77
69
  ctx: The MCP context (optional)
78
-
70
+ api_client: API client for testing (optional)
71
+
79
72
  Returns:
80
73
  Dictionary containing detailed Kubernetes events analysis or error information
81
74
  """
82
75
  try:
83
76
  # Process natural language time range if provided
84
77
  if time_range:
85
- print(f"DEBUG: Processing natural language time range: '{time_range}'", file=sys.stderr)
86
-
78
+ logger.debug(f"Processing natural language time range: '{time_range}'")
79
+
87
80
  # Current time in milliseconds
88
81
  current_time_ms = int(datetime.now().timestamp() * 1000)
89
-
82
+
90
83
  # Default to 24 hours if just "last few hours" is specified
91
84
  if time_range.lower() in ["last few hours", "last hours", "few hours"]:
92
85
  hours = 24
93
86
  from_time = current_time_ms - (hours * 60 * 60 * 1000)
94
87
  to_time = current_time_ms
95
- print(f"DEBUG: Interpreted as last {hours} hours", file=sys.stderr)
88
+ logger.debug(f"Interpreted as last {hours} hours")
96
89
  # Extract hours if specified
97
90
  elif "hour" in time_range.lower():
98
91
  import re
@@ -126,26 +119,26 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
126
119
  hours = 24
127
120
  from_time = current_time_ms - (hours * 60 * 60 * 1000)
128
121
  to_time = current_time_ms
129
-
122
+
130
123
  # Set default time range if not provided
131
124
  if not to_time:
132
125
  to_time = int(datetime.now().timestamp() * 1000)
133
126
  if not from_time:
134
127
  from_time = to_time - (24 * 60 * 60 * 1000) # Default to 24 hours
135
-
128
+
136
129
  # Call the kubernetes_info_events method from the SDK
137
- result = self.events_api.kubernetes_info_events(
130
+ result = api_client.kubernetes_info_events(
138
131
  to=to_time,
139
132
  var_from=from_time,
140
133
  window_size=None,
141
134
  filter_event_updates=None,
142
135
  exclude_triggered_before=None
143
136
  )
144
-
137
+
145
138
  # Print the raw result for debugging
146
- print(f"DEBUG: Raw API result type: {type(result)}", file=sys.stderr)
147
- print(f"DEBUG: Raw API result length: {len(result) if isinstance(result, list) else 'not a list'}", file=sys.stderr)
148
-
139
+ logger.debug(f"Raw API result type: {type(result)}")
140
+ logger.debug(f"Raw API result length: {len(result) if isinstance(result, list) else 'not a list'}")
141
+
149
142
  # If there are no events, return early
150
143
  if not result or (isinstance(result, list) and len(result) == 0):
151
144
  from_date = datetime.fromtimestamp(from_time/1000).strftime('%Y-%m-%d %H:%M:%S')
@@ -155,17 +148,17 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
155
148
  "time_range": f"{from_date} to {to_date}",
156
149
  "events_count": 0
157
150
  }
158
-
151
+
159
152
  # Process the events to create a summary
160
153
  events = result if isinstance(result, list) else [result]
161
-
154
+
162
155
  # Get the total number of events before limiting
163
156
  total_events_count = len(events)
164
-
157
+
165
158
  # Limit the number of events to process
166
159
  events = events[:max_events]
167
- print(f"DEBUG: Limited to processing {len(events)} events out of {total_events_count} total events", file=sys.stderr)
168
-
160
+ logger.debug(f"Limited to processing {len(events)} events out of {total_events_count} total events")
161
+
169
162
  # Convert InfraEventResult objects to dictionaries if needed
170
163
  event_dicts = []
171
164
  for event in events:
@@ -173,14 +166,14 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
173
166
  event_dicts.append(event.to_dict())
174
167
  else:
175
168
  event_dicts.append(event)
176
-
169
+
177
170
  # Group events by problem type
178
171
  problem_groups = {}
179
-
172
+
180
173
  # Process each event
181
174
  for event in event_dicts:
182
175
  problem = event.get("problem", "Unknown")
183
-
176
+
184
177
  # Initialize problem group if not exists
185
178
  if problem not in problem_groups:
186
179
  problem_groups[problem] = {
@@ -191,26 +184,26 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
191
184
  "fix_suggestions": set(),
192
185
  "sample_events": []
193
186
  }
194
-
187
+
195
188
  # Update problem group
196
189
  problem_groups[problem]["count"] += 1
197
-
190
+
198
191
  # Extract namespace from entityLabel
199
192
  entity_label = event.get("entityLabel", "")
200
193
  if "/" in entity_label:
201
194
  namespace, entity = entity_label.split("/", 1)
202
195
  problem_groups[problem]["affected_namespaces"].add(namespace)
203
196
  problem_groups[problem]["affected_entities"].add(entity)
204
-
197
+
205
198
  # Add detail and fix suggestion
206
199
  detail = event.get("detail", "")
207
200
  if detail:
208
201
  problem_groups[problem]["details"].add(detail)
209
-
202
+
210
203
  fix_suggestion = event.get("fixSuggestion", "")
211
204
  if fix_suggestion:
212
205
  problem_groups[problem]["fix_suggestions"].add(fix_suggestion)
213
-
206
+
214
207
  # Add sample event (up to 3 per problem)
215
208
  if len(problem_groups[problem]["sample_events"]) < 3:
216
209
  simple_event = {
@@ -220,17 +213,17 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
220
213
  "detail": detail
221
214
  }
222
215
  problem_groups[problem]["sample_events"].append(simple_event)
223
-
216
+
224
217
  # Sort problems by count (most frequent first)
225
218
  sorted_problems = sorted(problem_groups.items(), key=lambda x: x[1]["count"], reverse=True)
226
-
219
+
227
220
  # Format the time range in a human-readable format
228
221
  from_date = datetime.fromtimestamp(from_time/1000).strftime('%Y-%m-%d %H:%M:%S')
229
222
  to_date = datetime.fromtimestamp(to_time/1000).strftime('%Y-%m-%d %H:%M:%S')
230
-
223
+
231
224
  # Create a detailed analysis of each problem
232
225
  problem_analyses = []
233
-
226
+
234
227
  # Process each problem
235
228
  for problem_name, problem_data in sorted_problems:
236
229
  # Create a detailed problem analysis
@@ -242,9 +235,9 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
242
235
  "fix_suggestions": list(problem_data["fix_suggestions"]),
243
236
  "sample_events": problem_data["sample_events"]
244
237
  }
245
-
238
+
246
239
  problem_analyses.append(problem_analysis)
247
-
240
+
248
241
  # Create a comprehensive analysis
249
242
  analysis_result = {
250
243
  "summary": f"Analysis based on {len(events)} of {total_events_count} Kubernetes events between {from_date} and {to_date}.",
@@ -253,64 +246,63 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
253
246
  "events_analyzed": len(events),
254
247
  "problem_analyses": problem_analyses[:10] # Limit to top 10 problems for readability
255
248
  }
256
-
249
+
257
250
  # Create a more user-friendly text summary for direct display
258
251
  markdown_summary = "# Kubernetes Events Analysis\n\n"
259
252
  markdown_summary += f"Analysis based on {len(events)} of {total_events_count} Kubernetes events between {from_date} and {to_date}.\n\n"
260
-
253
+
261
254
  markdown_summary += "## Top Problems\n\n"
262
-
255
+
263
256
  # Add each problem to the markdown summary
264
257
  for problem_analysis in problem_analyses[:5]: # Limit to top 5 for readability
265
258
  problem_name = problem_analysis["problem"]
266
259
  count = problem_analysis["count"]
267
-
260
+
268
261
  markdown_summary += f"### {problem_name} ({count} events)\n\n"
269
-
262
+
270
263
  # Add affected namespaces if available
271
264
  if problem_analysis.get("affected_namespaces"):
272
265
  namespaces = ", ".join(problem_analysis["affected_namespaces"][:5])
273
266
  if len(problem_analysis["affected_namespaces"]) > 5:
274
267
  namespaces += f" and {len(problem_analysis['affected_namespaces']) - 5} more"
275
268
  markdown_summary += f"**Affected Namespaces:** {namespaces}\n\n"
276
-
269
+
277
270
  # Add fix suggestions
278
271
  if problem_analysis.get("fix_suggestions"):
279
272
  markdown_summary += "**Fix Suggestions:**\n\n"
280
273
  for suggestion in list(problem_analysis["fix_suggestions"])[:3]: # Limit to top 3 suggestions
281
274
  markdown_summary += f"- {suggestion}\n"
282
-
275
+
283
276
  markdown_summary += "\n"
284
-
277
+
285
278
  # Add the markdown summary to the result
286
279
  analysis_result["markdown_summary"] = markdown_summary
287
-
280
+
288
281
  return analysis_result
289
-
282
+
290
283
  except Exception as e:
291
- print(f"Error in get_kubernetes_info_events: {e}", file=sys.stderr)
292
- import traceback
293
- traceback.print_exc(file=sys.stderr)
284
+ logger.error(f"Error in get_kubernetes_info_events: {e}", exc_info=True)
294
285
  return {
295
- "error": f"Failed to get Kubernetes info events: {str(e)}"
286
+ "error": f"Failed to get Kubernetes info events: {e!s}"
296
287
  }
297
288
 
298
289
  @register_as_tool
299
- async def get_agent_monitoring_events(self,
300
- query: Optional[str] = None,
301
- from_time: Optional[int] = None,
302
- to_time: Optional[int] = None,
303
- size: Optional[int] = 100,
304
- max_events: Optional[int] = 50, # Added parameter to limit events
305
- time_range: Optional[str] = None, # Added parameter for natural language time range
306
- ctx=None) -> Dict[str, Any]:
290
+ @with_header_auth(EventsApi)
291
+ async def get_agent_monitoring_events(self,
292
+ query: Optional[str] = None,
293
+ from_time: Optional[int] = None,
294
+ to_time: Optional[int] = None,
295
+ size: Optional[int] = 100,
296
+ max_events: Optional[int] = 50, # Added parameter to limit events
297
+ time_range: Optional[str] = None, # Added parameter for natural language time range
298
+ ctx=None, api_client=None) -> Dict[str, Any]:
307
299
  """
308
300
  Get agent monitoring events from Instana and return a detailed analysis.
309
-
310
- This tool retrieves agent monitoring events from Instana and provides a detailed analysis focusing on
311
- monitoring issues, their frequency, and affected entities. You can specify a time range using timestamps
301
+
302
+ This tool retrieves agent monitoring events from Instana and provides a detailed analysis focusing on
303
+ monitoring issues, their frequency, and affected entities. You can specify a time range using timestamps
312
304
  or natural language like "last 24 hours" or "last 2 days".
313
-
305
+
314
306
  Args:
315
307
  query: Query string to filter events (optional)
316
308
  from_time: Start timestamp in milliseconds since epoch (optional, defaults to 1 hour ago)
@@ -319,24 +311,25 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
319
311
  max_events: Maximum number of events to process for analysis (optional, default 50)
320
312
  time_range: Natural language time range like "last 24 hours", "last 2 days", "last week" (optional)
321
313
  ctx: The MCP context (optional)
322
-
314
+ api_client: API client for testing (optional)
315
+
323
316
  Returns:
324
317
  Dictionary containing summarized agent monitoring events data or error information
325
318
  """
326
319
  try:
327
320
  # Process natural language time range if provided
328
321
  if time_range:
329
- print(f"DEBUG: Processing natural language time range: '{time_range}'", file=sys.stderr)
330
-
322
+ logger.debug(f"Processing natural language time range: '{time_range}'")
323
+
331
324
  # Current time in milliseconds
332
325
  current_time_ms = int(datetime.now().timestamp() * 1000)
333
-
326
+
334
327
  # Default to 24 hours if just "last few hours" is specified
335
328
  if time_range.lower() in ["last few hours", "last hours", "few hours"]:
336
329
  hours = 24
337
330
  from_time = current_time_ms - (hours * 60 * 60 * 1000)
338
331
  to_time = current_time_ms
339
- print(f"DEBUG: Interpreted as last {hours} hours", file=sys.stderr)
332
+ logger.debug(f"Interpreted as last {hours} hours")
340
333
  # Extract hours if specified
341
334
  elif "hour" in time_range.lower():
342
335
  import re
@@ -370,29 +363,29 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
370
363
  hours = 24
371
364
  from_time = current_time_ms - (hours * 60 * 60 * 1000)
372
365
  to_time = current_time_ms
373
-
374
- print(f"get_agent_monitoring_events called with query={query}, from_time={from_time}, to_time={to_time}, size={size}", file=sys.stderr)
375
-
366
+
367
+ logger.debug(f"get_agent_monitoring_events called with query={query}, from_time={from_time}, to_time={to_time}, size={size}")
368
+
376
369
  # Set default time range if not provided
377
370
  if not to_time:
378
371
  to_time = int(datetime.now().timestamp() * 1000)
379
-
372
+
380
373
  if not from_time:
381
374
  from_time = to_time - (60 * 60 * 1000) # Default to 1 hour
382
-
375
+
383
376
  # Call the agent_monitoring_events method from the SDK
384
- result = self.events_api.agent_monitoring_events(
377
+ result = api_client.agent_monitoring_events(
385
378
  to=to_time,
386
379
  var_from=from_time,
387
380
  window_size=None,
388
381
  filter_event_updates=None,
389
382
  exclude_triggered_before=None
390
383
  )
391
-
384
+
392
385
  # Print the raw result for debugging
393
- print(f"DEBUG: Raw API result type: {type(result)}", file=sys.stderr)
394
- print(f"DEBUG: Raw API result length: {len(result) if isinstance(result, list) else 'not a list'}", file=sys.stderr)
395
-
386
+ logger.debug(f"Raw API result type: {type(result)}")
387
+ logger.debug(f"Raw API result length: {len(result) if isinstance(result, list) else 'not a list'}")
388
+
396
389
  # If there are no events, return early
397
390
  if not result or (isinstance(result, list) and len(result) == 0):
398
391
  from_date = datetime.fromtimestamp(from_time/1000).strftime('%Y-%m-%d %H:%M:%S')
@@ -402,17 +395,17 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
402
395
  "time_range": f"{from_date} to {to_date}",
403
396
  "events_count": 0
404
397
  }
405
-
398
+
406
399
  # Process the events to create a summary
407
400
  events = result if isinstance(result, list) else [result]
408
-
401
+
409
402
  # Get the total number of events before limiting
410
403
  total_events_count = len(events)
411
-
404
+
412
405
  # Limit the number of events to process
413
406
  events = events[:max_events]
414
- print(f"DEBUG: Limited to processing {len(events)} events out of {total_events_count} total events", file=sys.stderr)
415
-
407
+ logger.debug(f"Limited to processing {len(events)} events out of {total_events_count} total events")
408
+
416
409
  # Convert objects to dictionaries if needed
417
410
  event_dicts = []
418
411
  for event in events:
@@ -420,17 +413,17 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
420
413
  event_dicts.append(event.to_dict())
421
414
  else:
422
415
  event_dicts.append(event)
423
-
416
+
424
417
  # Group events by problem type
425
418
  problem_groups = {}
426
-
419
+
427
420
  # Process each event
428
421
  for event in event_dicts:
429
422
  # Extract the monitoring issue from the problem field
430
423
  full_problem = event.get("problem", "Unknown")
431
424
  # Strip "Monitoring issue: " prefix if present
432
425
  problem = full_problem.replace("Monitoring issue: ", "") if "Monitoring issue: " in full_problem else full_problem
433
-
426
+
434
427
  # Initialize problem group if not exists
435
428
  if problem not in problem_groups:
436
429
  problem_groups[problem] = {
@@ -439,19 +432,19 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
439
432
  "entity_types": set(),
440
433
  "sample_events": []
441
434
  }
442
-
435
+
443
436
  # Update problem group
444
437
  problem_groups[problem]["count"] += 1
445
-
438
+
446
439
  # Add entity information
447
440
  entity_name = event.get("entityName", "Unknown")
448
441
  entity_label = event.get("entityLabel", "Unknown")
449
442
  entity_type = event.get("entityType", "Unknown")
450
-
443
+
451
444
  entity_info = f"{entity_name} ({entity_label})"
452
445
  problem_groups[problem]["affected_entities"].add(entity_info)
453
446
  problem_groups[problem]["entity_types"].add(entity_type)
454
-
447
+
455
448
  # Add sample event (up to 3 per problem)
456
449
  if len(problem_groups[problem]["sample_events"]) < 3:
457
450
  simple_event = {
@@ -462,17 +455,17 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
462
455
  "severity": event.get("severity", 0)
463
456
  }
464
457
  problem_groups[problem]["sample_events"].append(simple_event)
465
-
458
+
466
459
  # Sort problems by count (most frequent first)
467
460
  sorted_problems = sorted(problem_groups.items(), key=lambda x: x[1]["count"], reverse=True)
468
-
461
+
469
462
  # Format the time range in a human-readable format
470
463
  from_date = datetime.fromtimestamp(from_time/1000).strftime('%Y-%m-%d %H:%M:%S')
471
464
  to_date = datetime.fromtimestamp(to_time/1000).strftime('%Y-%m-%d %H:%M:%S')
472
-
465
+
473
466
  # Create a detailed analysis of each problem
474
467
  problem_analyses = []
475
-
468
+
476
469
  # Process each problem
477
470
  for problem_name, problem_data in sorted_problems:
478
471
  # Create a detailed problem analysis
@@ -483,9 +476,9 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
483
476
  "entity_types": list(problem_data["entity_types"]),
484
477
  "sample_events": problem_data["sample_events"]
485
478
  }
486
-
479
+
487
480
  problem_analyses.append(problem_analysis)
488
-
481
+
489
482
  # Create a comprehensive analysis
490
483
  analysis_result = {
491
484
  "summary": f"Analysis based on {len(events)} of {total_events_count} agent monitoring events between {from_date} and {to_date}.",
@@ -494,38 +487,37 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
494
487
  "events_analyzed": len(events),
495
488
  "problem_analyses": problem_analyses[:10] # Limit to top 10 problems for readability
496
489
  }
497
-
490
+
498
491
  # Create a more user-friendly text summary for direct display
499
492
  markdown_summary = "# Agent Monitoring Events Analysis\n\n"
500
493
  markdown_summary += f"Analysis based on {len(events)} of {total_events_count} agent monitoring events between {from_date} and {to_date}.\n\n"
501
-
494
+
502
495
  markdown_summary += "## Top Monitoring Issues\n\n"
503
-
496
+
504
497
  # Add each problem to the markdown summary
505
498
  for problem_analysis in problem_analyses[:5]: # Limit to top 5 for readability
506
499
  problem_name = problem_analysis["problem"]
507
500
  count = problem_analysis["count"]
508
-
501
+
509
502
  markdown_summary += f"### {problem_name} ({count} events)\n\n"
510
-
503
+
511
504
  # Add affected entities if available
512
505
  if problem_analysis.get("affected_entities"):
513
506
  entities = ", ".join(problem_analysis["affected_entities"][:5])
514
507
  if len(problem_analysis["affected_entities"]) > 5:
515
508
  entities += f" and {len(problem_analysis['affected_entities']) - 5} more"
516
509
  markdown_summary += f"**Affected Entities:** {entities}\n\n"
517
-
510
+
518
511
  markdown_summary += "\n"
519
-
512
+
520
513
  # Add the markdown summary to the result
521
514
  analysis_result["markdown_summary"] = markdown_summary
522
-
515
+
523
516
  return analysis_result
524
-
517
+
525
518
  except Exception as e:
526
- print(f"Error in get_agent_monitoring_events: {e}", file=sys.stderr)
527
- import traceback
528
- traceback.print_exc(file=sys.stderr)
519
+ logger.error(f"Error in get_agent_monitoring_events: {e}", exc_info=True)
529
520
  return {
530
- "error": f"Failed to get agent monitoring events: {str(e)}"
521
+ "error": f"Failed to get agent monitoring events: {e!s}"
531
522
  }
523
+
@@ -0,0 +1 @@
1
+ # Infrastructure module for MCP Instana