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
@@ -36,392 +36,441 @@ class ApplicationResourcesMCPTools(BaseInstanaClient):
36
36
  """Initialize the Application Resources MCP tools client."""
37
37
  super().__init__(read_token=read_token, base_url=base_url)
38
38
 
39
- @register_as_tool(
40
- title="Get Application Endpoints",
41
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
42
- )
43
- @with_header_auth(ApplicationResourcesApi)
44
- async def get_application_endpoints(self,
45
- app_id: Optional[str] = None,
46
- service_id: Optional[str] = None,
47
- endpoint_id: Optional[str] = None,
48
- name_filter: Optional[str] = None,
49
- types: Optional[List[str]] = None,
50
- technologies: Optional[List[str]] = None,
51
- window_size: Optional[int] = None,
52
- to_time: Optional[int] = None,
53
- page: Optional[int] = None,
54
- page_size: Optional[int] = None,
55
- application_boundary_scope: Optional[str] = None,
56
- ctx=None, api_client=None) -> Dict[str, Any]:
57
- """
58
- 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.
59
- 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.
60
- 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.
61
- 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'.
62
-
63
- Args:
64
- app_id: Application ID to filter endpoints by application (optional)
65
- service_id: Service ID to filter endpoints by service (optional)
66
- endpoint_id: Endpoint ID to get a specific endpoint (optional)
67
- name_filter: Name of service to filter by (optional)
68
- types: List of endpoint types to filter by (optional)
69
- technologies: List of technologies to filter by (optional)
70
- window_size: Size of time window in milliseconds (optional)
71
- to_time: End timestamp in milliseconds (optional)
72
- page: Page number for pagination (optional)
73
- page_size: Number of items per page (optional)
74
- application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
75
- ctx: The MCP context (optional)
76
-
77
- Returns:
78
- Dictionary containing endpoints data or error information
79
- """
80
- try:
81
- logger.debug(f"get_application_endpoints called with name_filter={name_filter}")
82
-
83
- # Set default time range if not provided
84
- if not to_time:
85
- to_time = int(datetime.now().timestamp() * 1000)
86
-
87
- if not window_size:
88
- window_size = 60 * 60 * 1000 # Default to 1 hour
89
-
90
- # Call the get_application_endpoints method from the SDK
91
- result = api_client.get_application_endpoints(
92
- app_id=app_id,
93
- service_id=service_id,
94
- endpoint_id=endpoint_id,
95
- name_filter=name_filter,
96
- types=types,
97
- technologies=technologies,
98
- window_size=window_size,
99
- to=to_time,
100
- page=page,
101
- page_size=page_size,
102
- application_boundary_scope=application_boundary_scope
103
- )
104
-
105
- # Convert the result to a dictionary
106
- if hasattr(result, 'to_dict'):
107
- result_dict = result.to_dict()
108
- else:
109
- # If it's already a dict or another format, use it as is
110
- result_dict = result
111
-
112
- logger.debug(f"Result from get_application_endpoints: {result_dict}")
113
-
114
- # Check if we got a single Endpoint or EndpointResult (list)
115
- # Single Endpoint is returned when app_id, service_id, AND endpoint_id are all provided
116
- if app_id and service_id and endpoint_id:
117
- # Single Endpoint object returned
118
- return {
119
- "type": "single_endpoint",
120
- "endpoint": result_dict
121
- }
122
- else:
123
- # EndpointResult (list) returned
124
- return {
125
- "type": "endpoint_list",
126
- "data": result_dict
127
- }
128
- except Exception as e:
129
- logger.error(f"Error in get_application_endpoints: {e}", exc_info=True)
130
- return {"error": f"Failed to get application endpoints: {e!s}"}
131
-
132
- @register_as_tool(
133
- title="Get Application Services",
134
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
135
- )
136
- @with_header_auth(ApplicationResourcesApi)
137
- async def get_application_services(self,
138
- app_id: Optional[str] = None,
139
- service_id: Optional[str] = None,
140
- name_filter: Optional[str] = None,
141
- window_size: Optional[int] = None,
142
- to_time: Optional[int] = None,
143
- page: Optional[int] = None,
144
- page_size: Optional[int] = None,
145
- application_boundary_scope: Optional[str] = None,
146
- include_snapshot_ids: Optional[bool] = None,
147
- ctx=None, api_client=None) -> Dict[str, Any]:
148
- """
149
- 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.
150
- 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,
151
- 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.
152
- 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.
153
-
154
- Args:
155
- app_id: Application ID to filter services by application (optional)
156
- service_id: Service ID to filter specific service (optional)
157
- name_filter: Name of application/service to filter by (optional)
158
- window_size: Size of time window in milliseconds (optional)
159
- to_time: End timestamp in milliseconds (optional)
160
- page: Page number for pagination (optional)
161
- page_size: Number of items per page (optional)
162
- application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
163
- include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
164
- ctx: The MCP context (optional)
165
-
166
- Returns:
167
- Dictionary containing service labels with their IDs and summary information
168
- """
169
- try:
170
- logger.debug(f"get_application_services called with name_filter={name_filter}")
171
-
172
- # Set default time range if not provided
173
- if not to_time:
174
- to_time = int(datetime.now().timestamp() * 1000)
175
-
176
- if not window_size:
177
- window_size = 60 * 60 * 1000 # Default to 1 hour
178
-
179
- # Call the get_application_services method from the SDK
180
- result = api_client.get_application_services(
181
- app_id=app_id,
182
- service_id=service_id,
183
- name_filter=name_filter,
184
- window_size=window_size,
185
- to=to_time,
186
- page=page,
187
- page_size=page_size,
188
- application_boundary_scope=application_boundary_scope,
189
- include_snapshot_ids=include_snapshot_ids
190
- )
191
-
192
- # Convert the result to a dictionary
193
- if hasattr(result, 'to_dict'):
194
- result_dict = result.to_dict()
195
- else:
196
- # If it's already a dict or another format, use it as is
197
- result_dict = result
198
-
199
- logger.debug(f"Result from get_application_services: {result_dict}")
200
-
201
- # Check if we got a single Service or ServiceResult (list)
202
- # Single Service is returned when both app_id AND service_id are provided
203
- if app_id and service_id:
204
- # Single Service object returned
205
- return {
206
- "type": "single_service",
207
- "service": result_dict
208
- }
209
-
210
- # ServiceResult (list) returned - extract and format the data
211
- # Extract service labels and IDs from the items
212
- services = []
213
- service_labels = []
214
- items = result_dict.get('items', [])
215
-
216
- for item in items:
217
- if isinstance(item, dict):
218
- svc_id = item.get('id', '')
219
- label = item.get('label', '')
220
- technologies = item.get('technologies', [])
221
-
222
- if label and svc_id:
223
- service_labels.append(label)
224
- services.append({
225
- 'id': svc_id,
226
- 'label': label,
227
- 'technologies': technologies
228
- })
229
- elif hasattr(item, 'label') and hasattr(item, 'id'):
230
- service_labels.append(item.label)
231
- services.append({
232
- 'id': item.id,
233
- 'label': item.label,
234
- 'technologies': getattr(item, 'technologies', [])
235
- })
236
-
237
- # Sort services by label alphabetically and limit to first 15
238
- services.sort(key=lambda x: x['label'])
239
- limited_services = services[:15]
240
- service_labels = [service['label'] for service in limited_services]
241
-
242
- return {
243
- "type": "service_list",
244
- "message": f"Found {len(services)} services in application perspectives. Showing first {len(limited_services)}:",
245
- "service_labels": service_labels,
246
- "services": limited_services,
247
- "total_available": len(services),
248
- "showing": len(limited_services)
249
- }
250
-
251
- except Exception as e:
252
- logger.error(f"Error in get_application_services: {e}", exc_info=True)
253
- return {"error": f"Failed to get application services: {e!s}"}
254
-
255
-
256
- @register_as_tool(
257
- title="Get Applications",
258
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
259
- )
260
39
  @with_header_auth(ApplicationResourcesApi)
