mcp-instana 0.1.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.
- mcp_instana-0.1.0.dist-info/LICENSE +201 -0
- mcp_instana-0.1.0.dist-info/METADATA +649 -0
- mcp_instana-0.1.0.dist-info/RECORD +19 -0
- mcp_instana-0.1.0.dist-info/WHEEL +4 -0
- mcp_instana-0.1.0.dist-info/entry_points.txt +3 -0
- src/__init__.py +0 -0
- src/client/What is the sum of queue depth for all q +55 -0
- src/client/application_alert_config_mcp_tools.py +680 -0
- src/client/application_metrics_mcp_tools.py +377 -0
- src/client/application_resources_mcp_tools.py +391 -0
- src/client/events_mcp_tools.py +531 -0
- src/client/infrastructure_analyze_mcp_tools.py +634 -0
- src/client/infrastructure_catalog_mcp_tools.py +624 -0
- src/client/infrastructure_resources_mcp_tools.py +653 -0
- src/client/infrastructure_topology_mcp_tools.py +319 -0
- src/client/instana_client_base.py +93 -0
- src/client/log_alert_configuration_mcp_tools.py +316 -0
- src/client/show the top 5 services with the highest +28 -0
- src/mcp_server.py +343 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application Resources MCP Tools Module
|
|
3
|
+
|
|
4
|
+
This module provides application resources-specific MCP tools for Instana monitoring.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import traceback
|
|
9
|
+
from typing import Dict, Any, Optional, List
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
# Import the necessary classes from the SDK
|
|
13
|
+
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
|
|
17
|
+
except ImportError as e:
|
|
18
|
+
print(f"Error importing Instana SDK: {e}", file=sys.stderr)
|
|
19
|
+
traceback.print_exc(file=sys.stderr)
|
|
20
|
+
raise
|
|
21
|
+
|
|
22
|
+
from .instana_client_base import BaseInstanaClient, register_as_tool
|
|
23
|
+
|
|
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)
|
|
28
|
+
|
|
29
|
+
class ApplicationResourcesMCPTools(BaseInstanaClient):
|
|
30
|
+
"""Tools for application resources in Instana MCP."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, read_token: str, base_url: str):
|
|
33
|
+
"""Initialize the Application Resources MCP tools client."""
|
|
34
|
+
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
|
+
|
|
54
|
+
@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]:
|
|
65
|
+
"""
|
|
66
|
+
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.
|
|
68
|
+
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
|
+
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
|
+
|
|
71
|
+
Args:
|
|
72
|
+
name_filter: Name of service to filter by (optional)
|
|
73
|
+
types: List of endpoint types to filter by (optional)
|
|
74
|
+
technologies: List of technologies to filter by (optional)
|
|
75
|
+
window_size: Size of time window in milliseconds (optional)
|
|
76
|
+
to_time: End timestamp in milliseconds (optional)
|
|
77
|
+
page: Page number for pagination (optional)
|
|
78
|
+
page_size: Number of items per page (optional)
|
|
79
|
+
application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
|
|
80
|
+
ctx: The MCP context (optional)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dictionary containing endpoints data or error information
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
debug_print(f"get_application_endpoints called with name_filter={name_filter}")
|
|
87
|
+
|
|
88
|
+
# Set default time range if not provided
|
|
89
|
+
if not to_time:
|
|
90
|
+
to_time = int(datetime.now().timestamp() * 1000)
|
|
91
|
+
|
|
92
|
+
if not window_size:
|
|
93
|
+
window_size = 60 * 60 * 1000 # Default to 1 hour
|
|
94
|
+
|
|
95
|
+
# Call the get_application_endpoints method from the SDK
|
|
96
|
+
result = self.app_api.get_application_endpoints(
|
|
97
|
+
name_filter=name_filter,
|
|
98
|
+
types=types,
|
|
99
|
+
technologies=technologies,
|
|
100
|
+
window_size=window_size,
|
|
101
|
+
to=to_time,
|
|
102
|
+
page=page,
|
|
103
|
+
page_size=page_size,
|
|
104
|
+
application_boundary_scope=application_boundary_scope
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Convert the result to a dictionary
|
|
108
|
+
if hasattr(result, 'to_dict'):
|
|
109
|
+
result_dict = result.to_dict()
|
|
110
|
+
else:
|
|
111
|
+
# If it's already a dict or another format, use it as is
|
|
112
|
+
result_dict = result
|
|
113
|
+
|
|
114
|
+
debug_print(f"Result from get_application_endpoints: {result_dict}")
|
|
115
|
+
return result_dict
|
|
116
|
+
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
|
+
|
|
121
|
+
@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]:
|
|
131
|
+
"""
|
|
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.
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
name_filter: Name of application/service to filter by (optional)
|
|
140
|
+
window_size: Size of time window in milliseconds (optional)
|
|
141
|
+
to_time: End timestamp in milliseconds (optional)
|
|
142
|
+
page: Page number for pagination (optional)
|
|
143
|
+
page_size: Number of items per page (optional)
|
|
144
|
+
application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
|
|
145
|
+
include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
|
|
146
|
+
ctx: The MCP context (optional)
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Dictionary containing service labels with their IDs and summary information
|
|
150
|
+
"""
|
|
151
|
+
try:
|
|
152
|
+
debug_print(f"get_application_services called with name_filter={name_filter}")
|
|
153
|
+
|
|
154
|
+
# Set default time range if not provided
|
|
155
|
+
if not to_time:
|
|
156
|
+
to_time = int(datetime.now().timestamp() * 1000)
|
|
157
|
+
|
|
158
|
+
if not window_size:
|
|
159
|
+
window_size = 60 * 60 * 1000 # Default to 1 hour
|
|
160
|
+
|
|
161
|
+
# Call the get_application_services method from the SDK
|
|
162
|
+
result = self.app_api.get_application_services(
|
|
163
|
+
name_filter=name_filter,
|
|
164
|
+
window_size=window_size,
|
|
165
|
+
to=to_time,
|
|
166
|
+
page=page,
|
|
167
|
+
page_size=page_size,
|
|
168
|
+
application_boundary_scope=application_boundary_scope,
|
|
169
|
+
include_snapshot_ids=include_snapshot_ids
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Convert the result to a dictionary
|
|
173
|
+
if hasattr(result, 'to_dict'):
|
|
174
|
+
result_dict = result.to_dict()
|
|
175
|
+
else:
|
|
176
|
+
# If it's already a dict or another format, use it as is
|
|
177
|
+
result_dict = result
|
|
178
|
+
|
|
179
|
+
debug_print(f"Result from get_application_services: {result_dict}")
|
|
180
|
+
|
|
181
|
+
# Extract service labels and IDs from the items
|
|
182
|
+
services = []
|
|
183
|
+
service_labels = []
|
|
184
|
+
items = result_dict.get('items', [])
|
|
185
|
+
|
|
186
|
+
for item in items:
|
|
187
|
+
if isinstance(item, dict):
|
|
188
|
+
service_id = item.get('id', '')
|
|
189
|
+
label = item.get('label', '')
|
|
190
|
+
technologies = item.get('technologies', [])
|
|
191
|
+
|
|
192
|
+
if label and service_id:
|
|
193
|
+
service_labels.append(label)
|
|
194
|
+
services.append({
|
|
195
|
+
'id': service_id,
|
|
196
|
+
'label': label,
|
|
197
|
+
'technologies': technologies
|
|
198
|
+
})
|
|
199
|
+
elif hasattr(item, 'label') and hasattr(item, 'id'):
|
|
200
|
+
service_labels.append(item.label)
|
|
201
|
+
services.append({
|
|
202
|
+
'id': item.id,
|
|
203
|
+
'label': item.label,
|
|
204
|
+
'technologies': getattr(item, 'technologies', [])
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
# Sort services by label alphabetically and limit to first 15
|
|
208
|
+
services.sort(key=lambda x: x['label'])
|
|
209
|
+
limited_services = services[:15]
|
|
210
|
+
service_labels = [service['label'] for service in limited_services]
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
"message": f"Found {len(services)} services in application perspectives. Showing first {len(limited_services)}:",
|
|
214
|
+
"service_labels": service_labels,
|
|
215
|
+
"services": limited_services,
|
|
216
|
+
"total_available": len(services),
|
|
217
|
+
"showing": len(limited_services)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
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)}"}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@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]:
|
|
235
|
+
"""
|
|
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
|
+
|
|
242
|
+
Args:
|
|
243
|
+
name_filter: Name of application to filter by (optional)
|
|
244
|
+
window_size: Size of time window in milliseconds (optional)
|
|
245
|
+
to_time: End timestamp in milliseconds (optional)
|
|
246
|
+
page: Page number for pagination (optional)
|
|
247
|
+
page_size: Number of items per page (optional)
|
|
248
|
+
application_boundary_scope: Filter for application scope, e.g., 'INBOUND' or 'ALL' (optional)
|
|
249
|
+
ctx: The MCP context (optional)
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
List of application names
|
|
253
|
+
"""
|
|
254
|
+
try:
|
|
255
|
+
debug_print(f"get_applications called with name_filter={name_filter}")
|
|
256
|
+
|
|
257
|
+
# Set default time range if not provided
|
|
258
|
+
if not to_time:
|
|
259
|
+
to_time = int(datetime.now().timestamp() * 1000)
|
|
260
|
+
|
|
261
|
+
if not window_size:
|
|
262
|
+
window_size = 60 * 60 * 1000 # Default to 1 hour
|
|
263
|
+
|
|
264
|
+
# Call the get_applications method from the SDK
|
|
265
|
+
result = self.app_api.get_applications(
|
|
266
|
+
name_filter=name_filter,
|
|
267
|
+
window_size=window_size,
|
|
268
|
+
to=to_time,
|
|
269
|
+
page=page,
|
|
270
|
+
page_size=page_size,
|
|
271
|
+
application_boundary_scope=application_boundary_scope
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Convert the result to a dictionary
|
|
275
|
+
if hasattr(result, 'to_dict'):
|
|
276
|
+
result_dict = result.to_dict()
|
|
277
|
+
else:
|
|
278
|
+
# If it's already a dict or another format, use it as is
|
|
279
|
+
result_dict = result
|
|
280
|
+
|
|
281
|
+
debug_print(f"Result from get_applications: {result_dict}")
|
|
282
|
+
|
|
283
|
+
# Extract labels from the items
|
|
284
|
+
labels = []
|
|
285
|
+
items = result_dict.get('items', [])
|
|
286
|
+
|
|
287
|
+
for item in items:
|
|
288
|
+
if isinstance(item, dict):
|
|
289
|
+
label = item.get('label', '')
|
|
290
|
+
if label:
|
|
291
|
+
labels.append(label)
|
|
292
|
+
elif hasattr(item, 'label'):
|
|
293
|
+
labels.append(item.label)
|
|
294
|
+
|
|
295
|
+
# Sort labels alphabetically and limit to first 15
|
|
296
|
+
labels.sort()
|
|
297
|
+
return labels[:15]
|
|
298
|
+
|
|
299
|
+
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)}"]
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@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:
|
|
314
|
+
"""
|
|
315
|
+
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
|
+
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',
|
|
319
|
+
'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
|
+
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
name_filter: Name of service to filter by (optional)
|
|
324
|
+
window_size: Size of time window in milliseconds (optional)
|
|
325
|
+
to_time: End timestamp in milliseconds (optional)
|
|
326
|
+
page: Page number for pagination (optional)
|
|
327
|
+
page_size: Number of items per page (optional)
|
|
328
|
+
include_snapshot_ids: Whether to include snapshot IDs in the results (optional)
|
|
329
|
+
ctx: The MCP context (optional)
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
String containing service names
|
|
333
|
+
"""
|
|
334
|
+
try:
|
|
335
|
+
debug_print(f"get_services called with name_filter={name_filter}")
|
|
336
|
+
|
|
337
|
+
# Set default time range if not provided
|
|
338
|
+
if not to_time:
|
|
339
|
+
to_time = int(datetime.now().timestamp() * 1000)
|
|
340
|
+
|
|
341
|
+
if not window_size:
|
|
342
|
+
window_size = 60 * 60 * 1000 # Default to 1 hour
|
|
343
|
+
|
|
344
|
+
# Call the get_services method from the SDK
|
|
345
|
+
result = self.app_api.get_services(
|
|
346
|
+
name_filter=name_filter,
|
|
347
|
+
window_size=window_size,
|
|
348
|
+
to=to_time,
|
|
349
|
+
page=page,
|
|
350
|
+
page_size=page_size,
|
|
351
|
+
include_snapshot_ids=include_snapshot_ids
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Convert the result to a dictionary
|
|
355
|
+
if hasattr(result, 'to_dict'):
|
|
356
|
+
result_dict = result.to_dict()
|
|
357
|
+
else:
|
|
358
|
+
# If it's already a dict or another format, use it as is
|
|
359
|
+
result_dict = result
|
|
360
|
+
|
|
361
|
+
debug_print(f"Result from get_services: {result_dict}")
|
|
362
|
+
|
|
363
|
+
# Extract labels from the items
|
|
364
|
+
labels = []
|
|
365
|
+
items = result_dict.get('items', [])
|
|
366
|
+
|
|
367
|
+
for item in items:
|
|
368
|
+
if isinstance(item, dict):
|
|
369
|
+
label = item.get('label', '')
|
|
370
|
+
if label:
|
|
371
|
+
labels.append(label)
|
|
372
|
+
elif hasattr(item, 'label'):
|
|
373
|
+
labels.append(item.label)
|
|
374
|
+
|
|
375
|
+
# Sort labels alphabetically and limit to first 10
|
|
376
|
+
labels.sort()
|
|
377
|
+
limited_labels = labels[:10]
|
|
378
|
+
|
|
379
|
+
# Return as a formatted string that forces display
|
|
380
|
+
services_text = "Services found in your environment:\n"
|
|
381
|
+
for i, label in enumerate(limited_labels, 1):
|
|
382
|
+
services_text += f"{i}. {label}\n"
|
|
383
|
+
|
|
384
|
+
services_text += f"\nShowing {len(limited_labels)} out of {len(labels)} total services."
|
|
385
|
+
|
|
386
|
+
return services_text
|
|
387
|
+
|
|
388
|
+
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)}"
|