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,70 +4,52 @@ Application Resources MCP Tools Module
4
4
  This module provides application resources-specific MCP tools for Instana monitoring.
5
5
  """
6
6
 
7
- import sys
8
- import traceback
9
- from typing import Dict, Any, Optional, List
7
+ import logging
10
8
  from datetime import datetime
9
+ from typing import Any, Dict, List, Optional
11
10
 
12
11
  # Import the necessary classes from the SDK
13
12
  try:
14
- from instana_client.api.application_resources_api import ApplicationResourcesApi
15
- from instana_client.api_client import ApiClient
16
- from instana_client.configuration import Configuration
13
+ from instana_client.api.application_resources_api import (
14
+ ApplicationResourcesApi,
15
+ )
16
+
17
17
  except ImportError as e:
18
- print(f"Error importing Instana SDK: {e}", file=sys.stderr)
19
- traceback.print_exc(file=sys.stderr)
18
+ import logging
19
+ logger = logging.getLogger(__name__)
20
+ logger.error(f"Error importing Instana SDK: {e}", exc_info=True)
20
21
  raise
21
22
 
22
- from .instana_client_base import BaseInstanaClient, register_as_tool
23
+ from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
23
24
 
24
- # Helper function for debug printing
25
- def debug_print(*args, **kwargs):
26
- """Print debug information to stderr instead of stdout"""
27
- print(*args, file=sys.stderr, **kwargs)
25
+ # Configure logger for this module
26
+ logger = logging.getLogger(__name__)
28
27
 
29
28
  class ApplicationResourcesMCPTools(BaseInstanaClient):
30
29
  """Tools for application resources in Instana MCP."""
31
-
30
+
32
31
  def __init__(self, read_token: str, base_url: str):
33
32
  """Initialize the Application Resources MCP tools client."""
34
33
  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 ApplicationResourcesApi with our configured client
48
- self.app_api = ApplicationResourcesApi(api_client=api_client)
49
- except Exception as e:
50
- debug_print(f"Error initializing ApplicationResourcesApi: {e}")
51
- traceback.print_exc(file=sys.stderr)
52
- raise
53
-
34
+
54
35
  @register_as_tool
55
- async def get_application_endpoints(self,
56
- name_filter: Optional[str] = None,
57
- types: Optional[List[str]] = None,
58
- technologies: Optional[List[str]] = None,
59
- window_size: Optional[int] = None,
60
- to_time: Optional[int] = None,
61
- page: Optional[int] = None,
62
- page_size: Optional[int] = None,
63
- application_boundary_scope: Optional[str] = None,
64
- ctx=None) -> Dict[str, Any]:
36
+ @with_header_auth(ApplicationResourcesApi)
37
+ async def get_application_endpoints(self,
38
+ name_filter: Optional[str] = None,
39
+ types: Optional[List[str]] = None,
40
+ technologies: Optional[List[str]] = None,
41
+ window_size: Optional[int] = None,
42
+ to_time: Optional[int] = None,
43
+ page: Optional[int] = None,
44
+ page_size: Optional[int] = None,
45
+ application_boundary_scope: Optional[str] = None,
46
+ ctx=None, api_client=None) -> Dict[str, Any]:
65
47
  """
66
48
  Get endpoints for all services from Instana. Use this API endpoint if one wants to retrieve a list of Endpoints. A use case could be to view the endpoint id of an Endpoint.
67
- Retrieve a list of application endpoints from Instana. This tool is useful when you need to get information about endpoints across services in your application.
49
+ Retrieve a list of application endpoints from Instana. This tool is useful when you need to get information about endpoints across services in your application.
68
50
  You can filter by endpoint name, types, technologies, and other parameters. Use this when you want to see what endpoints exist in your application, understand their IDs, or analyze endpoint performance metrics.
69
51
  For example, use this tool when asked about 'application endpoints', 'service endpoints', 'API endpoints in my application','endpoint id of an Endpoint', or when someone wants to 'list all endpoints'.
70
-
52
+
71
53
  Args:
72
54
  name_filter: Name of service to filter by (optional)
73
55
  types: List of endpoint types to filter by (optional)
@@ -78,22 +60,22 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
78
60
  page_size: Number of items per page (optional)
79
61
  application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