261
- async def get_applications(self,
262
- name_filter: Optional[str] = None,
263
- window_size: Optional[int] = None,
264
- to_time: Optional[int] = None,
265
- page: Optional[int] = None,
266
- page_size: Optional[int] = None,
267
- application_boundary_scope: Optional[str] = None,
268
- ctx=None, api_client=None) -> List[str]:
40
+ async def _get_applications_internal(
41
+ self,
42
+ name_filter: Optional[str] = None,
43
+ window_size: Optional[int] = None,
44
+ to_time: Optional[int] = None,
45
+ ctx=None,
46
+ api_client=None
47
+ ) -> Dict[str, Any]:
269
48
  """
270
- 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.
271
- 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,
272
- 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.
273
- 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'
274
- or 'get details about an application'.
49
+ Internal method to get applications from Application Resources API.
50
+ Used by smart router for application name resolution.
275
51
 
276
52
  Args:
277
- name_filter: Name of application to filter by (optional)
278
- window_size: Size of time window in milliseconds (optional)
279
- to_time: End timestamp in milliseconds (optional)
280
- page: Page number for pagination (optional)
281
- page_size: Number of items per page (optional)
282
- application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
283
- ctx: The MCP context (optional)
53
+ name_filter: Name of application to filter by
54
+ window_size: Size of time window in milliseconds
55
+ to_time: End timestamp in milliseconds
56
+ ctx: The MCP context
57
+ api_client: API client (injected by decorator)
284
58
 
285
59
  Returns:
286
- List of application names
60
+ Dictionary containing applications data
287
61
  """
