mcp-eregistrations-bpa 0.8.5__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.

Potentially problematic release.


This version of mcp-eregistrations-bpa might be problematic. Click here for more details.

Files changed (66) hide show
  1. mcp_eregistrations_bpa/__init__.py +121 -0
  2. mcp_eregistrations_bpa/__main__.py +6 -0
  3. mcp_eregistrations_bpa/arazzo/__init__.py +21 -0
  4. mcp_eregistrations_bpa/arazzo/expression.py +379 -0
  5. mcp_eregistrations_bpa/audit/__init__.py +56 -0
  6. mcp_eregistrations_bpa/audit/context.py +66 -0
  7. mcp_eregistrations_bpa/audit/logger.py +236 -0
  8. mcp_eregistrations_bpa/audit/models.py +131 -0
  9. mcp_eregistrations_bpa/auth/__init__.py +64 -0
  10. mcp_eregistrations_bpa/auth/callback.py +391 -0
  11. mcp_eregistrations_bpa/auth/cas.py +409 -0
  12. mcp_eregistrations_bpa/auth/oidc.py +252 -0
  13. mcp_eregistrations_bpa/auth/permissions.py +162 -0
  14. mcp_eregistrations_bpa/auth/token_manager.py +348 -0
  15. mcp_eregistrations_bpa/bpa_client/__init__.py +84 -0
  16. mcp_eregistrations_bpa/bpa_client/client.py +740 -0
  17. mcp_eregistrations_bpa/bpa_client/endpoints.py +193 -0
  18. mcp_eregistrations_bpa/bpa_client/errors.py +276 -0
  19. mcp_eregistrations_bpa/bpa_client/models.py +203 -0
  20. mcp_eregistrations_bpa/config.py +349 -0
  21. mcp_eregistrations_bpa/db/__init__.py +21 -0
  22. mcp_eregistrations_bpa/db/connection.py +64 -0
  23. mcp_eregistrations_bpa/db/migrations.py +168 -0
  24. mcp_eregistrations_bpa/exceptions.py +39 -0
  25. mcp_eregistrations_bpa/py.typed +0 -0
  26. mcp_eregistrations_bpa/rollback/__init__.py +19 -0
  27. mcp_eregistrations_bpa/rollback/manager.py +616 -0
  28. mcp_eregistrations_bpa/server.py +152 -0
  29. mcp_eregistrations_bpa/tools/__init__.py +372 -0
  30. mcp_eregistrations_bpa/tools/actions.py +155 -0
  31. mcp_eregistrations_bpa/tools/analysis.py +352 -0
  32. mcp_eregistrations_bpa/tools/audit.py +399 -0
  33. mcp_eregistrations_bpa/tools/behaviours.py +1042 -0
  34. mcp_eregistrations_bpa/tools/bots.py +627 -0
  35. mcp_eregistrations_bpa/tools/classifications.py +575 -0
  36. mcp_eregistrations_bpa/tools/costs.py +765 -0
  37. mcp_eregistrations_bpa/tools/debug_strategies.py +351 -0
  38. mcp_eregistrations_bpa/tools/debugger.py +1230 -0
  39. mcp_eregistrations_bpa/tools/determinants.py +2235 -0
  40. mcp_eregistrations_bpa/tools/document_requirements.py +670 -0
  41. mcp_eregistrations_bpa/tools/export.py +899 -0
  42. mcp_eregistrations_bpa/tools/fields.py +162 -0
  43. mcp_eregistrations_bpa/tools/form_errors.py +36 -0
  44. mcp_eregistrations_bpa/tools/formio_helpers.py +971 -0
  45. mcp_eregistrations_bpa/tools/forms.py +1269 -0
  46. mcp_eregistrations_bpa/tools/jsonlogic_builder.py +466 -0
  47. mcp_eregistrations_bpa/tools/large_response.py +163 -0
  48. mcp_eregistrations_bpa/tools/messages.py +523 -0
  49. mcp_eregistrations_bpa/tools/notifications.py +241 -0
  50. mcp_eregistrations_bpa/tools/registration_institutions.py +680 -0
  51. mcp_eregistrations_bpa/tools/registrations.py +897 -0
  52. mcp_eregistrations_bpa/tools/role_status.py +447 -0
  53. mcp_eregistrations_bpa/tools/role_units.py +400 -0
  54. mcp_eregistrations_bpa/tools/roles.py +1236 -0
  55. mcp_eregistrations_bpa/tools/rollback.py +335 -0
  56. mcp_eregistrations_bpa/tools/services.py +674 -0
  57. mcp_eregistrations_bpa/tools/workflows.py +2487 -0
  58. mcp_eregistrations_bpa/tools/yaml_transformer.py +991 -0
  59. mcp_eregistrations_bpa/workflows/__init__.py +28 -0
  60. mcp_eregistrations_bpa/workflows/loader.py +440 -0
  61. mcp_eregistrations_bpa/workflows/models.py +336 -0
  62. mcp_eregistrations_bpa-0.8.5.dist-info/METADATA +965 -0
  63. mcp_eregistrations_bpa-0.8.5.dist-info/RECORD +66 -0
  64. mcp_eregistrations_bpa-0.8.5.dist-info/WHEEL +4 -0
  65. mcp_eregistrations_bpa-0.8.5.dist-info/entry_points.txt +2 -0
  66. mcp_eregistrations_bpa-0.8.5.dist-info/licenses/LICENSE +86 -0
