mcp-instana 0.2.1__py3-none-any.whl → 0.3.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 (29) hide show
  1. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.1.dist-info}/METADATA +69 -40
  2. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.1.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.1.dist-info}/WHEEL +0 -0
  28. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.1.dist-info}/entry_points.txt +0 -0
  29. {mcp_instana-0.2.1.dist-info → mcp_instana-0.3.1.dist-info}/licenses/LICENSE.md +0 -0
@@ -7,6 +7,11 @@ This module provides application alert configuration tools for Instana monitorin
7
7
  import logging
8
8
  from typing import Any, Dict, List, Optional, Union
9
9
 
10
+ from mcp.types import ToolAnnotations
11
+
12
+ from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
13
+ from src.prompts import mcp
14
+
10
15
  # Import the necessary classes from the SDK
11
16
  try:
12
17
  from instana_client.api.global_application_alert_configuration_api import (
@@ -18,8 +23,6 @@ except ImportError:
18
23
  logger.error("Failed to import application alert configuration API", exc_info=True)
19
24
  raise
20
25
 
21
- from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
22
-
23
26
  # Configure logger for this module
24
27
  logger = logging.getLogger(__name__)
25
28
 
@@ -30,12 +33,15 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
30
33
  """Initialize the Application Alert MCP tools client."""
31
34
  super().__init__(read_token=read_token, base_url=base_url)
32
35
 
33
- @register_as_tool
36
+ @register_as_tool(
37
+ title="Find Active Global Application Alert Configs",
38
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
39
+ )
34
40
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
35
41
  async def find_active_global_application_alert_configs(self,
36
42
  application_id: str,
37
43
  alert_ids: Optional[List[str]] = None,
38
- ctx=None, api_client=None) -> Dict[str, Any]:
44
+ ctx=None, api_client=None) -> List[Dict[str, Any]]:
39
45
  """
40
46
  Get All Global Smart Alert Configuration.
41
47
 
@@ -57,7 +63,7 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
57
63
 
58
64
  # Validate required parameters
59
65
  if not application_id:
60
- return {"error": "application_id is required"}
66
+ return [{"error": "application_id is required"}]
61
67
 
62
68
  # Call the find_active_global_application_alert_configs method from the SDK
63
69
  logger.debug(f"Calling find_active_global_application_alert_configs with application_id={application_id}, alert_ids={alert_ids}")
@@ -66,21 +72,33 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
66
72
  alert_ids=alert_ids
67
73
  )
68
74
 
69
- # Convert the result to a dictionary
70
- if hasattr(result, 'to_dict'):
71
- result_dict = result.to_dict()
75
+ # Convert the result to a list format
76
+ if isinstance(result, list):
77
+ # If it's already a list, convert each item to dict if needed
78
+ result_list = []
79
+ for item in result:
80
+ if hasattr(item, 'to_dict'):
81
+ result_list.append(item.to_dict())
82
+ else:
83
+ result_list.append(item)
84
+ elif hasattr(result, 'to_dict'):
85
+ # If it's a single object, wrap it in a list
86
+ result_list = [result.to_dict()]
72
87
  else:
73
- # If it's already a dict or another format, use it as is
74
- result_dict = result
88
+ # If it's already a dict or other format, wrap it in a list
89
+ result_list = [result] if result else []
75
90
 
76
- logger.debug(f"Result from find_active_global_application_alert_configs: {result_dict}")
77
- return result_dict
91
+ logger.debug(f"Result from find_active_global_application_alert_configs: {result_list}")
92
+ return result_list
78
93
  except Exception as e:
79
94
  logger.error(f"Error in find_active_global_application_alert_configs: {e}", exc_info=True)
80
- return {"error": f"Failed to get active global application alert config: {e!s}"}
95
+ return [{"error": f"Failed to get active global application alert config: {e!s}"}]
81
96
 
82
97
 
83
- @register_as_tool
98
+ @register_as_tool(
99
+ title="Find Global Application Alert Config Versions",
100
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
101
+ )
84
102
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
85
103
  async def find_global_application_alert_config_versions(self,
86
104
  id: str,
@@ -128,7 +146,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
128
146
  logger.error(f"Error in find_global_application_alert_config_versions: {e}", exc_info=True)
129
147
  return {"error": f"Failed to get global application alert config versions: {e!s}"}
130
148
 
131
- @register_as_tool
149
+ @register_as_tool(
150
+ title="Find Global Application Alert Config",
151
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
152
+ )
132
153
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
133
154
  async def find_global_application_alert_config(self,
134
155
  id: Optional[str] = None,
@@ -174,7 +195,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
174
195
  logger.error(f"Error in find_global_application_alert_config: {e}", exc_info=True)
175
196
  return {"error": f"Failed to get global application alert configs: {e!s}"}
176
197
 
177
- @register_as_tool
198
+ @register_as_tool(
199
+ title="Delete Global Application Alert Config",
200
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
201
+ )
178
202
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
179
203
  async def delete_global_application_alert_config(self,
180
204
  id: str,
@@ -215,7 +239,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
215
239
  logger.error(f"Error in delete_global_application_alert_config: {e}", exc_info=True)
216
240
  return {"error": f"Failed to delete global application alert config: {e!s}"}
217
241
 
218
- @register_as_tool
242
+ @register_as_tool(
243
+ title="Enable Global Application Alert Config",
244
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
245
+ )
219
246
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
220
247
  async def enable_global_application_alert_config(self,
221
248
  id: str,
@@ -260,7 +287,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
260
287
  logger.error(f"Error in enable_global_application_alert_config: {e}", exc_info=True)
261
288
  return {"error": f"Failed to enable global application alert config: {e!s}"}
262
289
 
263
- @register_as_tool
290
+ @register_as_tool(
291
+ title="Disable Global Application Alert Config",
292
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
293
+ )
264
294
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
265
295
  async def disable_global_application_alert_config(self,
266
296
  id: str,
@@ -305,7 +335,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
305
335
  logger.error(f"Error in disable_global_application_alert_config: {e}", exc_info=True)
306
336
  return {"error": f"Failed to disable global application alert config: {e!s}"}
307
337
 
308
- @register_as_tool
338
+ @register_as_tool(
339
+ title="Restore Global Application Alert Config",
340
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
341
+ )
309
342
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
310
343
  async def restore_global_application_alert_config(self,
311
344
  id: str,
@@ -355,7 +388,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
355
388
  logger.error(f"Error in restore_global_application_alert_config: {e}", exc_info=True)
356
389
  return {"error": f"Failed to restore global application alert config: {e!s}"}
357
390
 
358
- @register_as_tool
391
+ @register_as_tool(
392
+ title="Create Global Application Alert Config",
393
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
394
+ )
359
395
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
360
396
  async def create_global_application_alert_config(self,
361
397
  payload: Union[Dict[str, Any], str],
@@ -497,7 +533,10 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
497
533
  logger.error(f"Error in create_global_application_alert_config: {e}", exc_info=True)
498
534
  return {"error": f"Failed to create global application alert config: {e!s}"}
499
535
 
500
- @register_as_tool
536
+ @register_as_tool(
537
+ title="Update Global Application Alert Config",
538
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
539
+ )
501
540
  @with_header_auth(GlobalApplicationAlertConfigurationApi)
502
541
  async def update_global_application_alert_config(self,
503
542
  id: str,
@@ -8,6 +8,10 @@ import logging
8
8
  from datetime import datetime
9
9
  from typing import Any, Dict, List, Optional
10
10
 
11
+ from mcp.types import ToolAnnotations
12
+
13
+ from src.prompts import mcp
14
+
11
15
  # Import the necessary classes from the SDK
12
16
  try:
13
17
  from instana_client.api.application_metrics_api import (
@@ -37,7 +41,10 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
37
41
  """Initialize the Application Metrics MCP tools client."""
38
42
  super().__init__(read_token=read_token, base_url=base_url)
39
43
 
40
- @register_as_tool
44
+ @register_as_tool(
45
+ title="Get Application Data Metrics V2",
46
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
47
+ )
41
48
  @with_header_auth(ApplicationMetricsApi)
42
49
  async def get_application_data_metrics_v2(self,
43
50
  metrics: Optional[List[Dict[str, Any]]] = None,
@@ -121,7 +128,10 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
121
128
  logger.error(f"Error in get_application_data_metrics_v2: {e}", exc_info=True)
122
129
  return {"error": f"Failed to get application data metrics: {e!s}"}
123
130
 
124
- @register_as_tool
131
+ @register_as_tool(
132
+ title="Get Application Metrics",
133
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
134
+ )
125
135
  @with_header_auth(ApplicationMetricsApi)
126
136
  async def get_application_metrics(self,
127
137
  application_ids: Optional[List[str]] = None,
@@ -199,7 +209,10 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
199
209
  logger.error(f"Error in get_application_metrics: {e}", exc_info=True)
200
210
  return {"error": f"Failed to get application metrics: {e!s}"}
201
211
 
202
- @register_as_tool
212
+ @register_as_tool(
213
+ title="Get Endpoints Metrics",
214
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
215
+ )
203
216
  @with_header_auth(ApplicationMetricsApi)
204
217
  async def get_endpoints_metrics(self,
205
218
  endpoint_ids: Optional[List[str]] = None,
@@ -277,7 +290,10 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
277
290
  logger.error(f"Error in get_endpoints_metrics: {e}", exc_info=True)
278
291
  return {"error": f"Failed to get endpoints metrics: {e!s}"}
279
292
 
280
- @register_as_tool
293
+ @register_as_tool(
294
+ title="Get Services Metrics",
295
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
296
+ )
281
297
  @with_header_auth(ApplicationMetricsApi)
282
298
  async def get_services_metrics(self,
283
299
  service_ids: Optional[List[str]] = None,
@@ -8,6 +8,10 @@ import logging
8
8
  from datetime import datetime
9
9
  from typing import Any, Dict, List, Optional
10
10
 
11
+ from mcp.types import ToolAnnotations
12
+
13
+ from src.prompts import mcp
14
+
11
15
  # Import the necessary classes from the SDK
12
16
  try:
13
17
  from instana_client.api.application_resources_api import (
@@ -32,7 +36,10 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
32
36
  """Initialize the Application Resources MCP tools client."""
33
37
  super().__init__(read_token=read_token, base_url=base_url)
34
38
 
35
- @register_as_tool
39
+ @register_as_tool(
40
+ title="Get Application Endpoints",
41
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
42
+ )
36
43
  @with_header_auth(ApplicationResourcesApi)
37
44
  async def get_application_endpoints(self,
38
45
  name_filter: Optional[str] = None,
@@ -99,7 +106,10 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
99
106
  logger.error(f"Error in get_application_endpoints: {e}", exc_info=True)
100
107
  return {"error": f"Failed to get application endpoints: {e!s}"}
101
108
 
102
- @register_as_tool
109
+ @register_as_tool(
110
+ title="Get Application Services",
111
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
112
+ )
103
113
  @with_header_auth(ApplicationResourcesApi)
104
114
  async def get_application_services(self,
105
115
  name_filter: Optional[str] = None,
@@ -203,7 +213,10 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
203
213
  return {"error": f"Failed to get application services: {e!s}"}
204
214
 
205
215
 
206
- @register_as_tool
216
+ @register_as_tool(
217
+ title="Get Applications",
218
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
219
+ )
207
220
  @with_header_auth(ApplicationResourcesApi)
208
221
  async def get_applications(self,
209
222
  name_filter: Optional[str] = None,
@@ -282,7 +295,10 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
282
295
  return [f"Error: Failed to get applications: {e!s}"]
283
296
 
284
297
 
285
- @register_as_tool
298
+ @register_as_tool(
299
+ title="Get Services",
300
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
301
+ )
286
302
  @with_header_auth(ApplicationResourcesApi)
287
303
  async def get_services(self,
288
304
  name_filter: Optional[str] = None,
@@ -13,9 +13,12 @@ import traceback
13
13
  from datetime import datetime
14
14
  from typing import Any, Dict, List, Optional, Union
15
15
 
16
- logger = logging.getLogger(__name__)
16
+ from mcp.types import ToolAnnotations
17
17
 
18
18
  from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
19
+ from src.prompts import mcp
20
+
21
+ logger = logging.getLogger(__name__)
19
22
 
20
23
  # Import the necessary classes from the SDK
21
24
  try:
@@ -68,7 +71,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
68
71
  traceback.print_exc(file=sys.stderr)
69
72
  raise
70
73
 
71
- @register_as_tool
74
+ @register_as_tool(
75
+ title="Get All Applications Configs",
76
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
77
+ )
72
78
  @with_header_auth(ApplicationSettingsApi)
73
79
  async def get_all_applications_configs(self,
74
80
  ctx=None,
@@ -85,24 +91,34 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
85
91
  """