80
62
  ctx: The MCP context (optional)
81
-
63
+
82
64
  Returns:
83
65
  Dictionary containing endpoints data or error information
84
66
  """
85
67
  try:
86
- debug_print(f"get_application_endpoints called with name_filter={name_filter}")
87
-
68
+ logger.debug(f"get_application_endpoints called with name_filter={name_filter}")
69
+
88
70
  # Set default time range if not provided
89
71
  if not to_time:
90
72
  to_time = int(datetime.now().timestamp() * 1000)
91
-
73
+
92
74
  if not window_size:
93
75
  window_size = 60 * 60 * 1000 # Default to 1 hour
94
-
76
+
95
77
  # Call the get_application_endpoints method from the SDK
96
- result = self.app_api.get_application_endpoints(
78
+ result = api_client.get_application_endpoints(
97
79
  name_filter=name_filter,
98
80
  types=types,
99
81
  technologies=technologies,
@@ -103,38 +85,37 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
103
85
  page_size=page_size,
104
86
  application_boundary_scope=application_boundary_scope
105
87
  )
106
-
88
+
107
89
  # Convert the result to a dictionary
108
90
  if hasattr(result, 'to_dict'):
109
91
  result_dict = result.to_dict()
110
92
  else:
111
93
  # If it's already a dict or another format, use it as is
112
94
  result_dict = result
113
-
114
- debug_print(f"Result from get_application_endpoints: {result_dict}")
95
+
96
+ logger.debug(f"Result from get_application_endpoints: {result_dict}")
115
97
  return result_dict
116
98
  except Exception as e:
117
- debug_print(f"Error in get_application_endpoints: {e}")
118
- traceback.print_exc(file=sys.stderr)
119
- return {"error": f"Failed to get application endpoints: {str(e)}"}
120
-
99
+ logger.error(f"Error in get_application_endpoints: {e}", exc_info=True)
100
+ return {"error": f"Failed to get application endpoints: {e!s}"}
101
+
121
102
  @register_as_tool
122
- async def get_application_services(self,
123
- name_filter: Optional[str] = None,
124
- window_size: Optional[int] = None,
125
- to_time: Optional[int] = None,
126
- page: Optional[int] = None,
127
- page_size: Optional[int] = None,
128
- application_boundary_scope: Optional[str] = None,
129
- include_snapshot_ids: Optional[bool] = None,
130
- ctx=None) -> Dict[str, Any]:
103
+ @with_header_auth(ApplicationResourcesApi)
104
+ async def get_application_services(self,
105
+ name_filter: Optional[str] = None,
106
+ window_size: Optional[int] = None,
107
+ to_time: Optional[int] = None,
108
+ page: Optional[int] = None,
109
+ page_size: Optional[int] = None,
110
+ application_boundary_scope: Optional[str] = None,
111
+ include_snapshot_ids: Optional[bool] = None,
112
+ ctx=None, api_client=None) -> Dict[str, Any]:
131
113
  """
132
- Retrieve a list of services within application perspectives from Instana. This tool is useful when you need to get information about all services in your monitored applications.
133
- You can filter by service name and other parameters to narrow down results. Use this when you want to see what services exist in your application,
134
- understand their IDs, or analyze service-level metrics. This is particularly helpful when you need to retrieve all service IDs present in an Application Perspective for further analysis or monitoring.
135
- For example, use this tool when asked about 'application services', 'microservices in my application', 'list all services', or when someone wants to 'get service information'. A use case could be to retrieve all service ids present in an Application Perspective.
114
+ Retrieve a list of services within application perspectives from Instana. This tool is useful when you need to get information about all services in your monitored applications.
115
+ You can filter by service name and other parameters to narrow down results. Use this when you want to see what services exist in your application,
116
+ understand their IDs, or analyze service-level metrics. This is particularly helpful when you need to retrieve all service IDs present in an Application Perspective for further analysis or monitoring.
117
+ For example, use this tool when asked about 'application services', 'microservices in my application', 'list all services', or when someone wants to 'get service information'. A use case could be to retrieve all service ids present in an Application Perspective.
136
118
 
137
-
138
119
  Args:
139
120
  name_filter: Name of application/service to filter by (optional)
