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.
- {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/METADATA +179 -120
- {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/RECORD +28 -21
- src/application/application_alert_config.py +397 -146
- src/application/application_analyze.py +597 -597
- src/application/application_call_group.py +528 -0
- src/application/application_catalog.py +0 -8
- src/application/application_global_alert_config.py +255 -38
- src/application/application_metrics.py +377 -237
- src/application/application_resources.py +414 -365
- src/application/application_settings.py +605 -1651
- src/application/application_topology.py +62 -62
- src/core/custom_dashboard_smart_router_tool.py +135 -0
- src/core/server.py +92 -119
- src/core/smart_router_tool.py +574 -0
- src/core/utils.py +17 -8
- src/custom_dashboard/custom_dashboard_tools.py +422 -0
- src/infrastructure/elicitation_handler.py +338 -0
- src/infrastructure/entity_registry.py +329 -0
- src/infrastructure/infrastructure_analyze_new.py +600 -0
- src/infrastructure/{infrastructure_analyze.py → infrastructure_analyze_old.py} +1 -16
- src/infrastructure/infrastructure_catalog.py +7 -28
- src/infrastructure/infrastructure_metrics.py +93 -17
- src/infrastructure/infrastructure_resources.py +5 -20
- src/infrastructure/infrastructure_topology.py +2 -8
- src/prompts/application/application_settings.py +58 -0
- {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/WHEEL +0 -0
- {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/entry_points.txt +0 -0
- {mcp_instana-0.6.2.dist-info → mcp_instana-0.7.0.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -55,65 +55,65 @@ class ApplicationTopologyMCPTools(BaseInstanaClient):
|
|
|
55
55
|
logger.error(f"Error initializing ApplicationTopologyMCPTools: {e}", exc_info=True)
|
|
56
56
|
raise
|
|
57
57
|
|
|
58
|
-
@register_as_tool(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
async def get_application_topology(self,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
58
|
+
# @register_as_tool(
|
|
59
|
+
# title="Get Application Topology",
|
|
60
|
+
# annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False)
|
|
61
|
+
# )
|
|
62
|
+
# async def get_application_topology(self,
|
|
63
|
+
# window_size: Optional[int] = None,
|
|
64
|
+
# to_timestamp: Optional[int] = None,
|
|
65
|
+
# application_id: Optional[str] = None,
|
|
66
|
+
# application_boundary_scope: Optional[str] = None,
|
|
67
|
+
# ctx = None) -> Dict[str, Any]:
|
|
68
|
+
# """
|
|
69
|
+
# Get the service topology from Instana Server.
|
|
70
|
+
# This tool retrieves services and connections (call paths) between them for calls in the scope given by the parameters.
|
|
71
|
+
|
|
72
|
+
# Args:
|
|
73
|
+
# window_size: Size of time window in milliseconds
|
|
74
|
+
# to_timestamp: Timestamp since Unix Epoch in milliseconds of the end of the time window
|
|
75
|
+
# application_id: Filter by application ID
|
|
76
|
+
# application_boundary_scope: Filter by application scope, i.e., INBOUND or ALL. The default value is INBOUND.
|
|
77
|
+
# ctx: Context information
|
|
78
|
+
|
|
79
|
+
# Returns:
|
|
80
|
+
# A dictionary containing the service topology data
|
|
81
|
+
# """
|
|
82
|
+
|
|
83
|
+
# try:
|
|
84
|
+
# logger.debug("Fetching service topology data")
|
|
85
|
+
|
|
86
|
+
# # Set default values if not provided
|
|
87
|
+
# if not to_timestamp:
|
|
88
|
+
# to_timestamp = int(datetime.now().timestamp() * 1000)
|
|
89
|
+
|
|
90
|
+
# if not window_size:
|
|
91
|
+
# window_size = 3600000 # Default to 1 hour in milliseconds
|
|
92
|
+
|
|
93
|
+
# # Call the API with raw JSON response to avoid Pydantic validation issues
|
|
94
|
+
# # Note: The SDK expects parameters in camelCase, but we use snake_case in Python
|
|
95
|
+
# # The SDK will handle the conversion
|
|
96
|
+
# result = self.topology_api.get_services_map_without_preload_content(
|
|
97
|
+
# window_size=window_size,
|
|
98
|
+
# to=to_timestamp,
|
|
99
|
+
# application_id=application_id,
|
|
100
|
+
# application_boundary_scope=application_boundary_scope
|
|
101
|
+
# )
|
|
102
|
+
|
|
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}
|
|
116
|
+
|
|
117
|
+
# except Exception as e:
|
|
118
|
+
# logger.error(f"Error in get_application_topology: {e}", exc_info=True)
|
|
119
|
+
# return {"error": f"Failed to get application topology: {e!s}"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom Dashboard Smart Router Tool
|
|
3
|
+
|
|
4
|
+
This module provides a unified MCP tool that routes queries to the appropriate
|
|
5
|
+
custom dashboard-specific tools for Instana monitoring.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
from mcp.types import ToolAnnotations
|
|
12
|
+
|
|
13
|
+
from src.core.utils import BaseInstanaClient, register_as_tool
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CustomDashboardSmartRouterMCPTool(BaseInstanaClient):
|
|
19
|
+
"""
|
|
20
|
+
Smart router that routes queries to Custom Dashboard tools.
|
|
21
|
+
The LLM agent determines the appropriate operation based on query understanding.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, read_token: str, base_url: str):
|
|
25
|
+
"""Initialize the Custom Dashboard Smart Router MCP tool."""
|
|
26
|
+
super().__init__(read_token=read_token, base_url=base_url)
|
|
27
|
+
|
|
28
|
+
# Initialize the custom dashboard tool client
|
|
29
|
+
from src.custom_dashboard.custom_dashboard_tools import CustomDashboardMCPTools
|
|
30
|
+
|
|
31
|
+
self.dashboard_client = CustomDashboardMCPTools(read_token, base_url)
|
|
32
|
+
|
|
33
|
+
logger.info("Custom Dashboard Smart Router initialized")
|
|
34
|
+
|
|
35
|
+
@register_as_tool(
|
|
36
|
+
title="Manage Instana Custom Dashboards",
|
|
37
|
+
annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False)
|
|
38
|
+
)
|
|
39
|
+
async def manage_custom_dashboards(
|
|
40
|
+
self,
|
|
41
|
+
operation: str,
|
|
42
|
+
params: Optional[Dict[str, Any]] = None,
|
|
43
|
+
ctx=None
|
|
44
|
+
) -> Dict[str, Any]:
|
|
45
|
+
"""
|
|
46
|
+
Unified Instana custom dashboard manager for CRUD operations.
|
|
47
|
+
|
|
48
|
+
Operations:
|
|
49
|
+
- "get_all": Get all custom dashboards
|
|
50
|
+
- "get": Get a specific dashboard by ID
|
|
51
|
+
- "create": Create a new custom dashboard
|
|
52
|
+
- "update": Update an existing custom dashboard
|
|
53
|
+
- "delete": Delete a custom dashboard
|
|
54
|
+
- "get_shareable_users": Get shareable users for a dashboard
|
|
55
|
+
- "get_shareable_api_tokens": Get shareable API tokens for a dashboard
|
|
56
|
+
|
|
57
|
+
Parameters (params dict):
|
|
58
|
+
- dashboard_id: Dashboard ID (required for get, update, delete, get_shareable_users, get_shareable_api_tokens)
|
|
59
|
+
- custom_dashboard: Dashboard configuration payload (required for create, update)
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
operation: Operation to perform
|
|
63
|
+
params: Operation-specific parameters (optional)
|
|
64
|
+
ctx: MCP context (internal)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Dictionary with results from the appropriate tool
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
# Get all dashboards
|
|
71
|
+
operation="get_all"
|
|
72
|
+
|
|
73
|
+
# Get specific dashboard
|
|
74
|
+
operation="get", params={"dashboard_id": "abc123"}
|
|
75
|
+
|
|
76
|
+
# Create dashboard
|
|
77
|
+
operation="create", params={"custom_dashboard": {"title": "My Dashboard", "widgets": []}}
|
|
78
|
+
|
|
79
|
+
# Update dashboard
|
|
80
|
+
operation="update", params={"dashboard_id": "abc123", "custom_dashboard": {"title": "Updated Dashboard"}}
|
|
81
|
+
|
|
82
|
+
# Delete dashboard
|
|
83
|
+
operation="delete", params={"dashboard_id": "abc123"}
|
|
84
|
+
|
|
85
|
+
# Get shareable users
|
|
86
|
+
operation="get_shareable_users", params={"dashboard_id": "abc123"}
|
|
87
|
+
|
|
88
|
+
# Get shareable API tokens
|
|
89
|
+
operation="get_shareable_api_tokens", params={"dashboard_id": "abc123"}
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
logger.info(f"Custom Dashboard Smart Router received: operation={operation}")
|
|
93
|
+
|
|
94
|
+
# Initialize params if not provided
|
|
95
|
+
if params is None:
|
|
96
|
+
params = {}
|
|
97
|
+
|
|
98
|
+
# Validate operation
|
|
99
|
+
valid_operations = [
|
|
100
|
+
"get_all", "get", "create", "update", "delete",
|
|
101
|
+
"get_shareable_users", "get_shareable_api_tokens"
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
if operation not in valid_operations:
|
|
105
|
+
return {
|
|
106
|
+
"error": f"Invalid operation '{operation}'",
|
|
107
|
+
"valid_operations": valid_operations
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Extract parameters
|
|
111
|
+
dashboard_id = params.get("dashboard_id")
|
|
112
|
+
custom_dashboard = params.get("custom_dashboard")
|
|
113
|
+
|
|
114
|
+
# Route to the dashboard client
|
|
115
|
+
logger.info(f"Routing to Custom Dashboard client for operation: {operation}")
|
|
116
|
+
|
|
117
|
+
result = await self.dashboard_client.execute_dashboard_operation(
|
|
118
|
+
operation=operation,
|
|
119
|
+
dashboard_id=dashboard_id,
|
|
120
|
+
custom_dashboard=custom_dashboard,
|
|
121
|
+
ctx=ctx
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
"operation": operation,
|
|
126
|
+
"dashboard_id": dashboard_id if dashboard_id else None,
|
|
127
|
+
"results": result
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
except Exception as e:
|
|
131
|
+
logger.error(f"Error in custom dashboard smart router: {e}", exc_info=True)
|
|
132
|
+
return {
|
|
133
|
+
"error": f"Custom dashboard smart router error: {e!s}",
|
|
134
|
+
"operation": operation
|
|
135
|
+
}
|
src/core/server.py
CHANGED
|
@@ -65,26 +65,30 @@ from fastmcp import FastMCP
|
|
|
65
65
|
|
|
66
66
|
@dataclass
|
|
67
67
|
class MCPState:
|
|
68
|
-
"""State for the MCP server."""
|
|
68
|
+
"""State for the MCP server with all tool categories."""
|
|
69
|
+
# Router tools
|
|
70
|
+
smart_router_client: Any = None
|
|
71
|
+
custom_dashboard_smart_router_client: Any = None
|
|
72
|
+
|
|
73
|
+
# Infrastructure - Only the new two-pass elicitation tool
|
|
74
|
+
infra_analyze_new_client: Any = None
|
|
75
|
+
|
|
76
|
+
# Events tools
|
|
69
77
|
events_client: Any = None
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
infra_analyze_client: Any = None
|
|
77
|
-
infra_metrics_client: Any = None
|
|
78
|
-
app_catalog_client: Any = None
|
|
79
|
-
app_topology_client: Any = None
|
|
80
|
-
app_analyze_client: Any = None
|
|
81
|
-
app_settings_client: Any = None
|
|
82
|
-
app_global_alert_client: Any = None
|
|
78
|
+
|
|
79
|
+
# Automation tools
|
|
80
|
+
action_catalog_client: Any = None
|
|
81
|
+
action_history_client: Any = None
|
|
82
|
+
|
|
83
|
+
# Website tools
|
|
83
84
|
website_metrics_client: Any = None
|
|
84
85
|
website_catalog_client: Any = None
|
|
85
86
|
website_analyze_client: Any = None
|
|
86
87
|
website_configuration_client: Any = None
|
|
87
88
|
|
|
89
|
+
# Settings tools
|
|
90
|
+
custom_dashboard_client: Any = None
|
|
91
|
+
|
|
88
92
|
# Global variables to store credentials for lifespan
|
|
89
93
|
_global_token = None
|
|
90
94
|
_global_base_url = None
|
|
@@ -236,33 +240,15 @@ async def execute_tool(tool_name: str, arguments: dict, clients_state) -> str:
|
|
|
236
240
|
def get_client_categories():
|
|
237
241
|
"""Get client categories with lazy imports to avoid circular dependencies"""
|
|
238
242
|
try:
|
|
239
|
-
from src.application.application_alert_config import ApplicationAlertMCPTools
|
|
240
|
-
from src.application.application_analyze import ApplicationAnalyzeMCPTools
|
|
241
|
-
from src.application.application_catalog import ApplicationCatalogMCPTools
|
|
242
|
-
from src.application.application_global_alert_config import (
|
|
243
|
-
ApplicationGlobalAlertMCPTools,
|
|
244
|
-
)
|
|
245
|
-
from src.application.application_metrics import ApplicationMetricsMCPTools
|
|
246
|
-
from src.application.application_resources import ApplicationResourcesMCPTools
|
|
247
|
-
from src.application.application_settings import ApplicationSettingsMCPTools
|
|
248
|
-
from src.application.application_topology import ApplicationTopologyMCPTools
|
|
249
243
|
from src.automation.action_catalog import ActionCatalogMCPTools
|
|
250
244
|
from src.automation.action_history import ActionHistoryMCPTools
|
|
251
|
-
from src.
|
|
252
|
-
|
|
253
|
-
InfrastructureAnalyzeMCPTools,
|
|
254
|
-
)
|
|
255
|
-
from src.infrastructure.infrastructure_catalog import (
|
|
256
|
-
InfrastructureCatalogMCPTools,
|
|
257
|
-
)
|
|
258
|
-
from src.infrastructure.infrastructure_metrics import (
|
|
259
|
-
InfrastructureMetricsMCPTools,
|
|
245
|
+
from src.core.custom_dashboard_smart_router_tool import (
|
|
246
|
+
CustomDashboardSmartRouterMCPTool,
|
|
260
247
|
)
|
|
261
|
-
from src.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
InfrastructureTopologyMCPTools,
|
|
248
|
+
from src.core.smart_router_tool import SmartRouterMCPTool
|
|
249
|
+
from src.event.events_tools import AgentMonitoringEventsMCPTools
|
|
250
|
+
from src.infrastructure.infrastructure_analyze_new import (
|
|
251
|
+
InfrastructureAnalyzeOption2,
|
|
266
252
|
)
|
|
267
253
|
from src.settings.custom_dashboard_tools import CustomDashboardMCPTools
|
|
268
254
|
from src.website.website_analyze import WebsiteAnalyzeMCPTools
|
|
@@ -274,22 +260,12 @@ def get_client_categories():
|
|
|
274
260
|
return {}
|
|
275
261
|
|
|
276
262
|
return {
|
|
277
|
-
"
|
|
278
|
-
('
|
|
279
|
-
('
|
|
280
|
-
('infra_topo_client', InfrastructureTopologyMCPTools),
|
|
281
|
-
('infra_analyze_client', InfrastructureAnalyzeMCPTools),
|
|
282
|
-
('infra_metrics_client', InfrastructureMetricsMCPTools),
|
|
263
|
+
"router": [
|
|
264
|
+
('smart_router_client', SmartRouterMCPTool),
|
|
265
|
+
('custom_dashboard_smart_router_client', CustomDashboardSmartRouterMCPTool),
|
|
283
266
|
],
|
|
284
|
-
"
|
|
285
|
-
('
|
|
286
|
-
('app_metrics_client', ApplicationMetricsMCPTools),
|
|
287
|
-
('app_alert_client', ApplicationAlertMCPTools),
|
|
288
|
-
('app_catalog_client', ApplicationCatalogMCPTools),
|
|
289
|
-
('app_topology_client', ApplicationTopologyMCPTools),
|
|
290
|
-
('app_analyze_client', ApplicationAnalyzeMCPTools),
|
|
291
|
-
('app_settings_client', ApplicationSettingsMCPTools),
|
|
292
|
-
('app_global_alert_client', ApplicationGlobalAlertMCPTools),
|
|
267
|
+
"infra": [
|
|
268
|
+
('infra_analyze_new_client', InfrastructureAnalyzeOption2),
|
|
293
269
|
],
|
|
294
270
|
"events": [
|
|
295
271
|
('events_client', AgentMonitoringEventsMCPTools),
|
|
@@ -312,79 +288,65 @@ def get_client_categories():
|
|
|
312
288
|
def get_prompt_categories():
|
|
313
289
|
"""Get prompt categories organized by functionality"""
|
|
314
290
|
# Import the class-based prompts
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
# Use the get_prompts method to get all prompts from the classes
|
|
345
|
-
infra_analyze_prompts = InfrastructureAnalyzePrompts.get_prompts()
|
|
346
|
-
infra_metrics_prompts = InfrastructureMetricsPrompts.get_prompts()
|
|
347
|
-
infra_catalog_prompts = InfrastructureCatalogPrompts.get_prompts()
|
|
348
|
-
infra_topology_prompts = InfrastructureTopologyPrompts.get_prompts()
|
|
349
|
-
infra_resources_prompts = InfrastructureResourcesPrompts.get_prompts()
|
|
350
|
-
app_resources_prompts = ApplicationResourcesPrompts.get_prompts()
|
|
291
|
+
try:
|
|
292
|
+
from src.prompts.application.application_alerts import ApplicationAlertsPrompts
|
|
293
|
+
from src.prompts.application.application_metrics import (
|
|
294
|
+
ApplicationMetricsPrompts,
|
|
295
|
+
)
|
|
296
|
+
from src.prompts.application.application_resources import (
|
|
297
|
+
ApplicationResourcesPrompts,
|
|
298
|
+
)
|
|
299
|
+
from src.prompts.application.application_settings import (
|
|
300
|
+
ApplicationSettingsPrompts,
|
|
301
|
+
)
|
|
302
|
+
from src.prompts.application.application_topology import (
|
|
303
|
+
ApplicationTopologyPrompts,
|
|
304
|
+
)
|
|
305
|
+
from src.prompts.events.events_tools import EventsPrompts
|
|
306
|
+
from src.prompts.settings.custom_dashboard import CustomDashboardPrompts
|
|
307
|
+
from src.prompts.website.website_analyze import WebsiteAnalyzePrompts
|
|
308
|
+
from src.prompts.website.website_catalog import WebsiteCatalogPrompts
|
|
309
|
+
from src.prompts.website.website_configuration import (
|
|
310
|
+
WebsiteConfigurationPrompts,
|
|
311
|
+
)
|
|
312
|
+
from src.prompts.website.website_metrics import WebsiteMetricsPrompts
|
|
313
|
+
except ImportError as e:
|
|
314
|
+
logger.warning(f"Could not import prompt classes: {e}")
|
|
315
|
+
return {}
|
|
316
|
+
|
|
317
|
+
# Get prompts from each class
|
|
318
|
+
app_alerts_prompts = ApplicationAlertsPrompts.get_prompts()
|
|
351
319
|
app_metrics_prompts = ApplicationMetricsPrompts.get_prompts()
|
|
352
|
-
|
|
320
|
+
app_resources_prompts = ApplicationResourcesPrompts.get_prompts()
|
|
353
321
|
app_settings_prompts = ApplicationSettingsPrompts.get_prompts()
|
|
354
322
|
app_topology_prompts = ApplicationTopologyPrompts.get_prompts()
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
website_catalog_prompts = WebsiteCatalogPrompts.get_prompts()
|
|
323
|
+
events_prompts = EventsPrompts.get_prompts()
|
|
324
|
+
custom_dashboard_prompts = CustomDashboardPrompts.get_prompts()
|
|
358
325
|
website_analyze_prompts = WebsiteAnalyzePrompts.get_prompts()
|
|
326
|
+
website_catalog_prompts = WebsiteCatalogPrompts.get_prompts()
|
|
359
327
|
website_configuration_prompts = WebsiteConfigurationPrompts.get_prompts()
|
|
360
|
-
|
|
328
|
+
website_metrics_prompts = WebsiteMetricsPrompts.get_prompts()
|
|
361
329
|
|
|
362
|
-
# Return the categories with their prompt groups
|
|
363
330
|
return {
|
|
364
|
-
"infra": [
|
|
365
|
-
('infra_resources_prompts', infra_resources_prompts),
|
|
366
|
-
('infra_catalog_prompts', infra_catalog_prompts),
|
|
367
|
-
('infra_topology_prompts', infra_topology_prompts),
|
|
368
|
-
('infra_analyze_prompts', infra_analyze_prompts),
|
|
369
|
-
('infra_metrics_prompts', infra_metrics_prompts),
|
|
370
|
-
],
|
|
371
331
|
"app": [
|
|
372
|
-
(
|
|
373
|
-
(
|
|
374
|
-
(
|
|
375
|
-
(
|
|
376
|
-
(
|
|
377
|
-
|
|
332
|
+
("Application Alerts", app_alerts_prompts),
|
|
333
|
+
("Application Metrics", app_metrics_prompts),
|
|
334
|
+
("Application Resources", app_resources_prompts),
|
|
335
|
+
("Application Settings", app_settings_prompts),
|
|
336
|
+
("Application Topology", app_topology_prompts),
|
|
337
|
+
],
|
|
338
|
+
"events": [
|
|
339
|
+
("Events Tools", events_prompts),
|
|
378
340
|
],
|
|
379
341
|
"website": [
|
|
380
|
-
(
|
|
381
|
-
(
|
|
382
|
-
(
|
|
383
|
-
(
|
|
342
|
+
("Website Analyze", website_analyze_prompts),
|
|
343
|
+
("Website Catalog", website_catalog_prompts),
|
|
344
|
+
("Website Configuration", website_configuration_prompts),
|
|
345
|
+
("Website Metrics", website_metrics_prompts),
|
|
384
346
|
],
|
|
385
347
|
"settings": [
|
|
386
|
-
(
|
|
387
|
-
]
|
|
348
|
+
("Custom Dashboard", custom_dashboard_prompts),
|
|
349
|
+
]
|
|
388
350
|
}
|
|
389
351
|
|
|
390
352
|
def get_enabled_client_configs(enabled_categories: str):
|
|
@@ -441,7 +403,7 @@ def main():
|
|
|
441
403
|
"--tools",
|
|
442
404
|
type=str,
|
|
443
405
|
metavar='<categories>',
|
|
444
|
-
help="Comma-separated list of tool categories to enable (--tools infra,app,events,automation,website,
|
|
406
|
+
help="Comma-separated list of tool categories to enable (--tools router,infra,app,events,automation,website,settings). Also controls which prompts are enabled. If not provided, all tools and prompts are enabled. Use 'router' for smart routing across app and infra metrics."
|
|
445
407
|
)
|
|
446
408
|
parser.add_argument(
|
|
447
409
|
"--list-tools",
|
|
@@ -454,6 +416,16 @@ def main():
|
|
|
454
416
|
default=int(os.getenv("PORT", "8080")),
|
|
455
417
|
help="Port to listen on (default: 8080, can be overridden with PORT env var)"
|
|
456
418
|
)
|
|
419
|
+
parser.add_argument(
|
|
420
|
+
"--api-token",
|
|
421
|
+
type=str,
|
|
422
|
+
help="Instana API token (overrides INSTANA_API_TOKEN env var)"
|
|
423
|
+
)
|
|
424
|
+
parser.add_argument(
|
|
425
|
+
"--base-url",
|
|
426
|
+
type=str,
|
|
427
|
+
help="Instana base URL (overrides INSTANA_BASE_URL env var)"
|
|
428
|
+
)
|
|
457
429
|
# Check for help arguments before parsing
|
|
458
430
|
if len(sys.argv) > 1 and any(arg in ['-h','--h','--help','-help'] for arg in sys.argv[1:]):
|
|
459
431
|
# Check if help is combined with other arguments
|
|
@@ -488,7 +460,7 @@ def main():
|
|
|
488
460
|
else:
|
|
489
461
|
set_log_level(args.log_level)
|
|
490
462
|
|
|
491
|
-
all_categories = {"infra", "app", "events", "automation", "website", "settings"}
|
|
463
|
+
all_categories = {"router", "infra", "app", "events", "automation", "website", "settings"}
|
|
492
464
|
|
|
493
465
|
# Handle --list-tools option
|
|
494
466
|
if args.list_tools:
|
|
@@ -516,7 +488,7 @@ def main():
|
|
|
516
488
|
enabled = set(all_categories)
|
|
517
489
|
|
|
518
490
|
if invalid:
|
|
519
|
-
logger.error(f"Error: Unknown category/categories: {', '.join(invalid)}. Available categories: infra, app, events, automation, website, settings")
|
|
491
|
+
logger.error(f"Error: Unknown category/categories: {', '.join(invalid)}. Available categories: router, infra, app, events, automation, website, settings")
|
|
520
492
|
sys.exit(2)
|
|
521
493
|
|
|
522
494
|
# Print enabled tools for user information
|
|
@@ -539,8 +511,9 @@ def main():
|
|
|
539
511
|
f"Total enabled tools: {len(enabled_tool_classes)}"
|
|
540
512
|
)
|
|
541
513
|
|
|
542
|
-
# Get credentials from
|
|
543
|
-
INSTANA_API_TOKEN
|
|
514
|
+
# Get credentials from command line args or environment variables
|
|
515
|
+
INSTANA_API_TOKEN = args.api_token if args.api_token else os.getenv("INSTANA_API_TOKEN", "")
|
|
516
|
+
INSTANA_BASE_URL = args.base_url if args.base_url else os.getenv("INSTANA_BASE_URL", "")
|
|
544
517
|
|
|
545
518
|
if args.transport == "stdio" or args.transport is None:
|
|
546
519
|
if not validate_credentials(INSTANA_API_TOKEN, INSTANA_BASE_URL):
|