86
92
  try:
87
93
  debug_print("Fetching all applications and their settings")
88
- result = api_client.get_application_configs()
89
- # Convert the result to a list of dictionaries
90
- if isinstance(result, list):
91
- result_dict = [item.to_dict() if hasattr(item, 'to_dict') else item for item in result]
92
- elif hasattr(result, 'to_dict'):
93
- result_dict = result.to_dict()
94
- else:
95
- result_dict = result
96
-
97
- debug_print(f"Result from get_application_configs: {result_dict}")
98
- return result_dict
94
+ # Use raw JSON response to avoid Pydantic validation issues
95
+ result = api_client.get_application_configs_without_preload_content()
96
+ import json
97
+ try:
98
+ response_text = result.data.decode('utf-8')
99
+ json_data = json.loads(response_text)
100
+ # Convert to List[Dict[str, Any]] format
101
+ if isinstance(json_data, list):
102
+ result_dict = json_data
103
+ else:
104
+ # If it's a single object, wrap it in a list
105
+ result_dict = [json_data] if json_data else []
106
+ debug_print("Successfully retrieved application configs data")
107
+ return result_dict
108
+ except (json.JSONDecodeError, AttributeError) as json_err:
109
+ error_message = f"Failed to parse JSON response: {json_err}"
110
+ debug_print(error_message)
111
+ return [{"error": error_message}]
99
112
 