140
121
  window_size: Size of time window in milliseconds (optional)
@@ -144,22 +125,22 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
144
125
  application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
145
126
  include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
146
127
  ctx: The MCP context (optional)
147
-
128
+
148
129
  Returns:
149
130
  Dictionary containing service labels with their IDs and summary information
150
131
  """
151
- try:
152
- debug_print(f"get_application_services called with name_filter={name_filter}")
153
-
132
+ try:
133
+ logger.debug(f"get_application_services called with name_filter={name_filter}")
134
+
154
135
  # Set default time range if not provided
155
136
  if not to_time:
156
137
  to_time = int(datetime.now().timestamp() * 1000)
157
-
138
+
158
139
  if not window_size:
159
140
  window_size = 60 * 60 * 1000 # Default to 1 hour
160
-
141
+
161
142
  # Call the get_application_services method from the SDK
162
- result = self.app_api.get_application_services(
143
+ result = api_client.get_application_services(
163
144
  name_filter=name_filter,
164
145
  window_size=window_size,
165
146
  to=to_time,
@@ -168,27 +149,27 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
168
149
  application_boundary_scope=application_boundary_scope,
169
150
  include_snapshot_ids=include_snapshot_ids
170
151
  )
171
-
152
+
172
153
  # Convert the result to a dictionary
173
154
  if hasattr(result, 'to_dict'):
174
155
  result_dict = result.to_dict()
175
156
  else:
176
157
  # If it's already a dict or another format, use it as is
177
158
  result_dict = result
178
-
179
- debug_print(f"Result from get_application_services: {result_dict}")
180
-
159
+
160
+ logger.debug(f"Result from get_application_services: {result_dict}")
161
+
181
162
  # Extract service labels and IDs from the items
182
163
  services = []
183
164
  service_labels = []
184
165
  items = result_dict.get('items', [])
185
-
166
+
186
167
  for item in items:
187
168
  if isinstance(item, dict):
188
169
  service_id = item.get('id', '')
189
170
  label = item.get('label', '')
190
171
  technologies = item.get('technologies', [])
191
-
172
+
192
173
  if label and service_id:
193
174
  service_labels.append(label)
194
175
  services.append({
@@ -203,12 +184,12 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
203
184
  'label': item.label,
204
185
  'technologies': getattr(item, 'technologies', [])
205
186
  })
206
-
187
+
207
188
  # Sort services by label alphabetically and limit to first 15
208
189
  services.sort(key=lambda x: x['label'])
209
190
  limited_services = services[:15]
210
191
  service_labels = [service['label'] for service in limited_services]
211
-
192
+
212
193
  return {
213
194
  "message": f"Found {len(services)} services in application perspectives. Showing first {len(limited_services)}:",
214
195
  "service_labels": service_labels,
@@ -216,29 +197,29 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
216
197
  "total_available": len(services),
217
198
  "showing": len(limited_services)
218
199
  }
219
-
200
+
220
201
  except Exception as e:
221
- debug_print(f"Error in get_application_services: {e}")
222
- traceback.print_exc(file=sys.stderr)
223
- return {"error": f"Failed to get application services: {str(e)}"}
202
+ logger.error(f"Error in get_application_services: {e}", exc_info=True)
203
+ return {"error": f"Failed to get application services: {e!s}"}
224
204
 
225
205
 
226
206
  @register_as_tool
227
- async def get_applications(self,
228
- name_filter: Optional[str] = None,
229
- window_size: Optional[int] = None,
230
- to_time: Optional[int] = None,
231
- page: Optional[int] = None,
232
- page_size: Optional[int] = None,
233
- application_boundary_scope: Optional[str] = None,
234
- ctx=None) -> List[str]:
207
+ @with_header_auth(ApplicationResourcesApi)
208
+ async def get_applications(self,
209
+ name_filter: Optional[str] = None,
210
+ window_size: Optional[int] = None,
211
+ to_time: Optional[int] = None,
212
+ page: Optional[int] = None,
213
+ page_size: Optional[int] = None,
214
+ application_boundary_scope: Optional[str] = None,
215
+ ctx=None, api_client=None) -> List[str]:
235
216
  """
