mcp-instana 0.1.1__py3-none-any.whl → 0.2.1__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.1.dist-info → mcp_instana-0.2.1.dist-info}/METADATA +460 -139
- mcp_instana-0.2.1.dist-info/RECORD +59 -0
- src/application/application_analyze.py +373 -160
- src/application/application_catalog.py +3 -1
- src/application/application_global_alert_config.py +653 -0
- src/application/application_metrics.py +6 -2
- src/application/application_resources.py +3 -1
- src/application/application_settings.py +966 -370
- src/application/application_topology.py +6 -2
- src/automation/action_catalog.py +416 -0
- src/automation/action_history.py +338 -0
- src/core/server.py +159 -9
- src/core/utils.py +2 -2
- src/event/events_tools.py +602 -275
- src/infrastructure/infrastructure_analyze.py +7 -3
- src/infrastructure/infrastructure_catalog.py +3 -1
- src/infrastructure/infrastructure_metrics.py +6 -2
- src/infrastructure/infrastructure_resources.py +7 -5
- src/infrastructure/infrastructure_topology.py +5 -3
- 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.1.dist-info/RECORD +0 -30
- src/prompts/mcp_prompts.py +0 -900
- src/prompts/prompt_loader.py +0 -29
- src/prompts/prompt_registry.json +0 -21
- {mcp_instana-0.1.1.dist-info → mcp_instana-0.2.1.dist-info}/WHEEL +0 -0
- {mcp_instana-0.1.1.dist-info → mcp_instana-0.2.1.dist-info}/entry_points.txt +0 -0
- {mcp_instana-0.1.1.dist-info → mcp_instana-0.2.1.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -11,13 +11,17 @@ from typing import Any, Dict, Optional
|
|
|
11
11
|
from src.core.utils import BaseInstanaClient, register_as_tool
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
|
-
from instana_client.api.application_topology_api import
|
|
14
|
+
from instana_client.api.application_topology_api import (
|
|
15
|
+
ApplicationTopologyApi,
|
|
16
|
+
)
|
|
15
17
|
from instana_client.api_client import ApiClient
|
|
16
18
|
from instana_client.configuration import Configuration
|
|
17
19
|
except ImportError as e:
|
|
18
20
|
import logging
|
|
21
|
+
import traceback
|
|
19
22
|
logger = logging.getLogger(__name__)
|
|
20
|
-
logger.error(f"Error importing Instana SDK: {e}"
|
|
23
|
+
logger.error(f"Error importing Instana SDK: {e}")
|
|
24
|
+
traceback.print_exc()
|
|
21
25
|
raise
|
|
22
26
|
|
|
23
27
|
# Configure logger for this module
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Automation Action CAtalog MCP Tools Module
|
|
3
|
+
|
|
4
|
+
This module provides automation action catalog tools for Instana Automation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
# Import the necessary classes from the SDK
|
|
11
|
+
try:
|
|
12
|
+
from instana_client.api.action_catalog_api import (
|
|
13
|
+
ActionCatalogApi,
|
|
14
|
+
)
|
|
15
|
+
except ImportError:
|
|
16
|
+
import logging
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
logger.error("Failed to import application alert configuration API", exc_info=True)
|
|
19
|
+
raise
|
|
20
|
+
|
|
21
|
+
from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
|
|
22
|
+
|
|
23
|
+
# Configure logger for this module
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
class ActionCatalogMCPTools(BaseInstanaClient):
|
|
27
|
+
"""Tools for application alerts in Instana MCP."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, read_token: str, base_url: str):
|
|
30
|
+
"""Initialize the Application Alert MCP tools client."""
|
|
31
|
+
super().__init__(read_token=read_token, base_url=base_url)
|
|
32
|
+
|
|
33
|
+
@register_as_tool
|
|
34
|
+
@with_header_auth(ActionCatalogApi)
|
|
35
|
+
async def get_action_matches(self,
|
|
36
|
+
payload: Union[Dict[str, Any], str],
|
|
37
|
+
target_snapshot_id: Optional[str] = None,
|
|
38
|
+
ctx=None,
|
|
39
|
+
api_client=None) -> Dict[str, Any]:
|
|
40
|
+
"""
|
|
41
|
+
Get action matches for a given action search space and target snapshot ID.
|
|
42
|
+
Args:
|
|
43
|
+
Sample payload:
|
|
44
|
+
{
|
|
45
|
+
"name": "CPU spends significant time waiting for input/output",
|
|
46
|
+
"description": "Checks whether the system spends significant time waiting for input/output."
|
|
47
|
+
}
|
|
48
|
+
target_snapshot_id: Optional[str]: The target snapshot ID to get action matches for.
|
|
49
|
+
ctx: Optional[Dict[str, Any]]: The context to get action matches for.
|
|
50
|
+
api_client: Optional[ActionCatalogApi]: The API client to get action matches for.
|
|
51
|
+
Returns:
|
|
52
|
+
Dict[str, Any]: The action matches for the given payload and target snapshot ID.
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
|
|
56
|
+
if not payload:
|
|
57
|
+
return {"error": "payload is required"}
|
|
58
|
+
|
|
59
|
+
# Parse the payload if it's a string
|
|
60
|
+
if isinstance(payload, str):
|
|
61
|
+
logger.debug("Payload is a string, attempting to parse")
|
|
62
|
+
try:
|
|
63
|
+
import json
|
|
64
|
+
try:
|
|
65
|
+
parsed_payload = json.loads(payload)
|
|
66
|
+
logger.debug("Successfully parsed payload as JSON")
|
|
67
|
+
request_body = parsed_payload
|
|
68
|
+
except json.JSONDecodeError as e:
|
|
69
|
+
logger.debug(f"JSON parsing failed: {e}, trying with quotes replaced")
|
|
70
|
+
|
|
71
|
+
# Try replacing single quotes with double quotes
|
|
72
|
+
fixed_payload = payload.replace("'", "\"")
|
|
73
|
+
try:
|
|
74
|
+
parsed_payload = json.loads(fixed_payload)
|
|
75
|
+
logger.debug("Successfully parsed fixed JSON")
|
|
76
|
+
request_body = parsed_payload
|
|
77
|
+
except json.JSONDecodeError:
|
|
78
|
+
# Try as Python literal
|
|
79
|
+
import ast
|
|
80
|
+
try:
|
|
81
|
+
parsed_payload = ast.literal_eval(payload)
|
|
82
|
+
logger.debug("Successfully parsed payload as Python literal")
|
|
83
|
+
request_body = parsed_payload
|
|
84
|
+
except (SyntaxError, ValueError) as e2:
|
|
85
|
+
logger.debug(f"Failed to parse payload string: {e2}")
|
|
86
|
+
return {"error": f"Invalid payload format: {e2}", "payload": payload}
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.debug(f"Error parsing payload string: {e}")
|
|
89
|
+
return {"error": f"Failed to parse payload: {e}", "payload": payload}
|
|
90
|
+
else:
|
|
91
|
+
# If payload is already a dictionary, use it directly
|
|
92
|
+
logger.debug("Using provided payload dictionary")
|
|
93
|
+
request_body = payload
|
|
94
|
+
|
|
95
|
+
# Validate required fields in the payload
|
|
96
|
+
required_fields = ["name"]
|
|
97
|
+
for field in required_fields:
|
|
98
|
+
if field not in request_body:
|
|
99
|
+
logger.warning(f"Missing required field: {field}")
|
|
100
|
+
return {"error": f"Missing required field: {field}"}
|
|
101
|
+
|
|
102
|
+
# Import the ActionSearchSpace class
|
|
103
|
+
try:
|
|
104
|
+
from instana_client.models.action_search_space import (
|
|
105
|
+
ActionSearchSpace,
|
|
106
|
+
)
|
|
107
|
+
logger.debug("Successfully imported ActionSearchSpace")
|
|
108
|
+
except ImportError as e:
|
|
109
|
+
logger.debug(f"Error importing ActionSearchSpace: {e}")
|
|
110
|
+
return {"error": f"Failed to import ActionSearchSpace: {e!s}"}
|
|
111
|
+
|
|
112
|
+
# Create an ActionSearchSpace object from the request body
|
|
113
|
+
try:
|
|
114
|
+
logger.debug(f"Creating ActionSearchSpace with params: {request_body}")
|
|
115
|
+
config_object = ActionSearchSpace(**request_body)
|
|
116
|
+
logger.debug("Successfully created config object")
|
|
117
|
+
except Exception as e:
|
|
118
|
+
logger.debug(f"Error creating ActionSearchSpace: {e}")
|
|
119
|
+
return {"error": f"Failed to create config object: {e!s}"}
|
|
120
|
+
|
|
121
|
+
# Call the get_action_matches method from the SDK
|
|
122
|
+
logger.debug("Calling get_action_matches with config object")
|
|
123
|
+
result = api_client.get_action_matches(
|
|
124
|
+
action_search_space=config_object,
|
|
125
|
+
target_snapshot_id=target_snapshot_id,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Convert the result to a dictionary
|
|
129
|
+
if isinstance(result, list):
|
|
130
|
+
# Convert list of ActionMatch objects to list of dictionaries
|
|
131
|
+
result_dict = []
|
|
132
|
+
for action_match in result:
|
|
133
|
+
try:
|
|
134
|
+
if hasattr(action_match, 'to_dict'):
|
|
135
|
+
result_dict.append(action_match.to_dict())
|
|
136
|
+
else:
|
|
137
|
+
result_dict.append(action_match)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.warning(f"Failed to convert action match to dict: {e}")
|
|
140
|
+
# Add a fallback representation
|
|
141
|
+
result_dict.append({
|
|
142
|
+
"error": f"Failed to serialize action match: {e}",
|
|
143
|
+
"raw_data": str(action_match)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
logger.debug(f"Result from get_action_matches: {result_dict}")
|
|
147
|
+
return {
|
|
148
|
+
"success": True,
|
|
149
|
+
"message": "Action matches retrieved successfully",
|
|
150
|
+
"data": result_dict,
|
|
151
|
+
"count": len(result_dict)
|
|
152
|
+
}
|
|
153
|
+
elif hasattr(result, 'to_dict'):
|
|
154
|
+
try:
|
|
155
|
+
result_dict = result.to_dict()
|
|
156
|
+
logger.debug(f"Result from get_action_matches: {result_dict}")
|
|
157
|
+
return {
|
|
158
|
+
"success": True,
|
|
159
|
+
"message": "Action match retrieved successfully",
|
|
160
|
+
"data": result_dict
|
|
161
|
+
}
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.warning(f"Failed to convert result to dict: {e}")
|
|
164
|
+
return {
|
|
165
|
+
"success": False,
|
|
166
|
+
"message": "Failed to serialize result",
|
|
167
|
+
"error": str(e),
|
|
168
|
+
"raw_data": str(result)
|
|
169
|
+
}
|
|
170
|
+
else:
|
|
171
|
+
# If it's already a dict or another format, use it as is
|
|
172
|
+
result_dict = result or {
|
|
173
|
+
"success": True,
|
|
174
|
+
"message": "Get action matches"
|
|
175
|
+
}
|
|
176
|
+
logger.debug(f"Result from get_action_matches: {result_dict}")
|
|
177
|
+
return result_dict
|
|
178
|
+
except Exception as e:
|
|
179
|
+
logger.error(f"Error in get_action_matches: {e}")
|
|
180
|
+
return {"error": f"Failed to get action matches: {e!s}"}
|
|
181
|
+
|
|
182
|
+
@register_as_tool
|
|
183
|
+
@with_header_auth(ActionCatalogApi)
|
|
184
|
+
async def get_actions(self,
|
|
185
|
+
page: Optional[int] = None,
|
|
186
|
+
page_size: Optional[int] = None,
|
|
187
|
+
search: Optional[str] = None,
|
|
188
|
+
types: Optional[List[str]] = None,
|
|
189
|
+
order_by: Optional[str] = None,
|
|
190
|
+
order_direction: Optional[str] = None,
|
|
191
|
+
ctx=None,
|
|
192
|
+
api_client=None) -> Dict[str, Any]:
|
|
193
|
+
"""
|
|
194
|
+
Get a list of available automation actions from the action catalog.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
page: Page number for pagination (optional)
|
|
198
|
+
page_size: Number of actions per page (optional)
|
|
199
|
+
search: Search term to filter actions by name or description (optional)
|
|
200
|
+
types: List of action types to filter by (optional)
|
|
201
|
+
order_by: Field to order results by (optional)
|
|
202
|
+
order_direction: Sort direction ('asc' or 'desc') (optional)
|
|
203
|
+
ctx: Optional[Dict[str, Any]]: The context for the action retrieval
|
|
204
|
+
api_client: Optional[ActionCatalogApi]: The API client for action catalog
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Dict[str, Any]: The list of available automation actions
|
|
208
|
+
"""
|
|
209
|
+
try:
|
|
210
|
+
logger.debug("get_actions called")
|
|
211
|
+
|
|
212
|
+
# Call the get_actions method from the SDK
|
|
213
|
+
result = api_client.get_actions(
|
|
214
|
+
page=page,
|
|
215
|
+
page_size=page_size,
|
|
216
|
+
search=search,
|
|
217
|
+
types=types,
|
|
218
|
+
order_by=order_by,
|
|
219
|
+
order_direction=order_direction
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Convert the result to a dictionary
|
|
223
|
+
if hasattr(result, 'to_dict'):
|
|
224
|
+
result_dict = result.to_dict()
|
|
225
|
+
else:
|
|
226
|
+
# If it's already a dict or another format, use it as is
|
|
227
|
+
result_dict = result or {
|
|
228
|
+
"success": True,
|
|
229
|
+
"message": "Actions retrieved successfully"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
logger.debug(f"Result from get_actions: {result_dict}")
|
|
233
|
+
return result_dict
|
|
234
|
+
|
|
235
|
+
except Exception as e:
|
|
236
|
+
logger.error(f"Error in get_actions: {e}")
|
|
237
|
+
return {"error": f"Failed to get actions: {e!s}"}
|
|
238
|
+
|
|
239
|
+
@register_as_tool
|
|
240
|
+
@with_header_auth(ActionCatalogApi)
|
|
241
|
+
async def get_action_details(self,
|
|
242
|
+
action_id: str,
|
|
243
|
+
ctx=None,
|
|
244
|
+
api_client=None) -> Dict[str, Any]:
|
|
245
|
+
"""
|
|
246
|
+
Get detailed information about a specific automation action by ID.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
action_id: The unique identifier of the action (required)
|
|
250
|
+
ctx: Optional[Dict[str, Any]]: The context for the action details retrieval
|
|
251
|
+
api_client: Optional[ActionCatalogApi]: The API client for action catalog
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Dict[str, Any]: The detailed information about the automation action
|
|
255
|
+
"""
|
|
256
|
+
try:
|
|
257
|
+
if not action_id:
|
|
258
|
+
return {"error": "action_id is required"}
|
|
259
|
+
|
|
260
|
+
logger.debug(f"get_action_details called with action_id: {action_id}")
|
|
261
|
+
|
|
262
|
+
# Call the get_action method from the SDK
|
|
263
|
+
result = api_client.get_action(action_id=action_id)
|
|
264
|
+
|
|
265
|
+
# Convert the result to a dictionary
|
|
266
|
+
if hasattr(result, 'to_dict'):
|
|
267
|
+
result_dict = result.to_dict()
|
|
268
|
+
else:
|
|
269
|
+
# If it's already a dict or another format, use it as is
|
|
270
|
+
result_dict = result or {
|
|
271
|
+
"success": True,
|
|
272
|
+
"message": "Action details retrieved successfully"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
logger.debug(f"Result from get_action: {result_dict}")
|
|
276
|
+
return result_dict
|
|
277
|
+
|
|
278
|
+
except Exception as e:
|
|
279
|
+
logger.error(f"Error in get_action_details: {e}")
|
|
280
|
+
return {"error": f"Failed to get action details: {e!s}"}
|
|
281
|
+
|
|
282
|
+
@register_as_tool
|
|
283
|
+
@with_header_auth(ActionCatalogApi)
|
|
284
|
+
async def search_actions(self,
|
|
285
|
+
search: str,
|
|
286
|
+
page: Optional[int] = None,
|
|
287
|
+
page_size: Optional[int] = None,
|
|
288
|
+
types: Optional[List[str]] = None,
|
|
289
|
+
order_by: Optional[str] = None,
|
|
290
|
+
order_direction: Optional[str] = None,
|
|
291
|
+
ctx=None,
|
|
292
|
+
api_client=None) -> Dict[str, Any]:
|
|
293
|
+
"""
|
|
294
|
+
Search for automation actions in the action catalog.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
search: Search term to find actions by name, description, or other attributes (required)
|
|
298
|
+
page: Page number for pagination (optional)
|
|
299
|
+
page_size: Number of actions per page (optional)
|
|
300
|
+
types: List of action types to filter by (optional)
|
|
301
|
+
order_by: Field to order results by (optional)
|
|
302
|
+
order_direction: Sort direction ('asc' or 'desc') (optional)
|
|
303
|
+
ctx: Optional[Dict[str, Any]]: The context for the action search
|
|
304
|
+
api_client: Optional[ActionCatalogApi]: The API client for action catalog
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
Dict[str, Any]: The search results for automation actions
|
|
308
|
+
"""
|
|
309
|
+
try:
|
|
310
|
+
if not search:
|
|
311
|
+
return {"error": "search parameter is required"}
|
|
312
|
+
|
|
313
|
+
logger.debug(f"search_actions called with search: {search}")
|
|
314
|
+
|
|
315
|
+
# Call the search_actions method from the SDK
|
|
316
|
+
result = api_client.search_actions(
|
|
317
|
+
search=search,
|
|
318
|
+
page=page,
|
|
319
|
+
page_size=page_size,
|
|
320
|
+
types=types,
|
|
321
|
+
order_by=order_by,
|
|
322
|
+
order_direction=order_direction
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Convert the result to a dictionary
|
|
326
|
+
if hasattr(result, 'to_dict'):
|
|
327
|
+
result_dict = result.to_dict()
|
|
328
|
+
else:
|
|
329
|
+
# If it's already a dict or another format, use it as is
|
|
330
|
+
result_dict = result or {
|
|
331
|
+
"success": True,
|
|
332
|
+
"message": "Action search completed successfully"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
logger.debug(f"Result from search_actions: {result_dict}")
|
|
336
|
+
return result_dict
|
|
337
|
+
|
|
338
|
+
except Exception as e:
|
|
339
|
+
logger.error(f"Error in search_actions: {e}")
|
|
340
|
+
return {"error": f"Failed to search actions: {e!s}"}
|
|
341
|
+
|
|
342
|
+
@register_as_tool
|
|
343
|
+
@with_header_auth(ActionCatalogApi)
|
|
344
|
+
async def get_action_types(self,
|
|
345
|
+
ctx=None,
|
|
346
|
+
api_client=None) -> Dict[str, Any]:
|
|
347
|
+
"""
|
|
348
|
+
Get a list of available action types in the action catalog.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
ctx: Optional[Dict[str, Any]]: The context for the action types retrieval
|
|
352
|
+
api_client: Optional[ActionCatalogApi]: The API client for action catalog
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Dict[str, Any]: The list of available action types
|
|
356
|
+
"""
|
|
357
|
+
try:
|
|
358
|
+
logger.debug("get_action_types called")
|
|
359
|
+
|
|
360
|
+
# Call the get_action_types method from the SDK
|
|
361
|
+
result = api_client.get_action_types()
|
|
362
|
+
|
|
363
|
+
# Convert the result to a dictionary
|
|
364
|
+
if hasattr(result, 'to_dict'):
|
|
365
|
+
result_dict = result.to_dict()
|
|
366
|
+
else:
|
|
367
|
+
# If it's already a dict or another format, use it as is
|
|
368
|
+
result_dict = result or {
|
|
369
|
+
"success": True,
|
|
370
|
+
"message": "Action types retrieved successfully"
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
logger.debug(f"Result from get_action_types: {result_dict}")
|
|
374
|
+
return result_dict
|
|
375
|
+
|
|
376
|
+
except Exception as e:
|
|
377
|
+
logger.error(f"Error in get_action_types: {e}")
|
|
378
|
+
return {"error": f"Failed to get action types: {e!s}"}
|
|
379
|
+
|
|
380
|
+
@register_as_tool
|
|
381
|
+
@with_header_auth(ActionCatalogApi)
|
|
382
|
+
async def get_action_categories(self,
|
|
383
|
+
ctx=None,
|
|
384
|
+
api_client=None) -> Dict[str, Any]:
|
|
385
|
+
"""
|
|
386
|
+
Get a list of available action categories in the action catalog.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
ctx: Optional[Dict[str, Any]]: The context for the action categories retrieval
|
|
390
|
+
api_client: Optional[ActionCatalogApi]: The API client for action catalog
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Dict[str, Any]: The list of available action categories
|
|
394
|
+
"""
|
|
395
|
+
try:
|
|
396
|
+
logger.debug("get_action_categories called")
|
|
397
|
+
|
|
398
|
+
# Call the get_action_categories method from the SDK
|
|
399
|
+
result = api_client.get_action_categories()
|
|
400
|
+
|
|
401
|
+
# Convert the result to a dictionary
|
|
402
|
+
if hasattr(result, 'to_dict'):
|
|
403
|
+
result_dict = result.to_dict()
|
|
404
|
+
else:
|
|
405
|
+
# If it's already a dict or another format, use it as is
|
|
406
|
+
result_dict = result or {
|
|
407
|
+
"success": True,
|
|
408
|
+
"message": "Action categories retrieved successfully"
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
logger.debug(f"Result from get_action_categories: {result_dict}")
|
|
412
|
+
return result_dict
|
|
413
|
+
|
|
414
|
+
except Exception as e:
|
|
415
|
+
logger.error(f"Error in get_action_categories: {e}")
|
|
416
|
+
return {"error": f"Failed to get action categories: {e!s}"}
|