mcp-instana 0.1.0__py3-none-any.whl → 0.2.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 (67) hide show
  1. mcp_instana-0.2.0.dist-info/METADATA +1229 -0
  2. mcp_instana-0.2.0.dist-info/RECORD +59 -0
  3. {mcp_instana-0.1.0.dist-info → mcp_instana-0.2.0.dist-info}/WHEEL +1 -1
  4. mcp_instana-0.2.0.dist-info/entry_points.txt +4 -0
  5. mcp_instana-0.1.0.dist-info/LICENSE → mcp_instana-0.2.0.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 +628 -0
  9. src/application/application_catalog.py +155 -0
  10. src/application/application_global_alert_config.py +653 -0
  11. src/{client/application_metrics_mcp_tools.py → application/application_metrics.py} +113 -131
  12. src/{client/application_resources_mcp_tools.py → application/application_resources.py} +131 -151
  13. src/application/application_settings.py +1731 -0
  14. src/application/application_topology.py +111 -0
  15. src/automation/action_catalog.py +416 -0
  16. src/automation/action_history.py +338 -0
  17. src/core/__init__.py +1 -0
  18. src/core/server.py +586 -0
  19. src/core/utils.py +213 -0
  20. src/event/__init__.py +1 -0
  21. src/event/events_tools.py +850 -0
  22. src/infrastructure/__init__.py +1 -0
  23. src/{client/infrastructure_analyze_mcp_tools.py → infrastructure/infrastructure_analyze.py} +207 -206
  24. src/{client/infrastructure_catalog_mcp_tools.py → infrastructure/infrastructure_catalog.py} +197 -265
  25. src/infrastructure/infrastructure_metrics.py +171 -0
  26. src/{client/infrastructure_resources_mcp_tools.py → infrastructure/infrastructure_resources.py} +198 -227
  27. src/{client/infrastructure_topology_mcp_tools.py → infrastructure/infrastructure_topology.py} +110 -109
  28. src/log/__init__.py +1 -0
  29. src/log/log_alert_configuration.py +331 -0
  30. src/prompts/__init__.py +16 -0
  31. src/prompts/application/__init__.py +1 -0
  32. src/prompts/application/application_alerts.py +54 -0
  33. src/prompts/application/application_catalog.py +26 -0
  34. src/prompts/application/application_metrics.py +57 -0
  35. src/prompts/application/application_resources.py +26 -0
  36. src/prompts/application/application_settings.py +75 -0
  37. src/prompts/application/application_topology.py +30 -0
  38. src/prompts/events/__init__.py +1 -0
  39. src/prompts/events/events_tools.py +161 -0
  40. src/prompts/infrastructure/infrastructure_analyze.py +72 -0
  41. src/prompts/infrastructure/infrastructure_catalog.py +53 -0
  42. src/prompts/infrastructure/infrastructure_metrics.py +45 -0
  43. src/prompts/infrastructure/infrastructure_resources.py +74 -0
  44. src/prompts/infrastructure/infrastructure_topology.py +38 -0
  45. src/prompts/settings/__init__.py +0 -0
  46. src/prompts/settings/custom_dashboard.py +157 -0
  47. src/prompts/website/__init__.py +1 -0
  48. src/prompts/website/website_analyze.py +35 -0
  49. src/prompts/website/website_catalog.py +40 -0
  50. src/prompts/website/website_configuration.py +105 -0
  51. src/prompts/website/website_metrics.py +34 -0
  52. src/settings/__init__.py +1 -0
  53. src/settings/custom_dashboard_tools.py +417 -0
  54. src/website/__init__.py +0 -0
  55. src/website/website_analyze.py +433 -0
  56. src/website/website_catalog.py +171 -0
  57. src/website/website_configuration.py +770 -0
  58. src/website/website_metrics.py +241 -0
  59. mcp_instana-0.1.0.dist-info/METADATA +0 -649
  60. mcp_instana-0.1.0.dist-info/RECORD +0 -19
  61. mcp_instana-0.1.0.dist-info/entry_points.txt +0 -3
  62. src/client/What is the sum of queue depth for all q +0 -55
  63. src/client/events_mcp_tools.py +0 -531
  64. src/client/instana_client_base.py +0 -93
  65. src/client/log_alert_configuration_mcp_tools.py +0 -316
  66. src/client/show the top 5 services with the highest +0 -28
  67. src/mcp_server.py +0 -343