236
- Retrieve a list of Application Perspectives from Instana. This tool is useful when you need to get information about any one application perspective in Instana.
237
- You can filter by application name and other parameters to narrow down results. Use this tool when you want to see what application perspectives exist, understand their IDs,
238
- or get an overview of your monitored applications. This is particularly helpful when you need to retrieve application IDs for use with other Instana APIs or when setting up monitoring dashboards.
239
- For example, use this tool when asked about 'application perspectives', 'list all applications in Instana', 'what applications are being monitored', or when someone wants to 'get application IDs'
240
- or 'get details about an application'.
241
-
217
+ Retrieve a list of Application Perspectives from Instana. This tool is useful when you need to get information about any one application perspective in Instana.
218
+ You can filter by application name and other parameters to narrow down results. Use this tool when you want to see what application perspectives exist, understand their IDs,
219
+ or get an overview of your monitored applications. This is particularly helpful when you need to retrieve application IDs for use with other Instana APIs or when setting up monitoring dashboards.
220
+ For example, use this tool when asked about 'application perspectives', 'list all applications in Instana', 'what applications are being monitored', or when someone wants to 'get application IDs'
221
+ or 'get details about an application'.
222
+
242
223
  Args:
243
224
  name_filter: Name of application to filter by (optional)
244
225
  window_size: Size of time window in milliseconds (optional)
@@ -247,22 +228,22 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
247
228
  page_size: Number of items per page (optional)
248
229
  application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
249
230
  ctx: The MCP context (optional)
250
-
231
+
251
232
  Returns:
252
233
  List of application names
253
234
  """
254
235
  try:
255
- debug_print(f"get_applications called with name_filter={name_filter}")
256
-
236
+ logger.debug(f"get_applications called with name_filter={name_filter}")
237
+
257
238
  # Set default time range if not provided
258
239
  if not to_time:
259
240
  to_time = int(datetime.now().timestamp() * 1000)
260
-
241
+
261
242
  if not window_size:
262
243
  window_size = 60 * 60 * 1000 # Default to 1 hour
263
-
244
+
264
245
  # Call the get_applications method from the SDK
265
- result = self.app_api.get_applications(
246
+ result = api_client.get_applications(
266
247
  name_filter=name_filter,
267
248
  window_size=window_size,
268
249
  to=to_time,
@@ -270,20 +251,20 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
270
251
  page_size=page_size,
271
252
  application_boundary_scope=application_boundary_scope
272
253
  )
273
-
254
+
274
255
  # Convert the result to a dictionary
275
256
  if hasattr(result, 'to_dict'):
276
257
  result_dict = result.to_dict()
277
258
  else:
278
259
  # If it's already a dict or another format, use it as is
279
260
  result_dict = result
280
-
281
- debug_print(f"Result from get_applications: {result_dict}")
282
-
261
+
262
+ logger.debug(f"Result from get_applications: {result_dict}")
263
+
283
264
  # Extract labels from the items
284
265
  labels = []
285
266
  items = result_dict.get('items', [])
286
-
267
+
287
268
  for item in items:
288
269
  if isinstance(item, dict):
289
270
  label = item.get('label', '')
@@ -291,34 +272,34 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
291
272
  labels.append(label)
292
273
  elif hasattr(item, 'label'):
293
274
  labels.append(item.label)
294
-
275
+
295
276
  # Sort labels alphabetically and limit to first 15
296
277
  labels.sort()
297
278
  return labels[:15]
298
-
279
+
299
280
  except Exception as e:
300
- debug_print(f"Error in get_applications: {e}")
301
- traceback.print_exc(file=sys.stderr)
302
- return [f"Error: Failed to get applications: {str(e)}"]
281
+ logger.error(f"Error in get_applications: {e}", exc_info=True)
282
+ return [f"Error: Failed to get applications: {e!s}"]
303
283
 
304
284
 
305
285
  @register_as_tool
306
- async def get_services(self,
307
- name_filter: Optional[str] = None,
308
- window_size: Optional[int] = None,
309
- to_time: Optional[int] = None,
310
- page: Optional[int] = None,
311
- page_size: Optional[int] = None,
312
- include_snapshot_ids: Optional[bool] = None,
313
- ctx=None) -> str:
286
+ @with_header_auth(ApplicationResourcesApi)
287
+ async def get_services(self,
288
+ name_filter: Optional[str] = None,
289
+ window_size: Optional[int] = None,
290
+ to_time: Optional[int] = None,
291
+ page: Optional[int] = None,
292
+ page_size: Optional[int] = None,
293
+ include_snapshot_ids: Optional[bool] = None,
294
+ ctx=None, api_client=None) -> str:
314
295
  """
