mcp-instana 0.6.2__py3-none-any.whl → 0.7.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 (28) hide show
  1. {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/METADATA +179 -120
  2. {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/RECORD +28 -21
  3. src/application/application_alert_config.py +397 -146
  4. src/application/application_analyze.py +597 -597
  5. src/application/application_call_group.py +528 -0
  6. src/application/application_catalog.py +0 -8
  7. src/application/application_global_alert_config.py +255 -38
  8. src/application/application_metrics.py +377 -237
  9. src/application/application_resources.py +414 -365
  10. src/application/application_settings.py +605 -1651
  11. src/application/application_topology.py +62 -62
  12. src/core/custom_dashboard_smart_router_tool.py +135 -0
  13. src/core/server.py +92 -119
  14. src/core/smart_router_tool.py +574 -0
  15. src/core/utils.py +17 -8
  16. src/custom_dashboard/custom_dashboard_tools.py +422 -0
  17. src/infrastructure/elicitation_handler.py +338 -0
  18. src/infrastructure/entity_registry.py +329 -0
  19. src/infrastructure/infrastructure_analyze_new.py +600 -0
  20. src/infrastructure/{infrastructure_analyze.py → infrastructure_analyze_old.py} +1 -16
  21. src/infrastructure/infrastructure_catalog.py +7 -28
  22. src/infrastructure/infrastructure_metrics.py +93 -17
  23. src/infrastructure/infrastructure_resources.py +5 -20
  24. src/infrastructure/infrastructure_topology.py +2 -8
  25. src/prompts/application/application_settings.py +58 -0
  26. {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/WHEEL +0 -0
  27. {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/entry_points.txt +0 -0
  28. {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/licenses/LICENSE.md +0 -0
@@ -34,10 +34,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
34
34
  """Initialize the Infrastructure Catalog MCP tools client."""
35
35
  super().__init__(read_token=read_token, base_url=base_url)
36
36
 
37
- @register_as_tool(
38
- title="Get Available Payload Keys By Plugin ID",
39
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
40
- )
37
+ # @register_as_tool(...) # Disabled for future reference
41
38
  @with_header_auth(InfrastructureCatalogApi)
42
39
  async def get_available_payload_keys_by_plugin_id(self,
43
40
  plugin_id: str,
@@ -142,10 +139,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
142
139
  return {"error": f"Failed to get payload keys: {e!s}", "plugin_id": plugin_id}
143
140
 
144
141
 
145
- @register_as_tool(
146
- title="Get Infrastructure Catalog Metrics",
147
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
148
- )
142
+ # @register_as_tool(...) # Disabled for future reference
149
143
  @with_header_auth(InfrastructureCatalogApi)
150
144
  async def get_infrastructure_catalog_metrics(self,
151
145
  plugin: str,
@@ -248,10 +242,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
248
242
  return [f"Error: Failed to get metric catalog for plugin '{plugin}': {e!s}"]
249
243
 
250
244
 
251
- @register_as_tool(
252
- title="Get Infrastructure Catalog Plugins",
253
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
254
- )
245
+ # @register_as_tool(...) # Disabled for future reference
255
246
  @with_header_auth(InfrastructureCatalogApi)
256
247
  async def get_infrastructure_catalog_plugins(self, ctx=None, api_client=None) -> Dict[str, Any]:
257
248
  """
@@ -321,10 +312,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
321
312
 
322
313
 
323
314
 
324
- @register_as_tool(
325
- title="Get Infrastructure Catalog Plugins With Custom Metrics",
326
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
327
- )
315
+ # @register_as_tool(...) # Disabled for future reference
328
316
  @with_header_auth(InfrastructureCatalogApi)
329
317
  async def get_infrastructure_catalog_plugins_with_custom_metrics(self, ctx=None, api_client=None) -> Dict[str, Any] | List[Dict[str, Any]]:
330
318
  """
@@ -364,10 +352,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
364
352
  return {"error": f"Failed to get plugins with custom metrics: {e!s}"}
365
353
 
366
354
 
367
- @register_as_tool(
368
- title="Get Tag Catalog",
369
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
370
- )
355
+ # @register_as_tool(...) # Disabled for future reference
371
356
  @with_header_auth(InfrastructureCatalogApi)
372
357
  async def get_tag_catalog(self, plugin: str, ctx=None, api_client=None) -> Dict[str, Any]:
373
358
  """
@@ -464,10 +449,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
464
449
  return {"error": f"Failed to get tag catalog: {e!s}"}
465
450
 
466
451
 
467
- @register_as_tool(
468
- title="Get Tag Catalog All",
469
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
470
- )
452
+ # @register_as_tool(...) # Disabled for future reference
471
453
  @with_header_auth(InfrastructureCatalogApi)
472
454
  async def get_tag_catalog_all(self, ctx=None, api_client=None) -> Dict[str, Any]:
473
455
  """
@@ -586,10 +568,7 @@ class InfrastructureCatalogMCPTools(BaseInstanaClient):
586
568
  return summary
587
569
 
588
570
 
589
- @register_as_tool(
590
- title="Get Infrastructure Catalog Search Fields",
591
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
592
- )
571
+ # @register_as_tool(...) # Disabled for future reference
593
572
  @with_header_auth(InfrastructureCatalogApi)
594
573
  async def get_infrastructure_catalog_search_fields(self, ctx=None, api_client=None) -> List[str] | Dict[str, Any]:
595
574
  """
@@ -41,10 +41,8 @@ class InfrastructureMetricsMCPTools(BaseInstanaClient):
41
41
  """Initialize the Infrastructure Analyze MCP tools client."""
42
42
  super().__init__(read_token=read_token, base_url=base_url)
43
43
 
44
- @register_as_tool(
45
- title="Get Infrastructure Metrics",
46
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
47
- )
44
+ # @register_as_tool(...) # Disabled for future reference
45
+ # Note: Not exposed as direct MCP tool - accessed via smart_router_tool.py
48
46
  @with_header_auth(InfrastructureMetricsApi)
49
47
  async def get_infrastructure_metrics(self,
50
48
  offline: Optional[StrictBool] = False,
@@ -78,18 +76,13 @@ class InfrastructureMetricsMCPTools(BaseInstanaClient):
78
76
 
79
77
  try:
80
78
 
81
- # If no metrics is provided, return an error
82
- if not metrics:
83
- return {"error": "Metrics is required for this operation"}
84
-
85
-
86
- # If no plugin is provided, return an error
87
- if not plugin:
88
- return {"error": "Plugin is required for this operation"}
89
-
90
- # If no query is provided, return an error
91
- if not query:
92
- return {"error": "Query is required for this operation"}
79
+ # Two-Pass Elicitation: Check for required parameters
80
+ elicitation_request = self._check_elicitation_for_infra_metrics(
81
+ metrics, plugin, query
82
+ )
83
+ if elicitation_request:
84
+ logger.info("Elicitation needed for infrastructure metrics")
85
+ return elicitation_request
93
86
 
94
87
 
95
88
  if not time_frame:
@@ -127,6 +120,7 @@ class InfrastructureMetricsMCPTools(BaseInstanaClient):
127
120
  # Create the InfrastructureMetricsApi object
128
121
  get_combined_metrics = GetCombinedMetrics(**request_body)
129
122
 
123
+
130
124
  # Call the get_infrastructure_metrics method from the SDK
131
125
  result = api_client.get_infrastructure_metrics(
132
126
  offline=offline,
@@ -173,4 +167,86 @@ class InfrastructureMetricsMCPTools(BaseInstanaClient):
173
167
 
174
168
  except Exception as e:
175
169
  logger.error(f"Error in get_infrastructure_metrics: {e}", exc_info=True)
176
- return {"error": f"Failed to get Infra metrics: {e!s}"}
170
+ return {"error": f"Failed to get infrastructure metrics: {e!s}"}
171
+
172
+ def _check_elicitation_for_infra_metrics(
173
+ self,
174
+ metrics: Optional[List[str]],
175
+ plugin: Optional[str],
176
+ query: Optional[str]
177
+ ) -> Optional[Dict[str, Any]]:
178
+ """
179
+ Check if required parameters are missing and create elicitation request (Two-Pass).
180
+
181
+ Infrastructure metrics require plugin and query parameters.
182
+
183
+ Args:
184
+ metrics: Metrics list if provided
185
+ plugin: Plugin name if provided
186
+ query: Query filter if provided
187
+
188
+ Returns:
189
+ Elicitation request dict if parameters are missing, None otherwise
190
+ """
191
+ missing_params = []
192
+
193
+ # Check for required parameters
194
+ if not metrics:
195
+ missing_params.append({
196
+ "name": "metrics",
197
+ "description": "List of metric names to retrieve (REQUIRED)",
198
+ "examples": ["cpu.used", "memory.used", "disk.used"],
199
+ "type": "list"
200
+ })
201
+
202
+ if not plugin:
203
+ missing_params.append({
204
+ "name": "plugin",
205
+ "description": "Plugin type for infrastructure entity (REQUIRED)",
206
+ "examples": ["host", "docker", "kubernetes", "jvm"],
207
+ "type": "string"
208
+ })
209
+
210
+ if not query:
211
+ missing_params.append({
212
+ "name": "query_filter",
213
+ "description": "Query filter to select entities (REQUIRED)",
214
+ "examples": ["entity.type:host", "entity.type:docker", "entity.tag:production"],
215
+ "type": "string"
216
+ })
217
+
218
+ # If any required parameters are missing, return elicitation request
219
+ if missing_params:
220
+ return self._create_elicitation_request(missing_params)
221
+
222
+ return None
223
+
224
+ def _create_elicitation_request(self, missing_params: list) -> Dict[str, Any]:
225
+ """
226
+ Create an elicitation request following MCP pattern.
227
+
228
+ Args:
229
+ missing_params: List of missing parameter descriptions
230
+
231
+ Returns:
232
+ Elicitation request dict
233
+ """
234
+ # Build simple, user-friendly parameter descriptions
235
+ param_lines = []
236
+ for param in missing_params:
237
+ # Use the examples from the parameter definition instead of hardcoding
238
+ examples = ", ".join([str(ex) for ex in param["examples"][:3]])
239
+ param_lines.append(f"{param['name']}: {examples}")
240
+
241
+ message = (
242
+ "I need:\n\n"
243
+ + "\n".join(param_lines)
244
+ )
245
+
246
+ return {
247
+ "elicitation_needed": True,
248
+ "message": message,
249
+ "missing_parameters": [p["name"] for p in missing_params],
250
+ "parameter_details": missing_params,
251
+ "instructions": "Call query_instana_metrics again with these parameters filled in."
252
+ }
@@ -39,10 +39,7 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
39
39
  """Initialize the Infrastructure Resources MCP tools client."""
40
40
  super().__init__(read_token=read_token, base_url=base_url)
41
41
 
42
- @register_as_tool(
43
- title="Get Monitoring State",
44
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
45
- )
42
+ # @register_as_tool(...) # Disabled for future reference
46
43
  @with_header_auth(InfrastructureResourcesApi)
47
44
  async def get_monitoring_state(self, ctx=None, api_client=None) -> Dict[str, Any]:
48
45
  """
@@ -109,10 +106,7 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
109
106
  logger.error(f"Error in get_plugin_payload: {e}", exc_info=True)
110
107
  return {"error": f"Failed to get plugin payload: {e!s}"}
111
108
 
112
- @register_as_tool(
113
- title="Get Snapshot",
114
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
115
- )
109
+ # @register_as_tool(...) # Disabled for future reference
116
110
  @with_header_auth(InfrastructureResourcesApi)
117
111
  async def get_snapshot(self,
118
112
  snapshot_id: str,
@@ -220,10 +214,7 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
220
214
  logger.error(f"Error in get_snapshot: {e}", exc_info=True)
221
215
  return {"error": f"Failed to get snapshot: {e!s}"}
222
216
 
223
- @register_as_tool(
224
- title="Get Snapshots",
225
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
226
- )
217
+ # @register_as_tool(...) # Disabled for future reference
227
218
  @with_header_auth(InfrastructureResourcesApi)
228
219
  async def get_snapshots(self,
229
220
  query: Optional[str] = None,
@@ -378,10 +369,7 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
378
369
 
379
370
 
380
371
 
381
- @register_as_tool(
382
- title="Post Snapshots",
383
- annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
384
- )
372
+ # @register_as_tool(...) # Disabled for future reference
385
373
  @with_header_auth(InfrastructureResourcesApi)
386
374
  async def post_snapshots(self,
387
375
  snapshot_ids: Union[List[str], str],
@@ -559,10 +547,7 @@ class InfrastructureResourcesMCPTools(BaseInstanaClient):
559
547
 
560
548
 
561
549
 
562
- @register_as_tool(
563
- title="Software Versions",
564
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
565
- )
550
+ # @register_as_tool(...) # Disabled for future reference
566
551
  @with_header_auth(InfrastructureResourcesApi)
567
552
  async def software_versions(self, ctx=None, api_client=None) -> Dict[str, Any]:
568
553
  """
@@ -51,10 +51,7 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
51
51
  """Initialize the Infrastructure Topology MCP tools client."""
52
52
  super().__init__(read_token=read_token, base_url=base_url)
53
53
 
54
- @register_as_tool(
55
- title="Get Related Hosts",
56
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
57
- )
54
+ # @register_as_tool(...) # Disabled for future reference
58
55
  @with_header_auth(InfrastructureTopologyApi)
59
56
  async def get_related_hosts(self,
60
57
  snapshot_id: str,
@@ -115,10 +112,7 @@ class InfrastructureTopologyMCPTools(BaseInstanaClient):
115
112
  logger.error(f"Error in get_related_hosts: {e}", exc_info=True)
116
113
  return {"error": f"Failed to get related hosts: {e!s}"}
117
114
 
118
- @register_as_tool(
119
- title="Get Topology",
120
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
121
- )
115
+ # @register_as_tool(...) # Disabled for future reference
122
116
  @with_header_auth(InfrastructureTopologyApi)
123
117
  async def get_topology(self,
124
118
  include_data: Optional[bool] = False,
@@ -18,6 +18,63 @@ class ApplicationSettingsPrompts:
18
18
  """Get an Application Perspective configuration by ID"""
19
19
  return f"Retrieve application configuration with ID: {id}"
20
20
 
21
+ @auto_register_prompt
22
+ @staticmethod
23
+ def create_application_config(
24
+ label: str,
25
+ scope: Optional[str] = None,
26
+ boundary_scope: Optional[str] = None,
27
+ access_rules: Optional[str] = None,
28
+ tag_filter_expression: Optional[dict] = None
29
+ ) -> str:
30
+ """
31
+ Create a new Application Perspective configuration with user-provided settings.
32
+
33
+ REQUIRED:
34
+ - label: Application perspective name (string)
35
+
36
+ OPTIONAL (will prompt user if not provided):
37
+ - scope: Monitoring scope
38
+ Options: "INCLUDE_ALL_DOWNSTREAM" (default), "INCLUDE_IMMEDIATE_DOWNSTREAM_DATABASE_AND_MESSAGING", "INCLUDE_NO_DOWNSTREAM"
39
+ - boundary_scope: Boundary scope
40
+ Options: "ALL" (default), "INBOUND", "DEFAULT"
41
+ - access_rules: Access control rules
42
+ Options: "READ_WRITE_GLOBAL" (default), "READ_ONLY_GLOBAL", "CUSTOM"
43
+ - tag_filter_expression: Tag filter to match services (optional)
44
+
45
+ ELICITATION QUESTIONS:
46
+ 1. What scope should be used for monitoring? (INCLUDE_ALL_DOWNSTREAM/INCLUDE_IMMEDIATE_DOWNSTREAM_DATABASE_AND_MESSAGING/INCLUDE_NO_DOWNSTREAM)
47
+ 2. What boundary scope should be applied? (ALL/INBOUND/DEFAULT)
48
+ 3. What access rules should be configured? (READ_WRITE_GLOBAL/READ_ONLY_GLOBAL/CUSTOM)
49
+ 4. Do you want to add a tag filter expression to match specific services? (yes/no)
50
+
51
+ Example with all options:
52
+ {
53
+ "label": "My Application",
54
+ "scope": "INCLUDE_ALL_DOWNSTREAM",
55
+ "boundaryScope": "ALL",
56
+ "accessRules": [{"accessType": "READ_WRITE", "relationType": "GLOBAL"}],
57
+ "tagFilterExpression": {
58
+ "type": "TAG_FILTER",
59
+ "name": "service.name",
60
+ "operator": "CONTAINS",
61
+ "entity": "DESTINATION",
62
+ "value": "my-service"
63
+ }
64
+ }
65
+ """
66
+ config_details = [f"label: {label}"]
67
+ if scope:
68
+ config_details.append(f"scope: {scope}")
69
+ if boundary_scope:
70
+ config_details.append(f"boundaryScope: {boundary_scope}")
71
+ if access_rules:
72
+ config_details.append(f"accessRules: {access_rules}")
73
+ if tag_filter_expression:
74
+ config_details.append(f"tagFilterExpression: {tag_filter_expression}")
75
+
76
+ return f"Create application perspective configuration with {', '.join(config_details)}"
77
+
21
78
  @auto_register_prompt
22
79
  @staticmethod
23
80
  def get_all_endpoint_configs() -> str:
@@ -67,6 +124,7 @@ class ApplicationSettingsPrompts:
67
124
  return [
68
125
  ('get_all_applications_configs', cls.get_all_applications_configs),
69
126
  ('get_application_config', cls.get_application_config),
127
+ ('create_application_config', cls.create_application_config),
70
128
  ('get_all_endpoint_configs', cls.get_all_endpoint_configs),
71
129
  ('get_endpoint_config', cls.get_endpoint_config),
72
130
  ('get_all_manual_service_configs', cls.get_all_manual_service_configs),