288
62
  try:
289
- logger.debug(f"get_applications called with name_filter={name_filter}")
290
-
291
- # Set default time range if not provided
292
- if not to_time:
293
- to_time = int(datetime.now().timestamp() * 1000)
294
-
295
- if not window_size:
296
- window_size = 60 * 60 * 1000 # Default to 1 hour
63
+ logger.debug(f"_get_applications_internal called with name_filter={name_filter}")
297
64
 
298
65
  # Call the get_applications method from the SDK
299
66
  result = api_client.get_applications(
300
67
  name_filter=name_filter,
301
68
  window_size=window_size,
302
69
  to=to_time,
303
- page=page,
304
- page_size=page_size,
305
- application_boundary_scope=application_boundary_scope
70
+ page=None,
71
+ page_size=None,
72
+ application_boundary_scope=None
306
73
  )
307
74
 
308
75
  # Convert the result to a dictionary
309
76
  if hasattr(result, 'to_dict'):
310
77
  result_dict = result.to_dict()
311
78
  else:
312
- # If it's already a dict or another format, use it as is
313
79
  result_dict = result
314
80
 
315
- logger.debug(f"Result from get_applications: {result_dict}")
316
-
317
- # Extract labels from the items
318
- labels = []
319
- items = result_dict.get('items', [])
320
-
321
- for item in items:
322
- if isinstance(item, dict):
323
- label = item.get('label', '')
324
- if label:
325
- labels.append(label)
326
- elif hasattr(item, 'label'):
327
- labels.append(item.label)
328
-
329
- # Sort labels alphabetically and limit to first 15
330
- labels.sort()
331
- return labels[:15]
332
-
333
- except Exception as e:
334
- logger.error(f"Error in get_applications: {e}", exc_info=True)
335
- return [f"Error: Failed to get applications: {e!s}"]
336
-
337
-
338
- @register_as_tool(
339
- title="Get Services",
340
- annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
341
- )
342
- @with_header_auth(ApplicationResourcesApi)
343
- async def get_services(self,
344
- name_filter: Optional[str] = None,
345
- window_size: Optional[int] = None,
346
- to_time: Optional[int] = None,
347
- page: Optional[int] = None,
348
- page_size: Optional[int] = None,
349
- include_snapshot_ids: Optional[bool] = None,
350
- ctx=None, api_client=None) -> str:
351
- """
352
- Retrieve a list of services from Instana. A use case could be to view the service id, or details,or information of a Service.
353
- 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.
354
- 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 .
355
- 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',
356
- '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.
357
-
358
-
359
- Args:
360
- name_filter: Name of service to filter by (optional)
361
- window_size: Size of time window in milliseconds (optional)
362
- to_time: End timestamp in milliseconds (optional)
363
- page: Page number for pagination (optional)
364
- page_size: Number of items per page (optional)
365
- include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
366
- ctx: The MCP context (optional)
367
-
368
- Returns:
369
- String containing service names
370
- """
371
- try:
372
- logger.debug(f"get_services called with name_filter={name_filter}")
373
-
374
- # Set default time range if not provided
375
- if not to_time:
376
- to_time = int(datetime.now().timestamp() * 1000)
377
-
378
- if not window_size:
379
- window_size = 60 * 60 * 1000 # Default to 1 hour
380
-
381
- # Call the get_services method from the SDK
382
- result = api_client.get_services(
383
- name_filter=name_filter,
384
- window_size=window_size,
385
- to=to_time,
386
- page=page,
387
- page_size=page_size,
388
- include_snapshot_ids=include_snapshot_ids
389
- )
390
-
391
- # Convert the result to a dictionary
392
- if hasattr(result, 'to_dict'):
393
- result_dict = result.to_dict()
394
- else:
395
- # If it's already a dict or another format, use it as is
396
- result_dict = result
397
-
398
- logger.debug(f"Result from get_services: {result_dict}")
399
-
400
- # Extract labels from the items
401
- labels = []
402
- items = result_dict.get('items', [])
403
-
404
- for item in items:
405
- if isinstance(item, dict):
406
- label = item.get('label', '')
407
- if label:
408
- labels.append(label)
409
- elif hasattr(item, 'label'):
410
- labels.append(item.label)
411
-
412
- # Sort labels alphabetically and limit to first 10
413
- labels.sort()
414
- limited_labels = labels[:10]
415
-
416
- # Return as a formatted string that forces display
417
- services_text = "Services found in your environment:\n"
418
- for i, label in enumerate(limited_labels, 1):
419
- services_text += f"{i}. {label}\n"
420
-
421
- services_text += f"\nShowing {len(limited_labels)} out of {len(labels)} total services."
422
-
423
- return services_text
81
+ logger.debug(f"Result from _get_applications_internal: {result_dict}")
82
+ return result_dict
424
83
 