@@ -4,93 +4,94 @@ Infrastructure Topology MCP Tools Module
4
4
  This module provides infrastructure topology-specific MCP tools for Instana monitoring.
5
5
  """
6
6
 
7
+ import logging
7
8
  import sys
8
- import traceback
9
- from typing import Dict, Any, Optional, List, Union
10
- from datetime import datetime
9
+ from typing import Any, Dict, Optional
11
10
 
12
11
  # Import the necessary classes from the SDK
13
12
  try:
14
- from instana_client.api.infrastructure_topology_api import InfrastructureTopologyApi
15
- from instana_client.api_client import ApiClient
16
- from instana_client.configuration import Configuration
17
- from instana_client.models.topology import Topology
18
- except ImportError as e:
19
- traceback.print_exc(file=sys.stderr)
13
+ from instana_client.api.infrastructure_topology_api import (
14
+ InfrastructureTopologyApi, #type: ignore
15
+ )
16
+ from instana_client.api_client import ApiClient #type: ignore
17
+ from instana_client.configuration import Configuration #type: ignore
18
+
19
+ except ImportError:
20
+ import logging
21
+ logger = logging.getLogger(__name__)
22
+ logger.error("Failed to import infrastructure topology API", exc_info=True)
20
23
  raise
21
24
 
22
- from .instana_client_base import BaseInstanaClient, register_as_tool
25
+ from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
26
+
27
+ # Configure logger for this module
28
+ logger = logging.getLogger(__name__)
23
29
 
24
- # Helper function for debug printing
25
30
  def debug_print(*args, **kwargs):
26
- """Print debug information to stderr instead of stdout"""
27
- print(*args, file=sys.stderr, **kwargs)
31
+ """
32
+ Print debug information to stderr.
33
+
34
+ This function is used for debugging purposes and prints information to stderr.
35
+ It accepts the same arguments as the built-in print function.
36
+
37
+ Args:
38
+ *args: Variable length argument list to print
39
+ **kwargs: Arbitrary keyword arguments to pass to print function
40
+ """
41
+ # Use logger.debug instead of direct printing
42
+ message = " ".join(str(arg) for arg in args)
43
+ logger.debug(message)
28
44
 
29
45
  class InfrastructureTopologyMCPTools(BaseInstanaClient):
30
46
  """Tools for infrastructure topology in Instana MCP."""
31
-
47
+
32
48
  def __init__(self, read_token: str, base_url: str):
33
49
  """Initialize the Infrastructure Topology MCP tools client."""
34
50
  super().__init__(read_token=read_token, base_url=base_url)
35
-
36
- try:
37
-
38
- # Configure the API client with the correct base URL and authentication
39
- configuration = Configuration()
40
- configuration.host = base_url
41
- configuration.api_key['ApiKeyAuth'] = read_token
42
- configuration.api_key_prefix['ApiKeyAuth'] = 'apiToken'
43
-
44
- # Create an API client with this configuration
45
- api_client = ApiClient(configuration=configuration)
46
-
47
- # Initialize the Instana SDK's InfrastructureTopologyApi with our configured client
48
- self.topo_api = InfrastructureTopologyApi(api_client=api_client)
49
- except Exception as e:
50
- debug_print(f"Error initializing InfrastructureTopologyApi: {e}")
51
- traceback.print_exc(file=sys.stderr)
52
- raise
53
-
51
+
54
52
  @register_as_tool
55
- async def get_related_hosts(self,
56
- snapshot_id: str,
57
- to_time: Optional[int] = None,
58
- window_size: Optional[int] = None,
59
- ctx=None) -> Dict[str, Any]:
53
+ @with_header_auth(InfrastructureTopologyApi)
54
+ async def get_related_hosts(self,
55
+ snapshot_id: str,
56
+ to_time: Optional[int] = None,
57
+ window_size: Optional[int] = None,
58
+ ctx=None,
59
+ api_client=None) -> Dict[str, Any]:
60
60
  """
61
61
  Get hosts related to a specific snapshot.