315
296
  Retrieve a list of services from Instana. A use case could be to view the service id, or details,or information of a Service.
316
297
  This tool is useful when you need to get information about all services across your monitored environment,regardless of which application perspective they belong to.
317
- You can filter by service name and other parameters to narrow down results.Use this when you want to see what services exist in your system, understand their IDs .
318
- This is particularly helpful when you need to retrieve service IDs for further analysis or monitoring. For example, use this tool when asked about 'all services',
298
+ You can filter by service name and other parameters to narrow down results.Use this when you want to see what services exist in your system, understand their IDs .
299
+ This is particularly helpful when you need to retrieve service IDs for further analysis or monitoring. For example, use this tool when asked about 'all services',
319
300
  'list services across applications', or when someone wants to 'get service information without application context'. A use case could be to view the service ID of a specific Service.
320
301
 
321
-
302
+
322
303
  Args:
323
304
  name_filter: Name of service to filter by (optional)
324
305
  window_size: Size of time window in milliseconds (optional)
@@ -327,22 +308,22 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
327
308
  page_size: Number of items per page (optional)
328
309
  include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
329
310
  ctx: The MCP context (optional)
330
-
311
+
331
312
  Returns:
332
313
  String containing service names
333
314
  """
334
315
  try:
335
- debug_print(f"get_services called with name_filter={name_filter}")
336
-
316
+ logger.debug(f"get_services called with name_filter={name_filter}")
317
+
337
318
  # Set default time range if not provided
338
319
  if not to_time:
339
320
  to_time = int(datetime.now().timestamp() * 1000)
340
-
321
+
341
322
  if not window_size:
342
323
  window_size = 60 * 60 * 1000 # Default to 1 hour
343
-
324
+
344
325
  # Call the get_services method from the SDK
345
- result = self.app_api.get_services(
326
+ result = api_client.get_services(
346
327
  name_filter=name_filter,
347
328
  window_size=window_size,
348
329
  to=to_time,
@@ -350,20 +331,20 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
350
331
  page_size=page_size,
351
332
  include_snapshot_ids=include_snapshot_ids
352
333
  )
353
-
334
+
354
335
  # Convert the result to a dictionary
355
336
  if hasattr(result, 'to_dict'):
356
337
  result_dict = result.to_dict()
357
338
  else:
358
339
  # If it's already a dict or another format, use it as is
359
340
  result_dict = result
360
-
361
- debug_print(f"Result from get_services: {result_dict}")
362
-
341
+
342
+ logger.debug(f"Result from get_services: {result_dict}")
343
+
363
344
  # Extract labels from the items
364
345
  labels = []
365
346
  items = result_dict.get('items', [])
366
-
347
+
367
348
  for item in items:
368
349
  if isinstance(item, dict):
369
350
  label = item.get('label', '')
@@ -371,21 +352,20 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
371
352
  labels.append(label)
372
353
  elif hasattr(item, 'label'):
373
354
  labels.append(item.label)
374
-
355
+
375
356
  # Sort labels alphabetically and limit to first 10
376
357
  labels.sort()
377
358
  limited_labels = labels[:10]
378
-
359
+
379
360
  # Return as a formatted string that forces display
380
361
  services_text = "Services found in your environment:\n"
381
362
  for i, label in enumerate(limited_labels, 1):
382
363
  services_text += f"{i}. {label}\n"
383
-
364
+
384
365
  services_text += f"\nShowing {len(limited_labels)} out of {len(labels)} total services."
385
-
366
+
386
367
  return services_text
387
-
368
+
388
369
  except Exception as e:
389
- debug_print(f"Error in get_services: {e}")
390
- traceback.print_exc(file=sys.stderr)
391
- return f"Error: Failed to get services: {str(e)}"
370
+ logger.error(f"Error in get_services: {e}", exc_info=True)
371
+ return f"Error: Failed to get services: {e!s}"