100
113
  except Exception as e:
101
114
  debug_print(f"Error in get_application_configs: {e}")
102
115
  traceback.print_exc(file=sys.stderr)
103
116
  return [{"error": f"Failed to get all applications: {e!s}"}]
104
117
 
105
- @register_as_tool
118
+ @register_as_tool(
119
+ title="Add Application Config",
120
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
121
+ )
106
122
  @with_header_auth(ApplicationSettingsApi)
107
123
  async def add_application_config(self,
108
124
  payload: Union[Dict[str, Any], str],
@@ -247,7 +263,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
247
263
  logger.error(f"Error in add_application_config: {e}")
248
264
  return {"error": f"Failed to add new application config: {e!s}"}
249
265
 
250
- @register_as_tool
266
+ @register_as_tool(
267
+ title="Delete Application Config",
268
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
269
+ )
251
270
  @with_header_auth(ApplicationSettingsApi)
252
271
  async def delete_application_config(self,
253
272
  id: str,
@@ -285,7 +304,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
285
304
  traceback.print_exc(file=sys.stderr)
286
305
  return {"error": f"Failed to delete application configuration: {e!s}"}
287
306
 
288
- @register_as_tool
307
+ @register_as_tool(
308
+ title="Get Application Config",
309
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
310
+ )
289
311
  @with_header_auth(ApplicationSettingsApi)
290
312
  async def get_application_config(self,
291
313
  id: str,
@@ -320,7 +342,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
320
342
  traceback.print_exc(file=sys.stderr)
321
343
  return {"error": f"Failed to get application configuration: {e!s}"}
322
344
 
323
- @register_as_tool
345
+ @register_as_tool(
346
+ title="Update Application Config",
347
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
348
+ )
324
349
  @with_header_auth(ApplicationSettingsApi)
325
350
  async def update_application_config(
326
351
  self,
@@ -473,7 +498,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
473
498
  logger.error(f"Error in put_application_config: {e}")
474
499
  return {"error": f"Failed to update existing application config: {e!s}"}
475
500
 
476
- @register_as_tool
501
+ @register_as_tool(
502
+ title="Get All Endpoint Configs",
503
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
504
+ )
477
505
  @with_header_auth(ApplicationSettingsApi)
478
506
  async def get_all_endpoint_configs(self,
479
507
  ctx=None,
@@ -505,7 +533,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
505
533
  traceback.print_exc(file=sys.stderr)
506
534
  return [{"error": f"Failed to get endpoint configs: {e!s}"}]
507
535
 
508
- @register_as_tool
536
+ @register_as_tool(
537
+ title="Create Endpoint Config",
538
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
539
+ )
509
540
  @with_header_auth(ApplicationSettingsApi)
510
541
  async def create_endpoint_config(
511
542
  self,
@@ -607,7 +638,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
607
638
  logger.error(f"Error in create_endpoint_config: {e}")
608
639
  return {"error": f"Failed to create new endpoint config: {e!s}"}
609
640
 
610
- @register_as_tool
641
+ @register_as_tool(
642
+ title="Delete Endpoint Config",
643
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
644
+ )
611
645
  @with_header_auth(ApplicationSettingsApi)
612
646
  async def delete_endpoint_config(
613
647
  self,
@@ -645,7 +679,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
645
679
  traceback.print_exc(file=sys.stderr)
646
680
  return {"error": f"Failed to delete endpoint configs: {e!s}"}
647
681
 
648
- @register_as_tool
682
+ @register_as_tool(
683
+ title="Get Endpoint Config",
684
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
685
+ )
649
686
  @with_header_auth(ApplicationSettingsApi)
650
687
  async def get_endpoint_config(
651
688
  self,
@@ -685,7 +722,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
685
722
  traceback.print_exc(file=sys.stderr)
686
723
  return {"error": f"Failed to get endpoint configs: {e!s}"}
687
724
 
688
- @register_as_tool
725
+ @register_as_tool(
726
+ title="Update Endpoint Config",
727
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
728
+ )
689
729
  @with_header_auth(ApplicationSettingsApi)
690
730
  async def update_endpoint_config(
691
731
  self,
@@ -811,7 +851,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
811
851
  return {"error": f"Failed to update existing application config: {e!s}"}
812
852
 
813
853
 
814
- @register_as_tool
854
+ @register_as_tool(
855
+ title="Get All Manual Service Configs",
856
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
857
+ )
815
858
  @with_header_auth(ApplicationSettingsApi)
816
859
  async def get_all_manual_service_configs(self,
817
860
  ctx=None,
@@ -843,7 +886,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
843
886
  traceback.print_exc(file=sys.stderr)
844
887
  return [{"error": f"Failed to get manual service configs: {e!s}"}]
845
888
 
846
- @register_as_tool
889
+ @register_as_tool(
890
+ title="Add Manual Service Config",
891
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
892
+ )
847
893
  @with_header_auth(ApplicationSettingsApi)
848
894
  async def add_manual_service_config(
849
895
  self,
@@ -960,7 +1006,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
960
1006
  logger.error(f"Error in add_manual_service_config: {e}")
961
1007
  return {"error": f"Failed to create new manual service config: {e!s}"}
962
1008
 
963
- @register_as_tool
1009
+ @register_as_tool(
1010
+ title="Delete Manual Service Config",
1011
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
1012
+ )
964
1013
  @with_header_auth(ApplicationSettingsApi)
965
1014
  async def delete_manual_service_config(
966
1015
  self,
@@ -998,7 +1047,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
998
1047
  traceback.print_exc(file=sys.stderr)
999
1048
  return {"error": f"Failed to delete manual service configs: {e!s}"}
1000
1049
 
1001
- @register_as_tool
1050
+ @register_as_tool(
1051
+ title="Update Manual Service Config",
1052
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
1053
+ )
1002
1054
  @with_header_auth(ApplicationSettingsApi)
1003
1055
  async def update_manual_service_config(
1004
1056
  self,
@@ -1122,7 +1174,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1122
1174
  return {"error": f"Failed to update manual config: {e!s}"}
1123
1175
 
1124
1176
 
1125
- @register_as_tool
1177
+ @register_as_tool(
1178
+ title="Replace All Manual Service Config",
1179
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
1180
+ )
1126
1181
  @with_header_auth(ApplicationSettingsApi)
1127
1182
  async def replace_all_manual_service_config(
1128
1183
  self,
@@ -1244,7 +1299,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1244
1299
  logger.error(f"Error in replace_all_manual_service_config: {e}")
1245
1300
  return [{"error": f"Failed to replace all manual config: {e!s}"}]
1246
1301
 
1247
- @register_as_tool
1302
+ @register_as_tool(
1303
+ title="Get All Service Configs",
1304
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
1305
+ )
1248
1306
  @with_header_auth(ApplicationSettingsApi)
1249
1307
  async def get_all_service_configs(self,
1250
1308
  ctx=None,
@@ -1276,7 +1334,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1276
1334
  traceback.print_exc(file=sys.stderr)
1277
1335
  return [{"error": f"Failed to get application data metrics: {e}"}]
1278
1336
 
1279
- @register_as_tool
1337
+ @register_as_tool(
1338
+ title="Add Service Config",
1339
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
1340
+ )
1280
1341
  @with_header_auth(ApplicationSettingsApi)
1281
1342
  async def add_service_config(self,
1282
1343
  payload: Union[Dict[str, Any], str],
@@ -1388,7 +1449,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1388
1449
  logger.error(f"Error in add_service_config: {e}")
1389
1450
  return {"error": f"Failed to add service config: {e!s}"}
1390
1451
 
1391
- @register_as_tool
1452
+ @register_as_tool(
1453
+ title="Replace All Service Configs",
1454
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
1455
+ )
1392
1456
  @with_header_auth(ApplicationSettingsApi)
1393
1457
  async def replace_all_service_configs(self,
1394
1458
  payload: Union[Dict[str, Any], str],
@@ -1498,7 +1562,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1498
1562
  return [{"error": f"Failed to replace all service config: {e!s}"}]
1499
1563
 
1500
1564
 
1501
- @register_as_tool
1565
+ @register_as_tool(
1566
+ title="Order Service Config",
1567
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
1568
+ )
1502
1569
  @with_header_auth(ApplicationSettingsApi)
1503
1570
  async def order_service_config(self,
1504
1571
  request_body: List[str],
@@ -1537,7 +1604,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1537
1604
  traceback.print_exc(file=sys.stderr)
1538
1605
  return {"error": f"Failed to order service configs: {e!s}"}
1539
1606
 
1540
- @register_as_tool
1607
+ @register_as_tool(
1608
+ title="Delete Service Config",
1609
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True)
1610
+ )
1541
1611
  @with_header_auth(ApplicationSettingsApi)
1542
1612
  async def delete_service_config(self,
1543
1613
  id: str,
@@ -1575,7 +1645,10 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1575
1645
  traceback.print_exc(file=sys.stderr)
1576
1646
  return {"error": f"Failed to delete service configuration: {e!s}"}
1577
1647
 
1578
- @register_as_tool
1648
+ @register_as_tool(
1649
+ title="Get Service Config",
1650
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
1651
+ )
1579
1652
  @with_header_auth(ApplicationSettingsApi)
1580
1653
  async def get_service_config(
1581
1654
  self,
@@ -1615,13 +1688,16 @@ class ApplicationSettingsMCPTools(BaseInstanaClient):
1615
1688
  traceback.print_exc(file=sys.stderr)
1616
1689
  return {"error": f"Failed to get service config: {e!s}"}
1617
1690
 
1618
- @register_as_tool
1691
+ @register_as_tool(
1692
+ title="Update Service Config",
1693
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
1694
+ )
1619
1695
  @with_header_auth(ApplicationSettingsApi)
1620
1696
  async def update_service_config(self,
1621
1697
  id: str,
1622
1698
  payload: Union[Dict[str, Any], str],
1623
1699
  ctx=None,
1624
- api_client=None) -> Dict[str, Any]:
1700
+ api_client=None) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
1625
1701
  """
1626
1702
  This tool gives is used if one wants to update a particular custom service rule.
1627
1703
  Args:
@@ -8,7 +8,10 @@ import logging
8
8
  from datetime import datetime
9
9
  from typing import Any, Dict, Optional
10
10
 
11
+ from mcp.types import ToolAnnotations
12
+
11
13
  from src.core.utils import BaseInstanaClient, register_as_tool
14
+ from src.prompts import mcp
12
15
 
13
16
  try:
14
17
  from instana_client.api.application_topology_api import (
@@ -52,7 +55,10 @@ class ApplicationTopologyMCPTools(BaseInstanaClient):
52
55
  logger.error(f"Error initializing ApplicationTopologyMCPTools: {e}", exc_info=True)
53
56
  raise
54
57
 
55
- @register_as_tool
58
+ @register_as_tool(
59
+ title="Get Application Topology",
60
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
61
+ )
56
62
  async def get_application_topology(self,
57
63
  window_size: Optional[int] = None,
58
64
  to_timestamp: Optional[int] = None,
@@ -84,27 +90,29 @@ class ApplicationTopologyMCPTools(BaseInstanaClient):
84
90
  if not window_size:
85
91
  window_size = 3600000 # Default to 1 hour in milliseconds
86
92
 
87
- # Call the API
93
+ # Call the API with raw JSON response to avoid Pydantic validation issues
88
94
  # Note: The SDK expects parameters in camelCase, but we use snake_case in Python
89
95
  # The SDK will handle the conversion
90
- result = self.topology_api.get_services_map(
96
+ result = self.topology_api.get_services_map_without_preload_content(
91
97
  window_size=window_size,
92
98
  to=to_timestamp,
93
99
  application_id=application_id,
94
100
  application_boundary_scope=application_boundary_scope
95
101
  )
96
102
 
97
- # Ensure we always return a dictionary
98
- if hasattr(result, "to_dict"):
99
- result_dict = result.to_dict()
100
- elif isinstance(result, dict):
101
- result_dict = result
102
- else:
103
- # Convert to dictionary using __dict__ or as a fallback, create a new dict with string representation
104
- result_dict = getattr(result, "__dict__", {"data": str(result)})
105
-
106
- logger.debug("Successfully retrieved service topology data")
107
- return result_dict
103
+ # Parse the JSON response manually
104
+ import json
105
+ try:
106
+ # The result from get_services_map_without_preload_content is a response object
107
+ # We need to read the response data and parse it as JSON
108
+ response_text = result.data.decode('utf-8')
109
+ result_dict = json.loads(response_text)
110
+ logger.debug("Successfully retrieved service topology data")
111
+ return result_dict
112
+ except (json.JSONDecodeError, AttributeError) as json_err:
113
+ error_message = f"Failed to parse JSON response: {json_err}"
114
+ logger.error(error_message)
115
+ return {"error": error_message}
108
116
 
109
117
  except Exception as e:
110
118
  logger.error(f"Error in get_application_topology: {e}", exc_info=True)