62
-
63
- This tool retrieves a list of host IDs that are related to the specified snapshot. Use this when you need to
64
- understand the relationships between infrastructure components, particularly which hosts are connected to
62
+
63
+ This tool retrieves a list of host IDs that are related to the specified snapshot. Use this when you need to
64
+ understand the relationships between infrastructure components, particularly which hosts are connected to
65
65
  a specific entity.
66
-
66
+
67
67
  For example, use this tool when:
68
68
  - You need to find all hosts connected to a specific container, process, or service
69
69
  - You want to understand the infrastructure dependencies of an application component
70
70
  - You're investigating an issue and need to see which hosts might be affected
71
-
71
+
72
72
  Args:
73
73
  snapshot_id: The ID of the snapshot to find related hosts for (required)
74
74
  to_time: End timestamp in milliseconds (optional)
75
75
  window_size: Window size in milliseconds (optional)
76
76
  ctx: The MCP context (optional)
77
-
77
+ api_client: API client for testing (optional)
78
+
78
79
  Returns:
79
80
  Dictionary containing related hosts information or error information
80
81
  """
81
82
  try:
82
- debug_print(f"get_related_hosts called with snapshot_id={snapshot_id}")
83
-
83
+ logger.debug(f"get_related_hosts called with snapshot_id={snapshot_id}")
84
+
84
85
  if not snapshot_id:
85
86
  return {"error": "snapshot_id parameter is required"}
86
-
87
+
87
88
  # Call the get_related_hosts method from the SDK
88
- result = self.topo_api.get_related_hosts(
89
+ result = api_client.get_related_hosts(
89
90
  snapshot_id=snapshot_id,
90
91
  to=to_time,
91
92
  window_size=window_size
92
93
  )
93
-
94
+
94
95
  # Convert the result to a dictionary
95
96
  if isinstance(result, list):
96
97
  result_dict = {
@@ -101,52 +102,53 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
101
102
  else:
102
103
  # For any other type, convert to string representation
103
104
  result_dict = {"data": str(result), "snapshotId": snapshot_id}
104
-
105
- debug_print(f"Result from get_related_hosts: {result_dict}")
105
+
106
+ logger.debug(f"Result from get_related_hosts: {result_dict}")
106
107
  return result_dict
107
-
108
+
108
109
  except Exception as e:
109
- debug_print(f"Error in get_related_hosts: {e}")
110
- import traceback
111
- traceback.print_exc(file=sys.stderr)
112
- return {"error": f"Failed to get related hosts: {str(e)}"}
110
+ logger.error(f"Error in get_related_hosts: {e}", exc_info=True)
111
+ return {"error": f"Failed to get related hosts: {e!s}"}
113
112
 
114
113
  @register_as_tool
115
- async def get_topology(self,
116
- include_data: Optional[bool] = False,
117
- ctx=None) -> Dict[str, Any]:
114
+ @with_header_auth(InfrastructureTopologyApi)
115
+ async def get_topology(self,
116
+ include_data: Optional[bool] = False,
117
+ ctx=None,
118
+ api_client=None) -> Dict[str, Any]:
118
119
  """
119
120
  Get the infrastructure topology information.
120
-
121
- This tool retrieves the complete infrastructure topology from Instana, showing how all monitored entities
121
+
122
+ This tool retrieves the complete infrastructure topology from Instana, showing how all monitored entities
122
123
  are connected. Use this when you need a comprehensive view of your infrastructure's relationships and dependencies.
