mcp-instana 0.2.1__py3-none-any.whl → 0.3.0__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 (29) hide show
  1. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.0.dist-info}/METADATA +2 -1
  2. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.0.dist-info}/RECORD +29 -29
  3. src/application/application_alert_config.py +45 -12
  4. src/application/application_analyze.py +28 -6
  5. src/application/application_catalog.py +11 -2
  6. src/application/application_global_alert_config.py +60 -21
  7. src/application/application_metrics.py +20 -4
  8. src/application/application_resources.py +20 -4
  9. src/application/application_settings.py +111 -35
  10. src/application/application_topology.py +22 -14
  11. src/automation/action_catalog.py +165 -188
  12. src/automation/action_history.py +21 -6
  13. src/core/server.py +7 -1
  14. src/core/utils.py +42 -5
  15. src/event/events_tools.py +30 -7
  16. src/infrastructure/infrastructure_analyze.py +18 -4
  17. src/infrastructure/infrastructure_catalog.py +72 -16
  18. src/infrastructure/infrastructure_metrics.py +5 -1
  19. src/infrastructure/infrastructure_resources.py +30 -11
  20. src/infrastructure/infrastructure_topology.py +10 -2
  21. src/log/log_alert_configuration.py +106 -31
  22. src/settings/custom_dashboard_tools.py +30 -7
  23. src/website/website_analyze.py +10 -2
  24. src/website/website_catalog.py +14 -3
  25. src/website/website_configuration.py +54 -13
  26. src/website/website_metrics.py +10 -2
  27. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.0.dist-info}/WHEEL +0 -0
  28. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.0.dist-info}/entry_points.txt +0 -0
  29. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.0.dist-info}/licenses/LICENSE.md +0 -0
src/event/events_tools.py CHANGED
@@ -25,6 +25,8 @@ except ImportError:
25
25
  logger.error("Failed to import event resources API", exc_info=True)
26
26
  raise
27
27
 
28
+ from mcp.types import ToolAnnotations
29
+
28
30
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
29
31
 
30
32
  logger = logging.getLogger(__name__)
@@ -153,7 +155,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
153
155
 
154
156
  return summary
155
157
 
156
- @register_as_tool
158
+ @register_as_tool(
159
+ title="Get Event",
160
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
161
+ )
157
162
  @with_header_auth(EventsApi)
158
163
  async def get_event(self, event_id: str, ctx=None, api_client=None) -> Dict[str, Any]:
159
164
  """
@@ -238,7 +243,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
238
243
  logger.error(f"Error in get_event: {e}", exc_info=True)
239
244
  return {"error": f"Failed to get event: {e!s}", "event_id": event_id}
240
245
 
241
- @register_as_tool
246
+ @register_as_tool(
247
+ title="Get Kubernetes Info Events",
248
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
249
+ )
242
250
  @with_header_auth(EventsApi)
243
251
  async def get_kubernetes_info_events(self,
244
252
  from_time: Optional[int] = None,
@@ -383,7 +391,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
383
391
  "details": str(e)
384
392
  }
385
393
 
386
- @register_as_tool
394
+ @register_as_tool(
395
+ title="Get Agent Monitoring Events",
396
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
397
+ )
387
398
  @with_header_auth(EventsApi)
388
399
  async def get_agent_monitoring_events(self,
389
400
  query: Optional[str] = None,
@@ -525,7 +536,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
525
536
  }
526
537
 
527
538
 
528
- @register_as_tool
539
+ @register_as_tool(
540
+ title="Get Issues",
541
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
542
+ )
529
543
  @with_header_auth(EventsApi)
530
544
  async def get_issues(self,
531
545
  query: Optional[str] = None,
@@ -593,7 +607,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
593
607
  logger.error(f"Error in get_issue_events: {e}", exc_info=True)
594
608
  return {"error": f"Failed to get issue events: {e!s}"}
595
609
 
596
- @register_as_tool
610
+ @register_as_tool(
611
+ title="Get Incidents",
612
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
613
+ )
597
614
  @with_header_auth(EventsApi)
598
615
  async def get_incidents(self,
599
616
  query: Optional[str] = None,
@@ -661,7 +678,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
661
678
  logger.error(f"Error in get_incident_events: {e}", exc_info=True)
662
679
  return {"error": f"Failed to get incident events: {e!s}"}
663
680
 
664
- @register_as_tool
681
+ @register_as_tool(
682
+ title="Get Changes",
683
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
684
+ )
665
685
  @with_header_auth(EventsApi)
666
686
  async def get_changes(self,
667
687
  query: Optional[str] = None,
@@ -729,7 +749,10 @@ class AgentMonitoringEventsMCPTools(BaseInstanaClient):
729
749
  logger.error(f"Error in get_change_events: {e}", exc_info=True)
730
750
  return {"error": f"Failed to get change events: {e!s}"}
731
751
 
732
- @register_as_tool
752
+ @register_as_tool(
753
+ title="Get Events By IDs",
754
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
755
+ )
733
756
  @with_header_auth(EventsApi)
734
757
  async def get_events_by_ids(
735
758
  self,
@@ -33,6 +33,8 @@ except ImportError as e:
33
33
  logger.error(f"Error importing Instana SDK: {e}", exc_info=True)
34
34
  raise
35
35
 
36
+ from mcp.types import ToolAnnotations
37
+
36
38
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
37
39
 
38
40
  # Configure logger for this module
@@ -50,7 +52,10 @@ class InfrastructureAnalyzeMCPTools(BaseInstanaClient):
50
52
  """Initialize the Infrastructure Analyze MCP tools client."""
51
53
  super().__init__(read_token=read_token, base_url=base_url)
52
54
 
53
- @register_as_tool
55
+ @register_as_tool(
56
+ title="Get Available Metrics",
57
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
58
+ )
54
59
  @with_header_auth(InfrastructureAnalyzeApi)
55
60
  async def get_available_metrics(self,
56
61
  payload: Optional[Union[Dict[str, Any], str]] = None,
@@ -186,7 +191,10 @@ class InfrastructureAnalyzeMCPTools(BaseInstanaClient):
186
191
  logger.error(f"Error in get_available_metrics: {e}", exc_info=True)
187
192
  return {"error": f"Failed to get available metrics: {e!s}"}
188
193
 
189
- @register_as_tool
194
+ @register_as_tool(
195
+ title="Get Entities",
196
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
197
+ )
190
198
  @with_header_auth(InfrastructureAnalyzeApi)
191
199
  async def get_entities(self,
192
200
  payload: Optional[Union[Dict[str, Any], str]] = None,
@@ -301,7 +309,10 @@ class InfrastructureAnalyzeMCPTools(BaseInstanaClient):
301
309
  logger.error(f"Error in get_entities: {e}", exc_info=True)
302
310
  return {"error": f"Failed to get entities: {e!s}"}
303
311
 
304
- @register_as_tool
312
+ @register_as_tool(
313
+ title="Get Aggregated Entity Groups",
314
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
315
+ )
305
316
  @with_header_auth(InfrastructureAnalyzeApi)
306
317
  async def get_aggregated_entity_groups(self,
307
318
  payload: Optional[Union[Dict[str, Any], str]] = None,
@@ -502,7 +513,10 @@ class InfrastructureAnalyzeMCPTools(BaseInstanaClient):
502
513
  "error": f"Failed to summarize results: {e!s}"
503
514
  }
504
515
 
505
- @register_as_tool
516
+ @register_as_tool(
517
+ title="Get Available Plugins",
518
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
519
+ )
506
520
  @with_header_auth(InfrastructureAnalyzeApi)
507
521
  async def get_available_plugins(self,
508
522
  payload: Optional[Union[Dict[str, Any], str]] = None,
@@ -20,6 +20,8 @@ except ImportError as e:
20
20
  logger.error(f"Error importing Instana SDK: {e}", exc_info=True)
21
21
  raise
22
22
 
23
+ from mcp.types import ToolAnnotations
24
+
23
25
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
24
26
 
25
27
  # Configure logger for this module
@@ -32,7 +34,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
32
34
  """Initialize the Infrastructure Catalog MCP tools client."""
33
35
  super().__init__(read_token=read_token, base_url=base_url)
34
36
 
35
- @register_as_tool
37
+ @register_as_tool(
38
+ title="Get Available Payload Keys By Plugin ID",
39
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
40
+ )
36
41
  @with_header_auth(InfrastructureCatalogApi)
37
42
  async def get_available_payload_keys_by_plugin_id(self,
38
43
  plugin_id: str,
@@ -123,7 +128,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
123
128
  return {"error": f"Failed to get payload keys: {e!s}", "plugin_id": plugin_id}
124
129
 
125
130
 
126
- @register_as_tool
131
+ @register_as_tool(
132
+ title="Get Infrastructure Catalog Metrics",
133
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
134
+ )
127
135
  @with_header_auth(InfrastructureCatalogApi)
128
136
  async def get_infrastructure_catalog_metrics(self,
129
137
  plugin: str,
@@ -160,10 +168,22 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
160
168
 
161
169
  # Handle different response types
162
170
  if isinstance(result, list):
163
- # If it's a list of metric names, limit to first 50
164
- limited_metrics = result[:50]
165
- logger.debug(f"Received {len(result)} metrics for plugin {plugin}, returning first {len(limited_metrics)}")
166
- return limited_metrics
171
+ # If it's a list of metric objects or names, extract metric names
172
+ metric_names = []
173
+ for item in result[:50]: # Limit to first 50
174
+ if isinstance(item, str):
175
+ # Already a string (metric name)
176
+ metric_names.append(item)
177
+ elif isinstance(item, dict):
178
+ # Extract metric name from metric object
179
+ metric_name = item.get('metricId') or item.get('label') or str(item)
180
+ metric_names.append(metric_name)
181
+ else:
182
+ # Convert to string
183
+ metric_names.append(str(item))
184
+
185
+ logger.debug(f"Received {len(result)} metrics for plugin {plugin}, returning first {len(metric_names)}")
186
+ return metric_names
167
187
 
168
188
  elif hasattr(result, 'to_dict'):
169
189
  # If it's an SDK object with to_dict method
@@ -171,14 +191,35 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
171
191
 
172
192
  # Check if the dict contains a list of metrics
173
193
  if isinstance(result_dict, list):
174
- limited_metrics = result_dict[:50]
175
- logger.debug(f"Received {len(result_dict)} metrics for plugin {plugin}, returning first {len(limited_metrics)}")
176
- return limited_metrics
194
+ metric_names = []
195
+ for item in result_dict[:50]: # Limit to first 50
196
+ if isinstance(item, str):
197
+ metric_names.append(item)
198
+ elif isinstance(item, dict):
199
+ metric_name = item.get('metricId') or item.get('label') or str(item)
200
+ metric_names.append(metric_name)
201
+ else:
202
+ metric_names.append(str(item))
203
+
204
+ logger.debug(f"Received {len(result_dict)} metrics for plugin {plugin}, returning first {len(metric_names)}")
205
+ return metric_names
177
206
  elif isinstance(result_dict, dict):
178
207
  # Try to extract metric names from dict structure
179
208
  if 'metrics' in result_dict:
180
- metrics = result_dict['metrics'][:50] if isinstance(result_dict['metrics'], list) else []
181
- return metrics
209
+ metrics_list = result_dict['metrics']
210
+ if isinstance(metrics_list, list):
211
+ metric_names = []
212
+ for item in metrics_list[:50]: # Limit to first 50
213
+ if isinstance(item, str):
214
+ metric_names.append(item)
215
+ elif isinstance(item, dict):
216
+ metric_name = item.get('metricId') or item.get('label') or str(item)
217
+ metric_names.append(metric_name)
218
+ else:
219
+ metric_names.append(str(item))
220
+ return metric_names
221
+ else:
222
+ return [f"Metrics field is not a list for plugin {plugin}"]
182
223
  else:
183
224
  return [f"Unexpected dict structure for plugin {plugin}"]
184
225
  else:
@@ -193,7 +234,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
193
234
  return [f"Error: Failed to get metric catalog for plugin '{plugin}': {e!s}"]
194
235
 
195
236
 
196
- @register_as_tool
237
+ @register_as_tool(
238
+ title="Get Infrastructure Catalog Plugins",
239
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
240
+ )
197
241
  @with_header_auth(InfrastructureCatalogApi)
198
242
  async def get_infrastructure_catalog_plugins(self, ctx=None, api_client=None) -> Dict[str, Any]:
199
243
  """