425
84
  except Exception as e:
426
- logger.error(f"Error in get_services: {e}", exc_info=True)
427
- return f"Error: Failed to get services: {e!s}"
85
+ logger.error(f"Error in _get_applications_internal: {e}", exc_info=True)
86
+ return {"error": f"Failed to get applications: {e!s}"}
87
+
88
+ # @register_as_tool(
89
+ # title="Get Application Endpoints",
90
+ # annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
91
+ # )
92
+ # @with_header_auth(ApplicationResourcesApi)
93
+ # async def get_application_endpoints(self,
94
+ # app_id: Optional[str] = None,
95
+ # service_id: Optional[str] = None,
96
+ # endpoint_id: Optional[str] = None,
97
+ # name_filter: Optional[str] = None,
98
+ # types: Optional[List[str]] = None,
99
+ # technologies: Optional[List[str]] = None,
100
+ # window_size: Optional[int] = None,
101
+ # to_time: Optional[int] = None,
102
+ # page: Optional[int] = None,
103
+ # page_size: Optional[int] = None,
104
+ # application_boundary_scope: Optional[str] = None,
105
+ # ctx=None, api_client=None) -> Dict[str, Any]:
106
+ # """
107
+ # 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.
108
+ # 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.
109
+ # 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.
110
+ # 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'.
111
+
112
+ # Args:
113
+ # app_id: Application ID to filter endpoints by application (optional)
114
+ # service_id: Service ID to filter endpoints by service (optional)
115
+ # endpoint_id: Endpoint ID to get a specific endpoint (optional)
116
+ # name_filter: Name of service to filter by (optional)
117
+ # types: List of endpoint types to filter by (optional)
118
+ # technologies: List of technologies to filter by (optional)
119
+ # window_size: Size of time window in milliseconds (optional)
120
+ # to_time: End timestamp in milliseconds (optional)
121
+ # page: Page number for pagination (optional)
122
+ # page_size: Number of items per page (optional)
123
+ # application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
124
+ # ctx: The MCP context (optional)
125
+
126
+ # Returns:
127
+ # Dictionary containing endpoints data or error information
128
+ # """
129
+ # try:
130
+ # logger.debug(f"get_application_endpoints called with name_filter={name_filter}")
131
+
132
+ # # Set default time range if not provided
133
+ # if not to_time:
134
+ # to_time = int(datetime.now().timestamp() * 1000)
135
+
136
+ # if not window_size:
137
+ # window_size = 60 * 60 * 1000 # Default to 1 hour
138
+
139
+ # # Call the get_application_endpoints method from the SDK
140
+ # result = api_client.get_application_endpoints(
141
+ # app_id=app_id,
142
+ # service_id=service_id,
143
+ # endpoint_id=endpoint_id,
144
+ # name_filter=name_filter,
145
+ # types=types,
146
+ # technologies=technologies,
147
+ # window_size=window_size,
148
+ # to=to_time,
149
+ # page=page,
150
+ # page_size=page_size,
151
+ # application_boundary_scope=application_boundary_scope
152
+ # )
153
+
154
+ # # Convert the result to a dictionary
155
+ # if hasattr(result, 'to_dict'):
156
+ # result_dict = result.to_dict()
157
+ # else:
158
+ # # If it's already a dict or another format, use it as is
159
+ # result_dict = result
160
+
161
+ # logger.debug(f"Result from get_application_endpoints: {result_dict}")
162
+
163
+ # # Check if we got a single Endpoint or EndpointResult (list)
164
+ # # Single Endpoint is returned when app_id, service_id, AND endpoint_id are all provided
165
+ # if app_id and service_id and endpoint_id:
166
+ # # Single Endpoint object returned
167
+ # return {
168
+ # "type": "single_endpoint",
169
+ # "endpoint": result_dict
170
+ # }
171
+ # else:
172
+ # # EndpointResult (list) returned
173
+ # return {
174
+ # "type": "endpoint_list",
175
+ # "data": result_dict
176
+ # }
177
+ # except Exception as e:
178
+ # logger.error(f"Error in get_application_endpoints: {e}", exc_info=True)
179
+ # return {"error": f"Failed to get application endpoints: {e!s}"}
180
+
181
+ # @register_as_tool(
182
+ # title="Get Application Services",
183
+ # annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
184
+ # )
185
+ # @with_header_auth(ApplicationResourcesApi)
186
+ # async def get_application_services(self,
187
+ # app_id: Optional[str] = None,
188
+ # service_id: Optional[str] = None,
189
+ # name_filter: Optional[str] = None,
190
+ # window_size: Optional[int] = None,
191
+ # to_time: Optional[int] = None,
192
+ # page: Optional[int] = None,
193
+ # page_size: Optional[int] = None,
194
+ # application_boundary_scope: Optional[str] = None,
195
+ # include_snapshot_ids: Optional[bool] = None,
196
+ # ctx=None, api_client=None) -> Dict[str, Any]:
197
+ # """
198
+ # 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.
199
+ # 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,
200
+ # 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.
201
+ # 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.
202
+
203
+ # Args:
204
+ # app_id: Application ID to filter services by application (optional)
205
+ # service_id: Service ID to filter specific service (optional)
206
+ # name_filter: Name of application/service to filter by (optional)
207
+ # window_size: Size of time window in milliseconds (optional)
208
+ # to_time: End timestamp in milliseconds (optional)
209
+ # page: Page number for pagination (optional)
210
+ # page_size: Number of items per page (optional)
211
+ # application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
212
+ # include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
213
+ # ctx: The MCP context (optional)
214
+
215
+ # Returns:
216
+ # Dictionary containing service labels with their IDs and summary information
217
+ # """
218
+ # try:
219
+ # logger.debug(f"get_application_services called with name_filter={name_filter}")
220
+
221
+ # # Set default time range if not provided
222
+ # if not to_time:
223
+ # to_time = int(datetime.now().timestamp() * 1000)
224
+
225
+ # if not window_size:
226
+ # window_size = 60 * 60 * 1000 # Default to 1 hour
227
+
228
+ # # Call the get_application_services method from the SDK
229
+ # result = api_client.get_application_services(
230
+ # app_id=app_id,
231
+ # service_id=service_id,
232
+ # name_filter=name_filter,
233
+ # window_size=window_size,
234
+ # to=to_time,
235
+ # page=page,
236
+ # page_size=page_size,
237
+ # application_boundary_scope=application_boundary_scope,
238
+ # include_snapshot_ids=include_snapshot_ids
239
+ # )
240
+
241
+ # # Convert the result to a dictionary
242
+ # if hasattr(result, 'to_dict'):
243
+ # result_dict = result.to_dict()
244
+ # else:
245
+ # # If it's already a dict or another format, use it as is
246
+ # result_dict = result
247
+
248
+ # logger.debug(f"Result from get_application_services: {result_dict}")
249
+
250
+ # # Check if we got a single Service or ServiceResult (list)
251
+ # # Single Service is returned when both app_id AND service_id are provided
252
+ # if app_id and service_id:
253
+ # # Single Service object returned
254
+ # return {
255
+ # "type": "single_service",
256
+ # "service": result_dict
257
+ # }
258
+
259
+ # # ServiceResult (list) returned - extract and format the data
260
+ # # Extract service labels and IDs from the items
261
+ # services = []
262
+ # service_labels = []
263
+ # items = result_dict.get('items', [])
264
+
265
+ # for item in items:
266
+ # if isinstance(item, dict):
267
+ # svc_id = item.get('id', '')
268
+ # label = item.get('label', '')
269
+ # technologies = item.get('technologies', [])
270
+
271
+ # if label and svc_id:
272
+ # service_labels.append(label)
273
+ # services.append({
274
+ # 'id': svc_id,
275
+ # 'label': label,
276
+ # 'technologies': technologies
277
+ # })
278
+ # elif hasattr(item, 'label') and hasattr(item, 'id'):
279
+ # service_labels.append(item.label)
280
+ # services.append({
281
+ # 'id': item.id,
282
+ # 'label': item.label,
283
+ # 'technologies': getattr(item, 'technologies', [])
284
+ # })
285
+
286
+ # # Sort services by label alphabetically and limit to first 15
287
+ # services.sort(key=lambda x: x['label'])
288
+ # limited_services = services[:15]
289
+ # service_labels = [service['label'] for service in limited_services]
290
+
291
+ # return {
292
+ # "type": "service_list",
293
+ # "message": f"Found {len(services)} services in application perspectives. Showing first {len(limited_services)}:",
294
+ # "service_labels": service_labels,
295
+ # "services": limited_services,
296
+ # "total_available": len(services),
297
+ # "showing": len(limited_services)
298
+ # }
299
+
300
+ # except Exception as e:
301
+ # logger.error(f"Error in get_application_services: {e}", exc_info=True)
302
+ # return {"error": f"Failed to get application services: {e!s}"}
303
+
304
+
305
+ # @register_as_tool(
306
+ # title="Get Applications",
307
+ # annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
308
+ # )
309
+ # @with_header_auth(ApplicationResourcesApi)
310
+ # async def get_applications(self,
311
+ # name_filter: Optional[str] = None,
312
+ # window_size: Optional[int] = None,
313
+ # to_time: Optional[int] = None,
314
+ # page: Optional[int] = None,
315
+ # page_size: Optional[int] = None,
316
+ # application_boundary_scope: Optional[str] = None,
317
+ # ctx=None, api_client=None) -> List[str]:
318
+ # """
319
+ # 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.
320
+ # 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,
321
+ # 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.
322
+ # 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'
323
+ # or 'get details about an application'.
324
+
325
+ # Args:
326
+ # name_filter: Name of application to filter by (optional)
327
+ # window_size: Size of time window in milliseconds (optional)
328
+ # to_time: End timestamp in milliseconds (optional)
329
+ # page: Page number for pagination (optional)
330
+ # page_size: Number of items per page (optional)
331
+ # application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
332
+ # ctx: The MCP context (optional)
333
+
334
+ # Returns:
335
+ # List of application names
336
+ # """
337
+ # try:
338
+ # logger.debug(f"get_applications called with name_filter={name_filter}")
339
+
340
+ # # Set default time range if not provided
341
+ # if not to_time:
342
+ # to_time = int(datetime.now().timestamp() * 1000)
343
+
344
+ # if not window_size:
345
+ # window_size = 60 * 60 * 1000 # Default to 1 hour
346
+
347
+ # # Call the get_applications method from the SDK
348
+ # result = api_client.get_applications(
349
+ # name_filter=name_filter,
350
+ # window_size=window_size,
351
+ # to=to_time,
352
+ # page=page,
353
+ # page_size=page_size,
354
+ # application_boundary_scope=application_boundary_scope
355
+ # )
356
+
357
+ # # Convert the result to a dictionary
358
+ # if hasattr(result, 'to_dict'):
359
+ # result_dict = result.to_dict()
360
+ # else:
361
+ # # If it's already a dict or another format, use it as is
362
+ # result_dict = result
363
+
364
+ # logger.debug(f"Result from get_applications: {result_dict}")
365
+
366
+ # # Extract labels from the items
367
+ # labels = []
368
+ # items = result_dict.get('items', [])
369
+
370
+ # for item in items:
371
+ # if isinstance(item, dict):
372
+ # label = item.get('label', '')
373
+ # if label:
374
+ # labels.append(label)
375
+ # elif hasattr(item, 'label'):
376
+ # labels.append(item.label)
377
+
378
+ # # Sort labels alphabetically and limit to first 15
379
+ # labels.sort()
380
+ # return labels[:15]
381
+
382
+ # except Exception as e:
383
+ # logger.error(f"Error in get_applications: {e}", exc_info=True)
384
+ # return [f"Error: Failed to get applications: {e!s}"]
385
+
386
+
387
+ # @register_as_tool(
388
+ # title="Get Services",
389
+ # annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
390
+ # )
391
+ # @with_header_auth(ApplicationResourcesApi)
392
+ # async def get_services(self,
393
+ # name_filter: Optional[str] = None,
394
+ # window_size: Optional[int] = None,
395
+ # to_time: Optional[int] = None,
396
+ # page: Optional[int] = None,
397
+ # page_size: Optional[int] = None,
398
+ # include_snapshot_ids: Optional[bool] = None,
399
+ # ctx=None, api_client=None) -> str:
400
+ # """
401
+ # Retrieve a list of services from Instana. A use case could be to view the service id, or details,or information of a Service.
402
+ # 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.
403
+ # 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 .
404
+ # 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',
405
+ # '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.
406
+
407
+
408
+ # Args:
409
+ # name_filter: Name of service to filter by (optional)
410
+ # window_size: Size of time window in milliseconds (optional)
411
+ # to_time: End timestamp in milliseconds (optional)
412
+ # page: Page number for pagination (optional)
413
+ # page_size: Number of items per page (optional)
414
+ # include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
415
+ # ctx: The MCP context (optional)
416
+
417
+ # Returns:
418
+ # String containing service names
419
+ # """
420
+ # try:
421
+ # logger.debug(f"get_services called with name_filter={name_filter}")
422
+
423
+ # # Set default time range if not provided
424
+ # if not to_time:
425
+ # to_time = int(datetime.now().timestamp() * 1000)
426
+
427
+ # if not window_size:
428
+ # window_size = 60 * 60 * 1000 # Default to 1 hour
429
+
430
+ # # Call the get_services method from the SDK
431
+ # result = api_client.get_services(
432
+ # name_filter=name_filter,
433
+ # window_size=window_size,
434
+ # to=to_time,
435
+ # page=page,
436
+ # page_size=page_size,
437
+ # include_snapshot_ids=include_snapshot_ids
438
+ # )
439
+
440
+ # # Convert the result to a dictionary
441
+ # if hasattr(result, 'to_dict'):
442
+ # result_dict = result.to_dict()
443
+ # else:
444
+ # # If it's already a dict or another format, use it as is
445
+ # result_dict = result
446
+
447
+ # logger.debug(f"Result from get_services: {result_dict}")
448
+
449
+ # # Extract labels from the items
450
+ # labels = []
451
+ # items = result_dict.get('items', [])
452
+
453
+ # for item in items:
454
+ # if isinstance(item, dict):
455
+ # label = item.get('label', '')
456
+ # if label:
457
+ # labels.append(label)
458
+ # elif hasattr(item, 'label'):
459
+ # labels.append(item.label)
460
+
461
+ # # Sort labels alphabetically and limit to first 10
462
+ # labels.sort()
463
+ # limited_labels = labels[:10]
464
+
465
+ # # Return as a formatted string that forces display
466
+ # services_text = "Services found in your environment:\n"
467
+ # for i, label in enumerate(limited_labels, 1):
468
+ # services_text += f"{i}. {label}\n"
469
+
470
+ # services_text += f"\nShowing {len(limited_labels)} out of {len(labels)} total services."
471
+
472
+ # return services_text
473
+
474
+ # except Exception as e:
475
+ # logger.error(f"Error in get_services: {e}", exc_info=True)
476
+ # return f"Error: Failed to get services: {e!s}"