123
-
124
- The topology includes nodes (representing entities like hosts, processes, containers) and edges (representing
124
+
125
+ The topology includes nodes (representing entities like hosts, processes, containers) and edges (representing
125
126
  connections between entities). This is useful for understanding the overall structure of your environment.
126
-
127
+
127
128
  For example, use this tool when:
128
129
  - You need a complete map of your infrastructure
129
130
  - You want to understand how components are connected
130
131
  - You're analyzing dependencies between systems
131
132
  - You need to visualize your infrastructure's architecture
132
-
133
+
133
134
  Args:
134
135
  include_data: Whether to include detailed snapshot data in nodes (optional, default: False)
135
136
  ctx: The MCP context (optional)
136
-
137
+ api_client: API client for testing (optional)
138
+
137
139
  Returns:
138
140
  Dictionary containing infrastructure topology information with detailed summary or error information
139
141
  """
140
142
  try:
141
- debug_print(f"get_topology called - using include_data=False to avoid validation issues")
142
-
143
- # Try to call the SDK method and handle validation errors
143
+ logger.debug(f"get_topology called - using include_data={include_data}")
144
+
145
+ # Use the API client from the decorator
144
146
  try:
145
- result = self.topo_api.get_topology(include_data=False)
146
- debug_print(f"SDK call successful, processing result")
147
+ result = api_client.get_topology(include_data=include_data)
148
+ logger.debug("SDK call successful, processing result")
147
149
  except Exception as sdk_error:
148
- debug_print(f"SDK validation error: {sdk_error}")
149
-
150
+ logger.error(f"SDK validation error: {sdk_error}")
151
+
150
152
  # If it's a validation error, try to extract useful information from the error
151
153
  if "validation error" in str(sdk_error).lower():
152
154
  return {
@@ -158,45 +160,45 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
158
160
  else:
159
161
  # Re-raise if it's not a validation error
160
162
  raise sdk_error
161
-
163
+
162
164
  # Convert the result to a dictionary
163
165
  result_dict = None
164
-
166
+
165
167
  # Try different ways to convert the result
166
168
  if hasattr(result, 'to_dict'):
167
169
  try:
168
170
  result_dict = result.to_dict()
169
- debug_print("Successfully converted result using to_dict()")
171
+ logger.debug("Successfully converted result using to_dict()")
170
172
  except Exception as e:
171
- debug_print(f"to_dict() failed: {e}")
172
-
173
+ logger.error(f"to_dict() failed: {e}")
174
+
173
175
  if result_dict is None and isinstance(result, dict):
174
176
  result_dict = result
175
- debug_print("Result is already a dictionary")
176
-
177
+ logger.debug("Result is already a dictionary")
178
+
177
179
  if result_dict is None:
178
180
  # Try to extract data from the result object manually
179
181
  try:
180
182
  if hasattr(result, '__dict__'):
181
183
  result_dict = result.__dict__
182
- debug_print("Extracted data using __dict__")
184
+ logger.debug("Extracted data using __dict__")
183
185
  else:
184
186
  result_dict = {"data": str(result)}
185
- debug_print("Converted result to string representation")
187
+ logger.debug("Converted result to string representation")
186
188
  except Exception as e:
187
- debug_print(f"Manual extraction failed: {e}")
189
+ logger.error(f"Manual extraction failed: {e}")
188
190
  result_dict = {"data": str(result)}
189
-
191
+
190
192
  # Process the result if we have valid data
191
193
  if isinstance(result_dict, dict) and ('nodes' in result_dict or 'data' in result_dict):
192
194
  nodes = result_dict.get('nodes', [])
193
195
  edges = result_dict.get('edges', [])
194
-
195
- debug_print(f"Processing {len(nodes)} nodes and {len(edges)} edges")
196
-
196
+
197
+ logger.debug(f"Processing {len(nodes)} nodes and {len(edges)} edges")
198
+
197
199
  # If we have no nodes but have data, try to extract from data field
198
200
  if not nodes and 'data' in result_dict:
199
- debug_print("No nodes found, checking data field")
201
+ logger.debug("No nodes found, checking data field")
200
202
  return {
201
203
  "summary": {
202
204
  "status": "Data retrieved but in unexpected format",
@@ -206,60 +208,60 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
206
208
  "rawDataAvailable": True,
207
209
  "note": "Topology data was retrieved but not in the expected nodes/edges format"
208
210
  }
209
-
211
+
210
212
  # Take only first 30 nodes for analysis to avoid token limits
211
213
  sample_nodes = nodes[:30] if len(nodes) > 30 else nodes
212
214
  sample_edges = edges[:30] if len(edges) > 30 else edges
213
-
215
+
214
216
  # Count nodes by plugin type from sample
215
217
  plugin_counts = {}
216
218
  host_info = {}
217
219
  kubernetes_resources = {}
218
220
  sample_nodes_details = []
219
-
221
+
220
222
  for node in sample_nodes:
221
223
  if not isinstance(node, dict):
222
224
  continue
223
-
225
+
224
226
  plugin = node.get('plugin', 'unknown')
225
227
  plugin_counts[plugin] = plugin_counts.get(plugin, 0) + 1
226
-
228
+
227
229
  # Keep minimal node info for sample
228
230
  node_label = str(node.get('label', 'unknown'))
229
231
  if len(node_label) > 40:
230
232
  node_label = node_label[:37] + "..."
231
-
233
+
232
234
  node_id = str(node.get('id', ''))
233
235
  if len(node_id) > 15:
234
236
  node_id = node_id[:12] + "..."
235
-
237
+
236
238
  sample_nodes_details.append({
237
239
  'plugin': plugin,
238
240
  'label': node_label,
239
241
  'id': node_id
240
242
  })
241
-
243
+
242
244
  # Extract host information
243
245
  if plugin == 'host':
244
246
  label = str(node.get('label', 'unknown'))
245
247
  host_info[label] = str(node.get('id', ''))
246
-
248
+
247
249
  # Group Kubernetes resources
248
250
  if plugin.startswith('kubernetes'):
249
251
  k8s_type = plugin.replace('kubernetes', '').lower()
250
252
  if k8s_type not in kubernetes_resources:
251
253
  kubernetes_resources[k8s_type] = 0
252
254
  kubernetes_resources[k8s_type] += 1
253
-
255
+
254
256
  # Estimate total counts based on sample
255
257
  sample_size = len(sample_nodes)
256
258
  total_size = len(nodes)
257
259
  scaling_factor = total_size / sample_size if sample_size > 0 else 1
258
-
260
+
259
261
  estimated_plugin_counts = {}
260
262
  for plugin, count in plugin_counts.items():
261
263
  estimated_plugin_counts[plugin] = int(count * scaling_factor)
262
-
264
+
263
265
  # Create comprehensive summary
264
266
  summary = {
265
267
  'totalNodes': len(nodes),
@@ -269,7 +271,7 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
269
271
  'scalingFactor': round(scaling_factor, 2),
270
272
  'note': f'Analysis based on first {sample_size} nodes out of {total_size} total'
271
273
  },
272
- 'topPluginTypes': dict(list(sorted(estimated_plugin_counts.items(), key=lambda x: x[1], reverse=True))[:10]),
274
+ 'topPluginTypes': dict(sorted(estimated_plugin_counts.items(), key=lambda x: x[1], reverse=True)[:10]),
273
275
  'infrastructureOverview': {
274
276
  'estimatedHosts': int(len(host_info) * scaling_factor),
275
277
  'sampleHosts': list(host_info.keys())[:3], # Show first 3 hosts
@@ -278,7 +280,7 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
278
280
  'estimatedProcesses': int(plugin_counts.get('process', 0) * scaling_factor)
279
281
  }
280
282
  }
281
-
283
+
282
284
  # Add edge analysis from sample if available
283
285
  if sample_edges:
284
286
  edge_types = {}
@@ -286,13 +288,13 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
286
288
  if isinstance(edge, dict):
287
289
  edge_type = edge.get('type', 'unknown')
288
290
  edge_types[edge_type] = edge_types.get(edge_type, 0) + 1
289
-
291
+
290
292
  if edge_types:
291
293
  summary['connectionAnalysis'] = {
292
294
  'sampleEdgeTypes': edge_types,
293
295
  'sampleEdgesAnalyzed': len(sample_edges)
294
296
  }
295
-
297
+
296
298
  # Return compact summary
297
299
  return {
298
300
  'summary': summary,
@@ -307,13 +309,12 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
307
309
  "availableKeys": list(result_dict.keys()) if isinstance(result_dict, dict) else "Not a dictionary",
308
310
  "suggestion": "The topology data may be in a different format than expected"
309
311
  }
310
-
312
+
311
313
  except Exception as e:
312
- debug_print(f"Error in get_topology: {e}")
313
- import traceback
314
- traceback.print_exc(file=sys.stderr)
314
+ logger.error(f"Error in get_topology: {e}", exc_info=True)
315
315
  return {
316
- "error": f"Failed to get topology: {str(e)}",
316
+ "error": f"Failed to get topology: {e!s}",
317
317
  "errorType": type(e).__name__,
318
318
  "suggestion": "This may be due to API response format changes or network issues"
319
319
  }
320
+
src/log/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # Log module for MCP Instana