@@ -263,7 +307,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
263
307
 
264
308
 
265
309
 
266
- @register_as_tool
310
+ @register_as_tool(
311
+ title="Get Infrastructure Catalog Plugins With Custom Metrics",
312
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
313
+ )
267
314
  @with_header_auth(InfrastructureCatalogApi)
268
315
  async def get_infrastructure_catalog_plugins_with_custom_metrics(self, ctx=None, api_client=None) -> Dict[str, Any] | List[Dict[str, Any]]:
269
316
  """
@@ -303,7 +350,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
303
350
  return {"error": f"Failed to get plugins with custom metrics: {e!s}"}
304
351
 
305
352
 
306
- @register_as_tool
353
+ @register_as_tool(
354
+ title="Get Tag Catalog",
355
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
356
+ )
307
357
  @with_header_auth(InfrastructureCatalogApi)
308
358
  async def get_tag_catalog(self, plugin: str, ctx=None, api_client=None) -> Dict[str, Any]:
309
359
  """
@@ -388,7 +438,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
388
438
  return {"error": f"Failed to get tag catalog: {e!s}"}
389
439
 
390
440
 
391
- @register_as_tool
441
+ @register_as_tool(
442
+ title="Get Tag Catalog All",
443
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
444
+ )
392
445
  @with_header_auth(InfrastructureCatalogApi)
