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.
- mcp_instana-0.2.0.dist-info/METADATA +1229 -0
- mcp_instana-0.2.0.dist-info/RECORD +59 -0
- {mcp_instana-0.1.0.dist-info → mcp_instana-0.2.0.dist-info}/WHEEL +1 -1
- mcp_instana-0.2.0.dist-info/entry_points.txt +4 -0
- mcp_instana-0.1.0.dist-info/LICENSE → mcp_instana-0.2.0.dist-info/licenses/LICENSE.md +3 -3
- src/application/__init__.py +1 -0
- src/{client/application_alert_config_mcp_tools.py → application/application_alert_config.py} +251 -273
- src/application/application_analyze.py +628 -0
- src/application/application_catalog.py +155 -0
- src/application/application_global_alert_config.py +653 -0
- src/{client/application_metrics_mcp_tools.py → application/application_metrics.py} +113 -131
- src/{client/application_resources_mcp_tools.py → application/application_resources.py} +131 -151
- src/application/application_settings.py +1731 -0
- src/application/application_topology.py +111 -0
- src/automation/action_catalog.py +416 -0
- src/automation/action_history.py +338 -0
- src/core/__init__.py +1 -0
- src/core/server.py +586 -0
- src/core/utils.py +213 -0
- src/event/__init__.py +1 -0
- src/event/events_tools.py +850 -0
- src/infrastructure/__init__.py +1 -0
- src/{client/infrastructure_analyze_mcp_tools.py → infrastructure/infrastructure_analyze.py} +207 -206
- src/{client/infrastructure_catalog_mcp_tools.py → infrastructure/infrastructure_catalog.py} +197 -265
- src/infrastructure/infrastructure_metrics.py +171 -0
- src/{client/infrastructure_resources_mcp_tools.py → infrastructure/infrastructure_resources.py} +198 -227
- src/{client/infrastructure_topology_mcp_tools.py → infrastructure/infrastructure_topology.py} +110 -109
- src/log/__init__.py +1 -0
- src/log/log_alert_configuration.py +331 -0
- src/prompts/__init__.py +16 -0
- src/prompts/application/__init__.py +1 -0
- src/prompts/application/application_alerts.py +54 -0
- src/prompts/application/application_catalog.py +26 -0
- src/prompts/application/application_metrics.py +57 -0
- src/prompts/application/application_resources.py +26 -0
- src/prompts/application/application_settings.py +75 -0
- src/prompts/application/application_topology.py +30 -0
- src/prompts/events/__init__.py +1 -0
- src/prompts/events/events_tools.py +161 -0
- src/prompts/infrastructure/infrastructure_analyze.py +72 -0
- src/prompts/infrastructure/infrastructure_catalog.py +53 -0
- src/prompts/infrastructure/infrastructure_metrics.py +45 -0
- src/prompts/infrastructure/infrastructure_resources.py +74 -0
- src/prompts/infrastructure/infrastructure_topology.py +38 -0
- src/prompts/settings/__init__.py +0 -0
- src/prompts/settings/custom_dashboard.py +157 -0
- src/prompts/website/__init__.py +1 -0
- src/prompts/website/website_analyze.py +35 -0
- src/prompts/website/website_catalog.py +40 -0
- src/prompts/website/website_configuration.py +105 -0
- src/prompts/website/website_metrics.py +34 -0
- src/settings/__init__.py +1 -0
- src/settings/custom_dashboard_tools.py +417 -0
- src/website/__init__.py +0 -0
- src/website/website_analyze.py +433 -0
- src/website/website_catalog.py +171 -0
- src/website/website_configuration.py +770 -0
- src/website/website_metrics.py +241 -0
- mcp_instana-0.1.0.dist-info/METADATA +0 -649
- mcp_instana-0.1.0.dist-info/RECORD +0 -19
- mcp_instana-0.1.0.dist-info/entry_points.txt +0 -3
- src/client/What is the sum of queue depth for all q +0 -55
- src/client/events_mcp_tools.py +0 -531
- src/client/instana_client_base.py +0 -93
- src/client/log_alert_configuration_mcp_tools.py +0 -316
- src/client/show the top 5 services with the highest +0 -28
- src/mcp_server.py +0 -343
src/mcp_server.py
DELETED
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Standalone MCP Server for Instana Events and Infrastructure Resources
|
|
3
|
-
|
|
4
|
-
This module provides a dedicated MCP server that exposes Instana tools.
|
|
5
|
-
Supports stdio and Streamable HTTP transports.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import argparse
|
|
9
|
-
import os
|
|
10
|
-
import sys
|
|
11
|
-
import warnings
|
|
12
|
-
import traceback
|
|
13
|
-
import json
|
|
14
|
-
from collections.abc import AsyncIterator
|
|
15
|
-
from contextlib import asynccontextmanager
|
|
16
|
-
from dataclasses import dataclass, fields
|
|
17
|
-
from dotenv import load_dotenv
|
|
18
|
-
load_dotenv()
|
|
19
|
-
|
|
20
|
-
# Add the project root to the Python path
|
|
21
|
-
current_path = os.path.abspath(__file__)
|
|
22
|
-
project_root = os.path.dirname(os.path.dirname(current_path))
|
|
23
|
-
if project_root not in sys.path:
|
|
24
|
-
sys.path.insert(0, project_root)
|
|
25
|
-
|
|
26
|
-
# Import the necessary modules
|
|
27
|
-
try:
|
|
28
|
-
from src.client.events_mcp_tools import AgentMonitoringEventsMCPTools
|
|
29
|
-
from src.client.infrastructure_resources_mcp_tools import InfrastructureResourcesMCPTools
|
|
30
|
-
from src.client.infrastructure_catalog_mcp_tools import InfrastructureCatalogMCPTools
|
|
31
|
-
from src.client.application_resources_mcp_tools import ApplicationResourcesMCPTools
|
|
32
|
-
from src.client.application_metrics_mcp_tools import ApplicationMetricsMCPTools
|
|
33
|
-
from src.client.infrastructure_topology_mcp_tools import InfrastructureTopologyMCPTools
|
|
34
|
-
from src.client.infrastructure_analyze_mcp_tools import InfrastructureAnalyzeMCPTools
|
|
35
|
-
from src.client.application_alert_config_mcp_tools import ApplicationAlertMCPTools
|
|
36
|
-
|
|
37
|
-
from src.client.instana_client_base import register_as_tool, MCP_TOOLS
|
|
38
|
-
except ImportError as e:
|
|
39
|
-
traceback.print_exc(file=sys.stderr)
|
|
40
|
-
sys.exit(1)
|
|
41
|
-
|
|
42
|
-
from mcp.server.fastmcp import FastMCP
|
|
43
|
-
|
|
44
|
-
@dataclass
|
|
45
|
-
class MCPState:
|
|
46
|
-
"""State for the MCP server."""
|
|
47
|
-
events_client: AgentMonitoringEventsMCPTools = None
|
|
48
|
-
infra_client: InfrastructureResourcesMCPTools = None
|
|
49
|
-
app_resource_client: ApplicationResourcesMCPTools = None
|
|
50
|
-
app_metrics_client: ApplicationMetricsMCPTools = None
|
|
51
|
-
app_alert_client: ApplicationAlertMCPTools = None
|
|
52
|
-
infra_catalog_client: InfrastructureCatalogMCPTools = None
|
|
53
|
-
infra_topo_client: InfrastructureTopologyMCPTools = None
|
|
54
|
-
infra_analyze_client: InfrastructureAnalyzeMCPTools = None
|
|
55
|
-
|
|
56
|
-
# Global variables to store credentials for lifespan
|
|
57
|
-
_global_token = ""
|
|
58
|
-
_global_base_url = ""
|
|
59
|
-
|
|
60
|
-
def get_client_configs():
|
|
61
|
-
"""Get client configurations dynamically from MCPState dataclass"""
|
|
62
|
-
# Map field names to their corresponding client classes
|
|
63
|
-
client_class_mapping = {
|
|
64
|
-
'events_client': AgentMonitoringEventsMCPTools,
|
|
65
|
-
'infra_client': InfrastructureResourcesMCPTools,
|
|
66
|
-
'infra_catalog_client': InfrastructureCatalogMCPTools,
|
|
67
|
-
'infra_topo_client': InfrastructureTopologyMCPTools,
|
|
68
|
-
'infra_analyze_client': InfrastructureAnalyzeMCPTools,
|
|
69
|
-
'app_resource_client': ApplicationResourcesMCPTools,
|
|
70
|
-
'app_metrics_client': ApplicationMetricsMCPTools,
|
|
71
|
-
'app_alert_client': ApplicationAlertMCPTools,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# Get all field names from MCPState dataclass
|
|
75
|
-
state_fields = [field.name for field in fields(MCPState)]
|
|
76
|
-
|
|
77
|
-
# Return configurations for fields that have corresponding client classes
|
|
78
|
-
configs = []
|
|
79
|
-
for field_name in state_fields:
|
|
80
|
-
if field_name in client_class_mapping:
|
|
81
|
-
configs.append((field_name, client_class_mapping[field_name]))
|
|
82
|
-
else:
|
|
83
|
-
print(f"Warning: No client class mapping found for field '{field_name}'", file=sys.stderr)
|
|
84
|
-
|
|
85
|
-
return configs
|
|
86
|
-
|
|
87
|
-
def create_clients(token: str, base_url: str, enabled_categories: str = "all") -> MCPState:
|
|
88
|
-
"""Create only the enabled Instana clients"""
|
|
89
|
-
state = MCPState()
|
|
90
|
-
|
|
91
|
-
# Get enabled client configurations
|
|
92
|
-
enabled_client_configs = get_enabled_client_configs(enabled_categories)
|
|
93
|
-
|
|
94
|
-
for attr_name, client_class in enabled_client_configs:
|
|
95
|
-
try:
|
|
96
|
-
client = client_class(read_token=token, base_url=base_url)
|
|
97
|
-
setattr(state, attr_name, client)
|
|
98
|
-
except Exception as e:
|
|
99
|
-
print(f"Failed to create {attr_name}: {e}", file=sys.stderr)
|
|
100
|
-
traceback.print_exc(file=sys.stderr)
|
|
101
|
-
setattr(state, attr_name, None)
|
|
102
|
-
|
|
103
|
-
return state
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
@asynccontextmanager
|
|
107
|
-
async def lifespan(server: FastMCP) -> AsyncIterator[MCPState]:
|
|
108
|
-
"""Set up and tear down the Instana clients."""
|
|
109
|
-
# Use global credentials set by create_app
|
|
110
|
-
token = _global_token or os.getenv("INSTANA_API_TOKEN", "")
|
|
111
|
-
base_url = _global_base_url or os.getenv("INSTANA_BASE_URL", "")
|
|
112
|
-
enabled_categories = os.getenv("INSTANA_ENABLED_TOOLS", "all")
|
|
113
|
-
|
|
114
|
-
try:
|
|
115
|
-
state = create_clients(token, base_url, enabled_categories)
|
|
116
|
-
|
|
117
|
-
yield state
|
|
118
|
-
except Exception as e:
|
|
119
|
-
traceback.print_exc(file=sys.stderr)
|
|
120
|
-
|
|
121
|
-
# Yield empty state if client creation failed
|
|
122
|
-
yield MCPState()
|
|
123
|
-
|
|
124
|
-
def create_app(instana_api_token_value: str, instana_base_url: str) -> FastMCP:
|
|
125
|
-
global _global_token, _global_base_url
|
|
126
|
-
|
|
127
|
-
try:
|
|
128
|
-
_global_token = instana_api_token_value
|
|
129
|
-
_global_base_url = instana_base_url
|
|
130
|
-
|
|
131
|
-
server = FastMCP("Instana Tools", lifespan=lifespan)
|
|
132
|
-
|
|
133
|
-
# Use the enabled categories from the environment
|
|
134
|
-
enabled_categories = os.getenv("INSTANA_ENABLED_TOOLS", "all")
|
|
135
|
-
|
|
136
|
-
# Only create and register enabled clients/tools
|
|
137
|
-
clients_state = create_clients(instana_api_token_value, instana_base_url, enabled_categories)
|
|
138
|
-
|
|
139
|
-
tools_registered = 0
|
|
140
|
-
for tool_name, tool_func in MCP_TOOLS.items():
|
|
141
|
-
try:
|
|
142
|
-
client_found = False
|
|
143
|
-
client_attr_names = [field.name for field in fields(MCPState)]
|
|
144
|
-
for attr_name in client_attr_names:
|
|
145
|
-
client = getattr(clients_state, attr_name, None)
|
|
146
|
-
if client and hasattr(client, tool_name):
|
|
147
|
-
bound_method = getattr(client, tool_name)
|
|
148
|
-
server.tool()(bound_method)
|
|
149
|
-
tools_registered += 1
|
|
150
|
-
client_found = True
|
|
151
|
-
break
|
|
152
|
-
except Exception as e:
|
|
153
|
-
print(f"Failed to register tool {tool_name}: {e}", file=sys.stderr)
|
|
154
|
-
traceback.print_exc(file=sys.stderr)
|
|
155
|
-
|
|
156
|
-
return server, tools_registered
|
|
157
|
-
|
|
158
|
-
except Exception as e:
|
|
159
|
-
traceback.print_exc(file=sys.stderr)
|
|
160
|
-
fallback_server = FastMCP("Instana Tools")
|
|
161
|
-
return fallback_server
|
|
162
|
-
|
|
163
|
-
async def execute_tool(tool_name: str, arguments: dict, clients_state) -> str:
|
|
164
|
-
"""Execute a tool and return result"""
|
|
165
|
-
try:
|
|
166
|
-
# Get all field names from MCPState dataclass
|
|
167
|
-
client_attr_names = [field.name for field in fields(MCPState)]
|
|
168
|
-
|
|
169
|
-
for attr_name in client_attr_names:
|
|
170
|
-
client = getattr(clients_state, attr_name, None)
|
|
171
|
-
if client and hasattr(client, tool_name):
|
|
172
|
-
method = getattr(client, tool_name)
|
|
173
|
-
result = await method(**arguments)
|
|
174
|
-
return str(result)
|
|
175
|
-
|
|
176
|
-
return f"Tool {tool_name} not found"
|
|
177
|
-
except Exception as e:
|
|
178
|
-
return f"Error executing tool {tool_name}: {str(e)}"
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
client_categories = {
|
|
182
|
-
"infra": [
|
|
183
|
-
('infra_client', InfrastructureResourcesMCPTools),
|
|
184
|
-
('infra_catalog_client', InfrastructureCatalogMCPTools),
|
|
185
|
-
('infra_topo_client', InfrastructureTopologyMCPTools),
|
|
186
|
-
('infra_analyze_client', InfrastructureAnalyzeMCPTools),
|
|
187
|
-
],
|
|
188
|
-
"app": [
|
|
189
|
-
('app_resource_client', ApplicationResourcesMCPTools),
|
|
190
|
-
('app_metrics_client', ApplicationMetricsMCPTools),
|
|
191
|
-
('app_alert_client', ApplicationAlertMCPTools),
|
|
192
|
-
],
|
|
193
|
-
"events": [
|
|
194
|
-
('events_client', AgentMonitoringEventsMCPTools),
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
def get_enabled_client_configs(enabled_categories: str):
|
|
199
|
-
"""Get client configurations based on enabled categories"""
|
|
200
|
-
# Use the global client_categories mapping
|
|
201
|
-
if enabled_categories.lower() == "all":
|
|
202
|
-
all_configs = []
|
|
203
|
-
for category_clients in client_categories.values():
|
|
204
|
-
all_configs.extend(category_clients)
|
|
205
|
-
return all_configs
|
|
206
|
-
categories = [cat.strip() for cat in enabled_categories.split(",")]
|
|
207
|
-
enabled_configs = []
|
|
208
|
-
for category in categories:
|
|
209
|
-
if category in client_categories:
|
|
210
|
-
enabled_configs.extend(client_categories[category])
|
|
211
|
-
else:
|
|
212
|
-
print(f"Warning: Unknown category '{category}'", file=sys.stderr)
|
|
213
|
-
return enabled_configs
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def main():
|
|
217
|
-
"""Main entry point for the MCP server."""
|
|
218
|
-
try:
|
|
219
|
-
# Get token from environment
|
|
220
|
-
instana_api_token_value = os.getenv("INSTANA_API_TOKEN")
|
|
221
|
-
if not instana_api_token_value:
|
|
222
|
-
warnings.warn(
|
|
223
|
-
"Instana API token not provided. Some functionality will be limited. "
|
|
224
|
-
"Provide token via --api-token argument or INSTANA_API_TOKEN environment variable."
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
# Get base URL from environment
|
|
228
|
-
instana_base_url = os.getenv("INSTANA_BASE_URL")
|
|
229
|
-
|
|
230
|
-
# Create and configure the MCP server
|
|
231
|
-
parser = argparse.ArgumentParser(description="Instana MCP Server", add_help=False)
|
|
232
|
-
parser.add_argument(
|
|
233
|
-
"-h", "--help",
|
|
234
|
-
action="store_true",
|
|
235
|
-
dest="help",
|
|
236
|
-
help="show this help message and exit"
|
|
237
|
-
)
|
|
238
|
-
parser.add_argument(
|
|
239
|
-
"--transport",
|
|
240
|
-
type=str,
|
|
241
|
-
choices=["streamable-http","stdio"],
|
|
242
|
-
metavar='<mode>',
|
|
243
|
-
help="Transport mode. Choose from: streamable-http, stdio."
|
|
244
|
-
)
|
|
245
|
-
parser.add_argument(
|
|
246
|
-
"--debug",
|
|
247
|
-
action="store_true",
|
|
248
|
-
help="Enable debug mode with additional logging"
|
|
249
|
-
)
|
|
250
|
-
parser.add_argument(
|
|
251
|
-
"--disable",
|
|
252
|
-
type=str,
|
|
253
|
-
metavar='<categories>',
|
|
254
|
-
help="Disable categories: Choose from (infra (infrastructure), app (application), events (event-based))."
|
|
255
|
-
)
|
|
256
|
-
# Check for help arguments before parsing
|
|
257
|
-
if len(sys.argv) > 1 and any(arg in ['-h','--h','--help','-help'] for arg in sys.argv[1:]):
|
|
258
|
-
# Check if help is combined with other arguments
|
|
259
|
-
help_args = ['-h','--h','--help','-help']
|
|
260
|
-
other_args = [arg for arg in sys.argv[1:] if arg not in help_args]
|
|
261
|
-
|
|
262
|
-
if other_args:
|
|
263
|
-
print("error: argument -h/--h/--help/-help: not allowed with other arguments", file=sys.stderr)
|
|
264
|
-
sys.exit(2)
|
|
265
|
-
|
|
266
|
-
# Show help and exit
|
|
267
|
-
print("options:")
|
|
268
|
-
for action in parser._actions:
|
|
269
|
-
# Only print options that start with '--' and have a help string
|
|
270
|
-
if any(opt.startswith('--') for opt in action.option_strings) and action.help:
|
|
271
|
-
# Find the first long option
|
|
272
|
-
long_opt = next((opt for opt in action.option_strings if opt.startswith('--')), None)
|
|
273
|
-
metavar = action.metavar or ''
|
|
274
|
-
opt_str = f"{long_opt} {metavar}".strip()
|
|
275
|
-
print(f"{opt_str:<24} {action.help}")
|
|
276
|
-
sys.exit(0)
|
|
277
|
-
|
|
278
|
-
args = parser.parse_args()
|
|
279
|
-
|
|
280
|
-
all_categories = {"infra", "app", "events"}
|
|
281
|
-
|
|
282
|
-
# By default, enable all categories
|
|
283
|
-
enabled = set(all_categories)
|
|
284
|
-
invalid = set()
|
|
285
|
-
# Remove disabled categories if specified
|
|
286
|
-
if args.disable:
|
|
287
|
-
disabled = set(cat.strip() for cat in args.disable.split(","))
|
|
288
|
-
invalid = disabled - all_categories
|
|
289
|
-
enabled = enabled - disabled
|
|
290
|
-
|
|
291
|
-
if invalid:
|
|
292
|
-
print(f"Error: Unknown category/categories: {', '.join(invalid)}")
|
|
293
|
-
print(f"Available categories: infra, app, events")
|
|
294
|
-
sys.exit(2)
|
|
295
|
-
|
|
296
|
-
if args.disable:
|
|
297
|
-
disabled_tool_classes = []
|
|
298
|
-
for category in disabled:
|
|
299
|
-
if category in client_categories:
|
|
300
|
-
disabled_tool_classes.extend(
|
|
301
|
-
[cls.__name__ for _, cls in client_categories[category]]
|
|
302
|
-
)
|
|
303
|
-
if disabled_tool_classes:
|
|
304
|
-
print(
|
|
305
|
-
f"The following tools are disabled: {', '.join(disabled_tool_classes)}"
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
os.environ["INSTANA_ENABLED_TOOLS"] = ",".join(enabled)
|
|
309
|
-
|
|
310
|
-
# Create and configure the MCP server
|
|
311
|
-
app, registered_tool_count = create_app(instana_api_token_value or "", instana_base_url or "")
|
|
312
|
-
|
|
313
|
-
# Run the server with the appropriate transport
|
|
314
|
-
if args.transport == "streamable-http":
|
|
315
|
-
if args.debug:
|
|
316
|
-
print(f"FastMCP instance: {app}", file=sys.stderr)
|
|
317
|
-
print(f"Registered tools: {registered_tool_count}", file=sys.stderr)
|
|
318
|
-
try:
|
|
319
|
-
app.run(transport="streamable-http")
|
|
320
|
-
except Exception as e:
|
|
321
|
-
print(f"Failed to start HTTP server: {e}", file=sys.stderr)
|
|
322
|
-
if args.debug:
|
|
323
|
-
traceback.print_exc(file=sys.stderr)
|
|
324
|
-
sys.exit(1)
|
|
325
|
-
else:
|
|
326
|
-
print("Starting stdio transport", file=sys.stderr)
|
|
327
|
-
app.run(transport="stdio")
|
|
328
|
-
|
|
329
|
-
except KeyboardInterrupt:
|
|
330
|
-
print("Server stopped by user", file=sys.stderr)
|
|
331
|
-
sys.exit(0)
|
|
332
|
-
except Exception as e:
|
|
333
|
-
print(f"Server error: {e}", file=sys.stderr)
|
|
334
|
-
traceback.print_exc(file=sys.stderr)
|
|
335
|
-
sys.exit(1)
|
|
336
|
-
|
|
337
|
-
if __name__ == "__main__":
|
|
338
|
-
try:
|
|
339
|
-
main()
|
|
340
|
-
except Exception as e:
|
|
341
|
-
traceback.print_exc(file=sys.stderr)
|
|
342
|
-
sys.exit(1)
|
|
343
|
-
|