@@ -0,0 +1,152 @@
1
+ """MCP server for eRegistrations BPA platform."""
2
+
3
+ from fastmcp import FastMCP
4
+
5
+ from mcp_eregistrations_bpa.auth import (
6
+ TokenManager,
7
+ perform_browser_login,
8
+ perform_cas_browser_login,
9
+ )
10
+ from mcp_eregistrations_bpa.config import AuthProvider, load_config
11
+ from mcp_eregistrations_bpa.tools import (
12
+ register_action_tools,
13
+ register_analysis_tools,
14
+ register_audit_tools,
15
+ register_behaviour_tools,
16
+ register_bot_tools,
17
+ register_classification_tools,
18
+ register_cost_tools,
19
+ register_debug_tools,
20
+ register_determinant_tools,
21
+ register_document_requirement_tools,
22
+ register_export_tools,
23
+ register_field_tools,
24
+ register_form_tools,
25
+ register_message_tools,
26
+ register_notification_tools,
27
+ register_registration_institution_tools,
28
+ register_registration_tools,
29
+ register_role_status_tools,
30
+ register_role_tools,
31
+ register_role_unit_tools,
32
+ register_rollback_tools,
33
+ register_service_tools,
34
+ register_workflow_tools,
35
+ )
36
+
37
+ mcp = FastMCP("eregistrations-bpa")
38
+
39
+ # Register BPA tools
40
+ register_service_tools(mcp)
41
+ register_registration_tools(mcp)
42
+ register_registration_institution_tools(mcp)
43
+ register_field_tools(mcp)
44
+ register_form_tools(mcp)
45
+ register_determinant_tools(mcp)
46
+ register_action_tools(mcp)
47
+ register_behaviour_tools(mcp)
48
+ register_bot_tools(mcp)
49
+ register_classification_tools(mcp)
50
+ register_notification_tools(mcp)
51
+ register_message_tools(mcp)
52
+ register_role_tools(mcp)
53
+ register_role_status_tools(mcp)
54
+ register_role_unit_tools(mcp)
55
+ register_document_requirement_tools(mcp)
56
+ register_cost_tools(mcp)
57
+ register_analysis_tools(mcp)
58
+ register_audit_tools(mcp)
59
+ register_rollback_tools(mcp)
60
+ register_export_tools(mcp)
61
+ register_workflow_tools(mcp)
62
+ register_debug_tools(mcp)
63
+
64
+ # Global token manager instance (in-memory storage)
65
+ _token_manager = TokenManager()
66
+
67
+
68
+ @mcp.tool()
69
+ async def auth_login() -> dict[str, object]:
70
+ """Authenticate with BPA via browser-based Keycloak login.
71
+
72
+ This tool initiates the OIDC authentication flow:
73
+ 1. Discovers Keycloak endpoints from BPA instance
74
+ 2. Opens browser to Keycloak login page
75
+ 3. Waits for callback with authorization code
76
+ 4. Exchanges code for tokens
77
+ 5. Returns success with user info
78
+
79
+ Returns:
80
+ dict: Authentication result with user email and session duration.
81
+ """
82
+ config = load_config()
83
+
84
+ if config.auth_provider == AuthProvider.CAS:
85
+ return await perform_cas_browser_login()
86
+ else:
87
+ return await perform_browser_login()
88
+
89
+
90
+ async def get_connection_status() -> dict[str, object]:
91
+ """Get current BPA connection status (internal implementation).
92
+
93
+ Returns connection state, authenticated user, permissions, and session info.
94
+ This is a read-only operation that does not trigger token refresh.
95
+
96
+ Returns:
97
+ dict: Connection status with instance URL, instance_id, user, permissions,
98
+ and expiry.
99
+ """
100
+ config = load_config()
101
+
102
+ # Check if not authenticated
103
+ if not _token_manager.is_authenticated():
104
+ return {
105
+ "connected": False,
106
+ "instance_id": config.instance_id,
107
+ "instance_url": config.bpa_instance_url,
108
+ "message": "Not authenticated. Run auth_login to connect.",
109
+ }
110
+
111
+ # Check if token has already expired
112
+ if _token_manager.is_token_expired():
113
+ return {
114
+ "connected": False,
115
+ "instance_id": config.instance_id,
116
+ "instance_url": config.bpa_instance_url,
117
+ "message": "Session expired. Run auth_login to reconnect.",
118
+ }
119
+
120
+ # Return full authenticated status
121
+ return {
122
+ "connected": True,
123
+ "instance_id": config.instance_id,
124
+ "instance_url": config.bpa_instance_url,
125
+ "user": _token_manager.user_email,
126
+ "permissions": _token_manager.permissions,
127
+ "session_expires_in": f"{_token_manager.expires_in_minutes} minutes",
128
+ }
129
+
130
+
131
+ @mcp.tool()
132
+ async def connection_status() -> dict[str, object]:
133
+ """View current BPA connection status.
134
+
135
+ Returns connection state, authenticated user, permissions, and session info.
136
+ This is a read-only operation that does not trigger token refresh.
137
+
138
+ Returns:
139
+ dict: Connection status with instance URL, user, permissions, and expiry.
140
+ """
141
+ return await get_connection_status()
142
+
143
+
144
+ def get_token_manager() -> TokenManager:
145
+ """Get the global token manager instance.
146
+
147
+ This is used by other modules to access the authenticated session.
148
+
149
+ Returns:
150
+ The global TokenManager instance.
151
+ """
152
+ return _token_manager
@@ -0,0 +1,372 @@
1
+ """MCP tools for BPA operations.
2
+
3
+ This module provides tools for interacting with the BPA API through MCP.
4
+ """
5
+
6
+ from mcp_eregistrations_bpa.tools.actions import (
7
+ componentaction_get,
8
+ componentaction_get_by_component,
9
+ register_action_tools,
10
+ )
11
+ from mcp_eregistrations_bpa.tools.analysis import (
12
+ analyze_service,
13
+ register_analysis_tools,
14
+ )
15
+ from mcp_eregistrations_bpa.tools.audit import (
16
+ audit_get,
17
+ audit_list,
18
+ register_audit_tools,
19
+ )
20
+ from mcp_eregistrations_bpa.tools.behaviours import (
21
+ componentbehaviour_get,
22
+ componentbehaviour_get_by_component,
23
+ componentbehaviour_list,
24
+ effect_create,
25
+ effect_delete,
26
+ register_behaviour_tools,
27
+ )
28
+ from mcp_eregistrations_bpa.tools.bots import (
29
+ bot_create,
30
+ bot_delete,
31
+ bot_get,
32
+ bot_list,
33
+ bot_update,
34
+ register_bot_tools,
35
+ )
36
+ from mcp_eregistrations_bpa.tools.classifications import (
37
+ classification_create,
38
+ classification_export_csv,
39
+ classification_get,
40
+ classification_list,
41
+ classification_update,
42
+ register_classification_tools,
43
+ )
44
+ from mcp_eregistrations_bpa.tools.costs import (
45
+ cost_create_fixed,
46
+ cost_create_formula,
47
+ cost_delete,
48
+ cost_update,
49
+ register_cost_tools,
50
+ )
51
+ from mcp_eregistrations_bpa.tools.debugger import (
52
+ debug_fix,
53
+ debug_fix_batch,
54
+ debug_group_issues,
55
+ debug_investigate,
56
+ debug_plan,
57
+ debug_scan,
58
+ debug_verify,
59
+ register_debug_tools,
60
+ )
61
+ from mcp_eregistrations_bpa.tools.determinants import (
62
+ booleandeterminant_create,
63
+ classificationdeterminant_create,
64
+ datedeterminant_create,
65
+ determinant_delete,
66
+ determinant_get,
67
+ determinant_list,
68
+ determinant_search,
69
+ griddeterminant_create,
70
+ numericdeterminant_create,
71
+ register_determinant_tools,
72
+ selectdeterminant_create,
73
+ textdeterminant_create,
74
+ textdeterminant_update,
75
+ )
76
+ from mcp_eregistrations_bpa.tools.document_requirements import (
77
+ documentrequirement_create,
78
+ documentrequirement_delete,
79
+ documentrequirement_list,
80
+ documentrequirement_update,
81
+ register_document_requirement_tools,
82
+ requirement_list,
83
+ )
84
+ from mcp_eregistrations_bpa.tools.export import (
85
+ register_export_tools,
86
+ service_copy,
87
+ service_export_raw,
88
+ service_to_yaml,
89
+ )
90
+ from mcp_eregistrations_bpa.tools.fields import (
91
+ field_get,
92
+ field_list,
93
+ register_field_tools,
94
+ )
95
+ from mcp_eregistrations_bpa.tools.formio_helpers import (
96
+ build_checkbox,
97
+ build_columns,
98
+ build_number,
99
+ build_panel,
100
+ build_select,
101
+ build_textarea,
102
+ build_textfield,
103
+ )
104
+ from mcp_eregistrations_bpa.tools.forms import (
105
+ form_component_add,
106
+ form_component_get,
107
+ form_component_move,
108
+ form_component_remove,
109
+ form_component_update,
110
+ form_get,
111
+ form_update,
112
+ register_form_tools,
113
+ )
114
+ from mcp_eregistrations_bpa.tools.messages import (
115
+ message_create,
116
+ message_delete,
117
+ message_get,
118
+ message_list,
119
+ message_update,
120
+ register_message_tools,
121
+ )
122
+ from mcp_eregistrations_bpa.tools.notifications import (
123
+ notification_create,
124
+ notification_list,
125
+ register_notification_tools,
126
+ )
127
+ from mcp_eregistrations_bpa.tools.registration_institutions import (
128
+ institution_create,
129
+ institution_discover,
130
+ register_registration_institution_tools,
131
+ registrationinstitution_create,
132
+ registrationinstitution_delete,
133
+ registrationinstitution_get,
134
+ registrationinstitution_list,
135
+ registrationinstitution_list_by_institution,
136
+ )
137
+ from mcp_eregistrations_bpa.tools.registrations import (
138
+ register_registration_tools,
139
+ registration_activate,
140
+ registration_create,
141
+ registration_delete,
142
+ registration_get,
143
+ registration_list,
144
+ serviceregistration_link,
145
+ )
146
+ from mcp_eregistrations_bpa.tools.role_status import (
147
+ register_role_status_tools,
148
+ rolestatus_create,
149
+ rolestatus_delete,
150
+ rolestatus_get,
151
+ rolestatus_update,
152
+ )
153
+ from mcp_eregistrations_bpa.tools.role_units import (
154
+ register_role_unit_tools,
155
+ roleunit_create,
156
+ roleunit_delete,
157
+ roleunit_get,
158
+ roleunit_list,
159
+ )
160
+ from mcp_eregistrations_bpa.tools.roles import (
161
+ register_role_tools,
162
+ role_create,
163
+ role_delete,
164
+ role_get,
165
+ role_list,
166
+ role_update,
167
+ roleinstitution_create,
168
+ roleregistration_create,
169
+ )
170
+ from mcp_eregistrations_bpa.tools.rollback import (
171
+ register_rollback_tools,
172
+ rollback,
173
+ rollback_cleanup,
174
+ rollback_history,
175
+ )
176
+ from mcp_eregistrations_bpa.tools.services import (
177
+ register_service_tools,
178
+ service_activate,
179
+ service_create,
180
+ service_get,
181
+ service_list,
182
+ service_publish,
183
+ service_update,
184
+ )
185
+ from mcp_eregistrations_bpa.tools.workflows import (
186
+ register_workflow_tools,
187
+ workflow_cancel,
188
+ workflow_chain,
189
+ workflow_confirm,
190
+ workflow_continue,
191
+ workflow_describe,
192
+ workflow_execute,
193
+ workflow_list,
194
+ workflow_retry,
195
+ workflow_rollback,
196
+ workflow_search,
197
+ workflow_start_interactive,
198
+ workflow_status,
199
+ )
200
+
201
+ __all__ = [
202
+ # Service tools
203
+ "service_list",
204
+ "service_get",
205
+ "service_create",
206
+ "service_update",
207
+ "service_publish",
208
+ "service_activate",
209
+ "register_service_tools",
210
+ # Registration tools
211
+ "registration_list",
212
+ "registration_get",
213
+ "registration_create",
214
+ "registration_delete",
215
+ "registration_activate",
216
+ "serviceregistration_link",
217
+ "register_registration_tools",
218
+ # Registration institution tools
219
+ "registrationinstitution_list",
220
+ "registrationinstitution_get",
221
+ "registrationinstitution_create",
222
+ "registrationinstitution_delete",
223
+ "registrationinstitution_list_by_institution",
224
+ "institution_discover",
225
+ "institution_create",
226
+ "register_registration_institution_tools",
227
+ # Field tools
228
+ "field_list",
229
+ "field_get",
230
+ "register_field_tools",
231
+ # Form tools
232
+ "form_get",
233
+ "form_component_get",
234
+ "form_component_add",
235
+ "form_component_update",
236
+ "form_component_remove",
237
+ "form_component_move",
238
+ "form_update",
239
+ "register_form_tools",
240
+ # Form.io component builders
241
+ "build_textfield",
242
+ "build_number",
243
+ "build_select",
244
+ "build_checkbox",
245
+ "build_textarea",
246
+ "build_panel",
247
+ "build_columns",
248
+ # Determinant tools
249
+ "determinant_list",
250
+ "determinant_get",
251
+ "determinant_search",
252
+ "determinant_delete",
253
+ "textdeterminant_create",
254
+ "textdeterminant_update",
255
+ "selectdeterminant_create",
256
+ "numericdeterminant_create",
257
+ "booleandeterminant_create",
258
+ "datedeterminant_create",
259
+ "classificationdeterminant_create",
260
+ "griddeterminant_create",
261
+ "register_determinant_tools",
262
+ # Behaviour/Effect tools
263
+ "componentbehaviour_list",
264
+ "componentbehaviour_get",
265
+ "componentbehaviour_get_by_component",
266
+ "effect_create",
267
+ "effect_delete",
268
+ "register_behaviour_tools",
269
+ # Component action tools
270
+ "componentaction_get",
271
+ "componentaction_get_by_component",
272
+ "register_action_tools",
273
+ # Bot tools
274
+ "bot_list",
275
+ "bot_get",
276
+ "bot_create",
277
+ "bot_update",
278
+ "bot_delete",
279
+ "register_bot_tools",
280
+ # Classification tools
281
+ "classification_list",
282
+ "classification_get",
283
+ "classification_create",
284
+ "classification_update",
285
+ "classification_export_csv",
286
+ "register_classification_tools",
287
+ # Notification tools
288
+ "notification_list",
289
+ "notification_create",
290
+ "register_notification_tools",
291
+ # Role tools
292
+ "role_list",
293
+ "role_get",
294
+ "role_create",
295
+ "role_update",
296
+ "role_delete",
297
+ "roleinstitution_create",
298
+ "roleregistration_create",
299
+ "register_role_tools",
300
+ # Role status tools
301
+ "rolestatus_get",
302
+ "rolestatus_create",
303
+ "rolestatus_update",
304
+ "rolestatus_delete",
305
+ "register_role_status_tools",
306
+ # Role unit tools
307
+ "roleunit_list",
308
+ "roleunit_get",
309
+ "roleunit_create",
310
+ "roleunit_delete",
311
+ "register_role_unit_tools",
312
+ # Message tools
313
+ "message_list",
314
+ "message_get",
315
+ "message_create",
316
+ "message_update",
317
+ "message_delete",
318
+ "register_message_tools",
319
+ # Analysis tools
320
+ "analyze_service",
321
+ "register_analysis_tools",
322
+ # Document requirement tools
323
+ "requirement_list",
324
+ "documentrequirement_list",
325
+ "documentrequirement_create",
326
+ "documentrequirement_update",
327
+ "documentrequirement_delete",
328
+ "register_document_requirement_tools",
329
+ # Cost tools
330
+ "cost_create_fixed",
331
+ "cost_create_formula",
332
+ "cost_update",
333
+ "cost_delete",
334
+ "register_cost_tools",
335
+ # Audit tools
336
+ "audit_list",
337
+ "audit_get",
338
+ "register_audit_tools",
339
+ # Rollback tools
340
+ "rollback",
341
+ "rollback_history",
342
+ "rollback_cleanup",
343
+ "register_rollback_tools",
344
+ # Export tools
345
+ "service_export_raw",
346
+ "service_to_yaml",
347
+ "service_copy",
348
+ "register_export_tools",
349
+ # Workflow orchestration tools
350
+ "workflow_list",
351
+ "workflow_describe",
352
+ "workflow_search",
353
+ "workflow_execute",
354
+ "workflow_status",
355
+ "workflow_cancel",
356
+ "workflow_retry",
357
+ "workflow_rollback",
358
+ "workflow_chain",
359
+ "workflow_start_interactive",
360
+ "workflow_continue",
361
+ "workflow_confirm",
362
+ "register_workflow_tools",
363
+ # Debug tools
364
+ "debug_scan",
365
+ "debug_investigate",
366
+ "debug_fix",
367
+ "debug_fix_batch",
368
+ "debug_group_issues",
369
+ "debug_plan",
370
+ "debug_verify",
371
+ "register_debug_tools",
372
+ ]
@@ -0,0 +1,155 @@
1
+ """Component action tools for BPA API.
2
+
3
+ This module provides MCP tools for retrieving component actions
4
+ from the BPA API. Component actions define workflow automation
5
+ configured for form components.
6
+
7
+ Tools:
8
+ componentaction_get: Get component actions by ID
9
+ componentaction_get_by_component: Get actions for a form component
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+ from mcp.server.fastmcp.exceptions import ToolError
17
+
18
+ from mcp_eregistrations_bpa.bpa_client import BPAClient
19
+ from mcp_eregistrations_bpa.bpa_client.errors import (
20
+ BPAClientError,
21
+ BPANotFoundError,
22
+ translate_error,
23
+ )
24
+
25
+ __all__ = [
26
+ "componentaction_get",
27
+ "componentaction_get_by_component",
28
+ "register_action_tools",
29
+ ]
30
+
31
+
32
+ async def componentaction_get(id: str) -> dict[str, Any]:
33
+ """Get component actions by ID.
34
+
35
+ Args:
36
+ id: The unique identifier of the component actions record.
37
+
38
+ Returns:
39
+ dict with id, service_id, component_key, actions.
40
+ """
41
+ try:
42
+ async with BPAClient() as client:
43
+ try:
44
+ data = await client.get(
45
+ "/componentactions/{id}",
46
+ path_params={"id": id},
47
+ resource_type="componentactions",
48
+ resource_id=id,
49
+ )
50
+ except BPANotFoundError:
51
+ raise ToolError(
52
+ f"ComponentActions '{id}' not found. Verify the ID is correct."
53
+ )
54
+ except ToolError:
55
+ raise
56
+ except BPAClientError as e:
57
+ raise translate_error(e, resource_type="componentactions", resource_id=id)
58
+
59
+ return _transform_component_actions(data)
60
+
61
+
62
+ async def componentaction_get_by_component(
63
+ service_id: str | int, component_key: str
64
+ ) -> dict[str, Any]:
65
+ """Get component actions for a specific form component.
66
+
67
+ Args:
68
+ service_id: The service containing the component.
69
+ component_key: The form component key/identifier.
70
+
71
+ Returns:
72
+ dict with id, service_id, component_key, actions.
73
+ """
74
+ try:
75
+ async with BPAClient() as client:
76
+ try:
77
+ data = await client.get(
78
+ "/service/{service_id}/componentactions/{component_key}",
79
+ path_params={
80
+ "service_id": service_id,
81
+ "component_key": component_key,
82
+ },
83
+ resource_type="componentactions",
84
+ )
85
+ except BPANotFoundError:
86
+ raise ToolError(
87
+ f"No actions found for component '{component_key}' "
88
+ f"in service '{service_id}'."
89
+ )
90
+ except ToolError:
91
+ raise
92
+ except BPAClientError as e:
93
+ raise translate_error(e, resource_type="componentactions")
94
+
95
+ return _transform_component_actions(data)
96
+
97
+
98
+ def _transform_bot(bot: dict[str, Any]) -> dict[str, Any]:
99
+ """Transform a bot object from camelCase to snake_case.
100
+
101
+ Args:
102
+ bot: Raw bot object from API.
103
+
104
+ Returns:
105
+ dict: Transformed bot with snake_case keys.
106
+ """
107
+ return {
108
+ "bot_type": bot.get("botType"),
109
+ "name": bot.get("name"),
110
+ "description": bot.get("description"),
111
+ "enabled": bot.get("enabled", True),
112
+ }
113
+
114
+
115
+ def _transform_component_actions(data: dict[str, Any]) -> dict[str, Any]:
116
+ """Transform API response to snake_case format.
117
+
118
+ Args:
119
+ data: Raw API response with camelCase keys.
120
+
121
+ Returns:
122
+ dict: Transformed response with snake_case keys.
123
+ """
124
+ actions = []
125
+ for action in data.get("actions", []):
126
+ bots = [_transform_bot(bot) for bot in action.get("bots", [])]
127
+ actions.append(
128
+ {
129
+ "id": action.get("id"),
130
+ "json_determinants": action.get("jsonDeterminants"),
131
+ "bots": bots,
132
+ "sort_order": action.get("sortOrderNumber"),
133
+ "parallel": action.get("parallel", False),
134
+ "mandatory": action.get("mandatory", False),
135
+ "multiple_bot": action.get("multipleBot", False),
136
+ "multiple_field_key": action.get("multipleFieldKey"),
137
+ }
138
+ )
139
+
140
+ return {
141
+ "id": data.get("id"),
142
+ "service_id": data.get("serviceId"),
143
+ "component_key": data.get("componentKey"),
144
+ "actions": actions,
145
+ }
146
+
147
+
148
+ def register_action_tools(mcp: Any) -> None:
149
+ """Register action tools with the MCP server.
150
+
151
+ Args:
152
+ mcp: The FastMCP server instance.
153
+ """
154
+ mcp.tool()(componentaction_get)
155
+ mcp.tool()(componentaction_get_by_component)