393
446
  async def get_tag_catalog_all(self, ctx=None, api_client=None) -> Dict[str, Any]:
394
447
  """
@@ -507,7 +560,10 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
507
560
  return summary
508
561
 
509
562
 
510
- @register_as_tool
563
+ @register_as_tool(
564
+ title="Get Infrastructure Catalog Search Fields",
565
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
566
+ )
511
567
  @with_header_auth(InfrastructureCatalogApi)
512
568
  async def get_infrastructure_catalog_search_fields(self, ctx=None, api_client=None) -> List[str] | Dict[str, Any]:
513
569
  """
@@ -9,6 +9,7 @@ import logging
9
9
  from datetime import datetime
10
10
  from typing import Any, Dict, List, Optional, Union
11
11
 
12
+ from mcp.types import ToolAnnotations
12
13
  from pydantic import StrictBool
13
14
 
14
15
  from src.core.utils import (
@@ -40,7 +41,10 @@ class InfrastructureMetricsMCPTools(BaseInstanaClient):
40
41
  """Initialize the Infrastructure Analyze MCP tools client."""
41
42
  super().__init__(read_token=read_token, base_url=base_url)
42
43
 
43
- @register_as_tool
44
+ @register_as_tool(
45
+ title="Get Infrastructure Metrics",
46
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
47
+ )
44
48
  @with_header_auth(InfrastructureMetricsApi)
45
49
  async def get_infrastructure_metrics(self,
46
50
  offline: Optional[StrictBool] = False,
@@ -25,6 +25,8 @@ except ImportError:
25
25
  logger.error("Failed to import infrastructure resources API", exc_info=True)
26
26
  raise
27
27
 
28
+ from mcp.types import ToolAnnotations
29
+
28
30
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
29
31
 
30
32
  # Configure logger for this module
@@ -37,7 +39,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
37
39
  """Initialize the Infrastructure Resources MCP tools client."""
38
40
  super().__init__(read_token=read_token, base_url=base_url)
39
41
 
40
- @register_as_tool
42
+ @register_as_tool(
43
+ title="Get Monitoring State",
44
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
45
+ )
41
46
  @with_header_auth(InfrastructureResourcesApi)
42
47
  async def get_monitoring_state(self, ctx=None, api_client=None) -> Dict[str, Any]:
43
48
  """
@@ -63,7 +68,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
63
68
  logger.error(f"Error in get_monitoring_state: {e}", exc_info=True)
64
69
  return {"error": f"Failed to get monitoring state: {e!s}"}
65
70
 
66
- @register_as_tool
71
+ @register_as_tool(
72
+ title="Get Plugin Payload",
73
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
74
+ )
67
75
  @with_header_auth(InfrastructureResourcesApi)
68
76
  async def get_plugin_payload(self,
69
77
  snapshot_id: str,
@@ -104,7 +112,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
104
112
  logger.error(f"Error in get_plugin_payload: {e}", exc_info=True)
105
113
  return {"error": f"Failed to get plugin payload: {e!s}"}
106
114
 
107
- @register_as_tool
115
+ @register_as_tool(
116
+ title="Get Snapshot",
117
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
118
+ )
108
119
  @with_header_auth(InfrastructureResourcesApi)
109
120
  async def get_snapshot(self,
110
121
  snapshot_id: str,
@@ -212,7 +223,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
212
223
  logger.error(f"Error in get_snapshot: {e}", exc_info=True)
213
224
  return {"error": f"Failed to get snapshot: {e!s}"}
214
225
 
215
- @register_as_tool
226
+ @register_as_tool(
227
+ title="Get Snapshots",
228
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
229
+ )
216
230
  @with_header_auth(InfrastructureResourcesApi)
217
231
  async def get_snapshots(self,
218
232
  query: Optional[str] = None,
@@ -367,7 +381,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
367
381
 
368
382
 
369
383
 
370
- @register_as_tool
384
+ @register_as_tool(
385
+ title="Post Snapshots",
386
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
387
+ )
371
388
  @with_header_auth(InfrastructureResourcesApi)
372
389
  async def post_snapshots(self,
373
390
  snapshot_ids: Union[List[str], str],
@@ -414,13 +431,12 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
414
431
  from instana_client.models.get_snapshots_query import (
415
432
  GetSnapshotsQuery, #type: ignore
416
433
  )
434
+ from instana_client.models.time_frame import TimeFrame #type: ignore
417
435
 
436
+ time_frame = TimeFrame(to=to_time, windowSize=window_size)
418
437
  query_obj = GetSnapshotsQuery(
419
- snapshot_ids=snapshot_ids,
420
- time_frame={
421
- "to": to_time,
422
- "windowSize": window_size
423
- }
438
+ snapshotIds=snapshot_ids if isinstance(snapshot_ids, list) else [snapshot_ids],
439
+ timeFrame=time_frame
424
440
  )
425
441
 
426
442
  logger.debug("Making SDK request with without_preload_content...")
@@ -546,7 +562,10 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
546
562
 
547
563
 
548
564
 
549
- @register_as_tool
565
+ @register_as_tool(
566
+ title="Software Versions",
567
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
568
+ )
550
569
  @with_header_auth(InfrastructureResourcesApi)
551
570
  async def software_versions(self, ctx=None, api_client=None) -> Dict[str, Any]:
552
571
  """
@@ -22,6 +22,8 @@ except ImportError:
22
22
  logger.error("Failed to import infrastructure topology API", exc_info=True)
23
23
  raise
24
24
 
25
+ from mcp.types import ToolAnnotations
26
+
25
27
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
26
28
 
27
29
  # Configure logger for this module
@@ -49,7 +51,10 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
49
51
  """Initialize the Infrastructure Topology MCP tools client."""
50
52
  super().__init__(read_token=read_token, base_url=base_url)
51
53
 
52
- @register_as_tool
54
+ @register_as_tool(
55
+ title="Get Related Hosts",
56
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
57
+ )
53
58
  @with_header_auth(InfrastructureTopologyApi)
54
59
  async def get_related_hosts(self,
55
60
  snapshot_id: str,
@@ -110,7 +115,10 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
110
115
  logger.error(f"Error in get_related_hosts: {e}", exc_info=True)
111
116
  return {"error": f"Failed to get related hosts: {e!s}"}
112
117
 
113
- @register_as_tool
118
+ @register_as_tool(
119
+ title="Get Topology",
120
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
121
+ )
114
122
  @with_header_auth(InfrastructureTopologyApi)
115
123
  async def get_topology(self,
116
124
  include_data: Optional[bool] = False,