mcp-instana 0.1.1__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.1.1.dist-info → mcp_instana-0.2.0.dist-info}/METADATA +459 -138
- mcp_instana-0.2.0.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.0.dist-info}/WHEEL +0 -0
- {mcp_instana-0.1.1.dist-info → mcp_instana-0.2.0.dist-info}/entry_points.txt +0 -0
- {mcp_instana-0.1.1.dist-info → mcp_instana-0.2.0.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom Dashboard MCP Tools Module
|
|
3
|
+
|
|
4
|
+
This module provides custom dashboard-specific MCP tools for Instana monitoring.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from src.core.utils import (
|
|
12
|
+
BaseInstanaClient,
|
|
13
|
+
register_as_tool,
|
|
14
|
+
with_header_auth,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from instana_client.api.custom_dashboards_api import CustomDashboardsApi
|
|
19
|
+
from instana_client.models.custom_dashboard import CustomDashboard
|
|
20
|
+
|
|
21
|
+
except ImportError as e:
|
|
22
|
+
import logging
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
logger.error(f"Error importing Instana SDK: {e}", exc_info=True)
|
|
25
|
+
raise
|
|
26
|
+
|
|
27
|
+
# Configure logger for this module
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
class CustomDashboardMCPTools(BaseInstanaClient):
|
|
31
|
+
"""Tools for custom dashboards in Instana MCP."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, read_token: str, base_url: str):
|
|
34
|
+
"""Initialize the Custom Dashboard MCP tools client."""
|
|
35
|
+
super().__init__(read_token=read_token, base_url=base_url)
|
|
36
|
+
|
|
37
|
+
@register_as_tool
|
|
38
|
+
@with_header_auth(CustomDashboardsApi)
|
|
39
|
+
async def get_custom_dashboards(self,
|
|
40
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
41
|
+
"""
|
|
42
|
+
Get all custom dashboards from Instana server.
|
|
43
|
+
This tool retrieves a list of all custom dashboards configured in your Instana environment.
|
|
44
|
+
Use this tool to see what dashboards are available and their basic information.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
ctx: The MCP context (optional)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Dictionary containing custom dashboards data or error information
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
logger.debug("Getting custom dashboards from Instana SDK")
|
|
54
|
+
|
|
55
|
+
# Call the get_custom_dashboards method from the SDK
|
|
56
|
+
result = api_client.get_custom_dashboards()
|
|
57
|
+
|
|
58
|
+
# Convert the result to a dictionary
|
|
59
|
+
result_dict: Dict[str, Any] = {}
|
|
60
|
+
|
|
61
|
+
if hasattr(result, 'to_dict'):
|
|
62
|
+
result_dict = result.to_dict()
|
|
63
|
+
elif isinstance(result, dict):
|
|
64
|
+
result_dict = result
|
|
65
|
+
elif isinstance(result, list):
|
|
66
|
+
# If it's a list, wrap it in a dictionary
|
|
67
|
+
result_dict = {"items": result}
|
|
68
|
+
else:
|
|
69
|
+
# For any other type, convert to string and wrap
|
|
70
|
+
result_dict = {"result": str(result)}
|
|
71
|
+
|
|
72
|
+
# Limit the response size
|
|
73
|
+
if "items" in result_dict and isinstance(result_dict["items"], list):
|
|
74
|
+
# Limit items to top 10
|
|
75
|
+
items_list = result_dict["items"]
|
|
76
|
+
original_count = len(items_list)
|
|
77
|
+
if original_count > 10:
|
|
78
|
+
result_dict["items"] = items_list[:10]
|
|
79
|
+
logger.debug(f"Limited response items from {original_count} to 10")
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
logger.debug(f"Result from get_custom_dashboards: {json.dumps(result_dict, indent=2)}")
|
|
83
|
+
except TypeError:
|
|
84
|
+
logger.debug(f"Result from get_custom_dashboards: {result_dict} (not JSON serializable)")
|
|
85
|
+
|
|
86
|
+
return result_dict
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Error in get_custom_dashboards: {e}", exc_info=True)
|
|
90
|
+
return {"error": f"Failed to get custom dashboards: {e!s}"}
|
|
91
|
+
|
|
92
|
+
@register_as_tool
|
|
93
|
+
@with_header_auth(CustomDashboardsApi)
|
|
94
|
+
async def get_custom_dashboard(self,
|
|
95
|
+
dashboard_id: str,
|
|
96
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
97
|
+
"""
|
|
98
|
+
Get a specific custom dashboard by ID from Instana server.
|
|
99
|
+
This tool retrieves detailed information about a specific custom dashboard including
|
|
100
|
+
its widgets, access rules, and configuration.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
dashboard_id: The ID of the custom dashboard to retrieve
|
|
104
|
+
ctx: The MCP context (optional)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Dictionary containing custom dashboard data or error information
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
if not dashboard_id:
|
|
111
|
+
return {"error": "Dashboard ID is required for this operation"}
|
|
112
|
+
|
|
113
|
+
logger.debug(f"Getting custom dashboard {dashboard_id} from Instana SDK")
|
|
114
|
+
|
|
115
|
+
# Call the get_custom_dashboard method from the SDK
|
|
116
|
+
result = api_client.get_custom_dashboard(dashboard_id=dashboard_id)
|
|
117
|
+
|
|
118
|
+
# Convert the result to a dictionary
|
|
119
|
+
result_dict: Dict[str, Any] = {}
|
|
120
|
+
|
|
121
|
+
if hasattr(result, 'to_dict'):
|
|
122
|
+
result_dict = result.to_dict()
|
|
123
|
+
elif isinstance(result, dict):
|
|
124
|
+
result_dict = result
|
|
125
|
+
else:
|
|
126
|
+
# For any other type, convert to string and wrap
|
|
127
|
+
result_dict = {"result": str(result)}
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
logger.debug(f"Result from get_custom_dashboard: {json.dumps(result_dict, indent=2)}")
|
|
131
|
+
except TypeError:
|
|
132
|
+
logger.debug(f"Result from get_custom_dashboard: {result_dict} (not JSON serializable)")
|
|
133
|
+
|
|
134
|
+
return result_dict
|
|
135
|
+
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(f"Error in get_custom_dashboard: {e}", exc_info=True)
|
|
138
|
+
return {"error": f"Failed to get custom dashboard: {e!s}"}
|
|
139
|
+
|
|
140
|
+
@register_as_tool
|
|
141
|
+
@with_header_auth(CustomDashboardsApi)
|
|
142
|
+
async def add_custom_dashboard(self,
|
|
143
|
+
custom_dashboard: Dict[str, Any],
|
|
144
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
145
|
+
"""
|
|
146
|
+
Add a new custom dashboard to Instana server.
|
|
147
|
+
This tool creates a new custom dashboard with the specified configuration,
|
|
148
|
+
widgets, and access rules.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
custom_dashboard: Dictionary containing dashboard configuration including:
|
|
152
|
+
- title: Dashboard title
|
|
153
|
+
- widgets: List of widget configurations
|
|
154
|
+
- accessRules: List of access rules
|
|
155
|
+
ctx: The MCP context (optional)
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Dictionary containing the created custom dashboard data or error information
|
|
159
|
+
"""
|
|
160
|
+
try:
|
|
161
|
+
if not custom_dashboard:
|
|
162
|
+
return {"error": "Custom dashboard configuration is required for this operation"}
|
|
163
|
+
|
|
164
|
+
logger.debug("Adding custom dashboard to Instana SDK")
|
|
165
|
+
logger.debug(json.dumps(custom_dashboard, indent=2))
|
|
166
|
+
|
|
167
|
+
# Create the CustomDashboard object
|
|
168
|
+
dashboard_obj = CustomDashboard(**custom_dashboard)
|
|
169
|
+
|
|
170
|
+
# Call the add_custom_dashboard method from the SDK
|
|
171
|
+
result = api_client.add_custom_dashboard(custom_dashboard=dashboard_obj)
|
|
172
|
+
|
|
173
|
+
# Convert the result to a dictionary
|
|
174
|
+
result_dict: Dict[str, Any] = {}
|
|
175
|
+
|
|
176
|
+
if hasattr(result, 'to_dict'):
|
|
177
|
+
result_dict = result.to_dict()
|
|
178
|
+
elif isinstance(result, dict):
|
|
179
|
+
result_dict = result
|
|
180
|
+
else:
|
|
181
|
+
# For any other type, convert to string and wrap
|
|
182
|
+
result_dict = {"result": str(result)}
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
logger.debug(f"Result from add_custom_dashboard: {json.dumps(result_dict, indent=2)}")
|
|
186
|
+
except TypeError:
|
|
187
|
+
logger.debug(f"Result from add_custom_dashboard: {result_dict} (not JSON serializable)")
|
|
188
|
+
|
|
189
|
+
return result_dict
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.error(f"Error in add_custom_dashboard: {e}", exc_info=True)
|
|
193
|
+
return {"error": f"Failed to add custom dashboard: {e!s}"}
|
|
194
|
+
|
|
195
|
+
@register_as_tool
|
|
196
|
+
@with_header_auth(CustomDashboardsApi)
|
|
197
|
+
async def update_custom_dashboard(self,
|
|
198
|
+
dashboard_id: str,
|
|
199
|
+
custom_dashboard: Dict[str, Any],
|
|
200
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
201
|
+
"""
|
|
202
|
+
Update an existing custom dashboard in Instana server.
|
|
203
|
+
This tool updates a custom dashboard with new configuration, widgets, or access rules.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
dashboard_id: The ID of the custom dashboard to update
|
|
207
|
+
custom_dashboard: Dictionary containing updated dashboard configuration
|
|
208
|
+
ctx: The MCP context (optional)
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Dictionary containing the updated custom dashboard data or error information
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
if not dashboard_id:
|
|
215
|
+
return {"error": "Dashboard ID is required for this operation"}
|
|
216
|
+
|
|
217
|
+
if not custom_dashboard:
|
|
218
|
+
return {"error": "Custom dashboard configuration is required for this operation"}
|
|
219
|
+
|
|
220
|
+
logger.debug(f"Updating custom dashboard {dashboard_id} in Instana SDK")
|
|
221
|
+
logger.debug(json.dumps(custom_dashboard, indent=2))
|
|
222
|
+
|
|
223
|
+
# Create the CustomDashboard object
|
|
224
|
+
dashboard_obj = CustomDashboard(**custom_dashboard)
|
|
225
|
+
|
|
226
|
+
# Call the update_custom_dashboard method from the SDK
|
|
227
|
+
result = api_client.update_custom_dashboard(
|
|
228
|
+
dashboard_id=dashboard_id,
|
|
229
|
+
custom_dashboard=dashboard_obj
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Convert the result to a dictionary
|
|
233
|
+
result_dict: Dict[str, Any] = {}
|
|
234
|
+
|
|
235
|
+
if hasattr(result, 'to_dict'):
|
|
236
|
+
result_dict = result.to_dict()
|
|
237
|
+
elif isinstance(result, dict):
|
|
238
|
+
result_dict = result
|
|
239
|
+
else:
|
|
240
|
+
# For any other type, convert to string and wrap
|
|
241
|
+
result_dict = {"result": str(result)}
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
logger.debug(f"Result from update_custom_dashboard: {json.dumps(result_dict, indent=2)}")
|
|
245
|
+
except TypeError:
|
|
246
|
+
logger.debug(f"Result from update_custom_dashboard: {result_dict} (not JSON serializable)")
|
|
247
|
+
|
|
248
|
+
return result_dict
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
logger.error(f"Error in update_custom_dashboard: {e}", exc_info=True)
|
|
252
|
+
return {"error": f"Failed to update custom dashboard: {e!s}"}
|
|
253
|
+
|
|
254
|
+
@register_as_tool
|
|
255
|
+
@with_header_auth(CustomDashboardsApi)
|
|
256
|
+
async def delete_custom_dashboard(self,
|
|
257
|
+
dashboard_id: str,
|
|
258
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
259
|
+
"""
|
|
260
|
+
Delete a custom dashboard from Instana server.
|
|
261
|
+
This tool removes a custom dashboard from your Instana environment.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
dashboard_id: The ID of the custom dashboard to delete
|
|
265
|
+
ctx: The MCP context (optional)
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Dictionary containing deletion status or error information
|
|
269
|
+
"""
|
|
270
|
+
try:
|
|
271
|
+
if not dashboard_id:
|
|
272
|
+
return {"error": "Dashboard ID is required for this operation"}
|
|
273
|
+
|
|
274
|
+
logger.debug(f"Deleting custom dashboard {dashboard_id} from Instana SDK")
|
|
275
|
+
|
|
276
|
+
# Call the delete_custom_dashboard method from the SDK
|
|
277
|
+
result = api_client.delete_custom_dashboard(dashboard_id=dashboard_id)
|
|
278
|
+
|
|
279
|
+
# Convert the result to a dictionary
|
|
280
|
+
result_dict: Dict[str, Any] = {}
|
|
281
|
+
|
|
282
|
+
if hasattr(result, 'to_dict'):
|
|
283
|
+
result_dict = result.to_dict()
|
|
284
|
+
elif isinstance(result, dict):
|
|
285
|
+
result_dict = result
|
|
286
|
+
else:
|
|
287
|
+
# For any other type, convert to string and wrap
|
|
288
|
+
result_dict = {"result": str(result)}
|
|
289
|
+
|
|
290
|
+
try:
|
|
291
|
+
logger.debug(f"Result from delete_custom_dashboard: {json.dumps(result_dict, indent=2)}")
|
|
292
|
+
except TypeError:
|
|
293
|
+
logger.debug(f"Result from delete_custom_dashboard: {result_dict} (not JSON serializable)")
|
|
294
|
+
|
|
295
|
+
return result_dict
|
|
296
|
+
|
|
297
|
+
except Exception as e:
|
|
298
|
+
logger.error(f"Error in delete_custom_dashboard: {e}", exc_info=True)
|
|
299
|
+
return {"error": f"Failed to delete custom dashboard: {e!s}"}
|
|
300
|
+
|
|
301
|
+
@register_as_tool
|
|
302
|
+
@with_header_auth(CustomDashboardsApi)
|
|
303
|
+
async def get_shareable_users(self,
|
|
304
|
+
dashboard_id: str,
|
|
305
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
306
|
+
"""
|
|
307
|
+
Get shareable users for a custom dashboard from Instana server.
|
|
308
|
+
This tool retrieves the list of users who can be granted access to a specific custom dashboard.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
dashboard_id: The ID of the custom dashboard
|
|
312
|
+
ctx: The MCP context (optional)
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
Dictionary containing shareable users data or error information
|
|
316
|
+
"""
|
|
317
|
+
try:
|
|
318
|
+
if not dashboard_id:
|
|
319
|
+
return {"error": "Dashboard ID is required for this operation"}
|
|
320
|
+
|
|
321
|
+
logger.debug(f"Getting shareable users for dashboard {dashboard_id} from Instana SDK")
|
|
322
|
+
|
|
323
|
+
# Call the get_shareable_users method from the SDK
|
|
324
|
+
result = api_client.get_shareable_users(dashboard_id=dashboard_id)
|
|
325
|
+
|
|
326
|
+
# Convert the result to a dictionary
|
|
327
|
+
result_dict: Dict[str, Any] = {}
|
|
328
|
+
|
|
329
|
+
if hasattr(result, 'to_dict'):
|
|
330
|
+
result_dict = result.to_dict()
|
|
331
|
+
elif isinstance(result, dict):
|
|
332
|
+
result_dict = result
|
|
333
|
+
elif isinstance(result, list):
|
|
334
|
+
# If it's a list, wrap it in a dictionary
|
|
335
|
+
result_dict = {"items": result}
|
|
336
|
+
else:
|
|
337
|
+
# For any other type, convert to string and wrap
|
|
338
|
+
result_dict = {"result": str(result)}
|
|
339
|
+
|
|
340
|
+
# Limit the response size
|
|
341
|
+
if "items" in result_dict and isinstance(result_dict["items"], list):
|
|
342
|
+
# Limit items to top 20
|
|
343
|
+
items_list = result_dict["items"]
|
|
344
|
+
original_count = len(items_list)
|
|
345
|
+
if original_count > 20:
|
|
346
|
+
result_dict["items"] = items_list[:20]
|
|
347
|
+
logger.debug(f"Limited response items from {original_count} to 20")
|
|
348
|
+
|
|
349
|
+
try:
|
|
350
|
+
logger.debug(f"Result from get_shareable_users: {json.dumps(result_dict, indent=2)}")
|
|
351
|
+
except TypeError:
|
|
352
|
+
logger.debug(f"Result from get_shareable_users: {result_dict} (not JSON serializable)")
|
|
353
|
+
|
|
354
|
+
return result_dict
|
|
355
|
+
|
|
356
|
+
except Exception as e:
|
|
357
|
+
logger.error(f"Error in get_shareable_users: {e}", exc_info=True)
|
|
358
|
+
return {"error": f"Failed to get shareable users: {e!s}"}
|
|
359
|
+
|
|
360
|
+
@register_as_tool
|
|
361
|
+
@with_header_auth(CustomDashboardsApi)
|
|
362
|
+
async def get_shareable_api_tokens(self,
|
|
363
|
+
dashboard_id: str,
|
|
364
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
365
|
+
"""
|
|
366
|
+
Get shareable API tokens for a custom dashboard from Instana server.
|
|
367
|
+
This tool retrieves the list of API tokens that can be used to access a specific custom dashboard.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
dashboard_id: The ID of the custom dashboard
|
|
371
|
+
ctx: The MCP context (optional)
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
Dictionary containing shareable API tokens data or error information
|
|
375
|
+
"""
|
|
376
|
+
try:
|
|
377
|
+
if not dashboard_id:
|
|
378
|
+
return {"error": "Dashboard ID is required for this operation"}
|
|
379
|
+
|
|
380
|
+
logger.debug(f"Getting shareable API tokens for dashboard {dashboard_id} from Instana SDK")
|
|
381
|
+
|
|
382
|
+
# Call the get_shareable_api_tokens method from the SDK
|
|
383
|
+
result = api_client.get_shareable_api_tokens(dashboard_id=dashboard_id)
|
|
384
|
+
|
|
385
|
+
# Convert the result to a dictionary
|
|
386
|
+
result_dict: Dict[str, Any] = {}
|
|
387
|
+
|
|
388
|
+
if hasattr(result, 'to_dict'):
|
|
389
|
+
result_dict = result.to_dict()
|
|
390
|
+
elif isinstance(result, dict):
|
|
391
|
+
result_dict = result
|
|
392
|
+
elif isinstance(result, list):
|
|
393
|
+
# If it's a list, wrap it in a dictionary
|
|
394
|
+
result_dict = {"items": result}
|
|
395
|
+
else:
|
|
396
|
+
# For any other type, convert to string and wrap
|
|
397
|
+
result_dict = {"result": str(result)}
|
|
398
|
+
|
|
399
|
+
# Limit the response size
|
|
400
|
+
if "items" in result_dict and isinstance(result_dict["items"], list):
|
|
401
|
+
# Limit items to top 10
|
|
402
|
+
items_list = result_dict["items"]
|
|
403
|
+
original_count = len(items_list)
|
|
404
|
+
if original_count > 10:
|
|
405
|
+
result_dict["items"] = items_list[:10]
|
|
406
|
+
logger.debug(f"Limited response items from {original_count} to 10")
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
logger.debug(f"Result from get_shareable_api_tokens: {json.dumps(result_dict, indent=2)}")
|
|
410
|
+
except TypeError:
|
|
411
|
+
logger.debug(f"Result from get_shareable_api_tokens: {result_dict} (not JSON serializable)")
|
|
412
|
+
|
|
413
|
+
return result_dict
|
|
414
|
+
|
|
415
|
+
except Exception as e:
|
|
416
|
+
logger.error(f"Error in get_shareable_api_tokens: {e}", exc_info=True)
|
|
417
|
+
return {"error": f"Failed to get shareable API tokens: {e!s}"}
|
src/website/__init__.py
ADDED
|
File without changes
|