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,336 @@
1
+ """Data models for Arazzo workflow definitions.
2
+
3
+ These models represent the parsed structure of Arazzo workflow specifications,
4
+ optimized for MCP tool consumption and workflow execution.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from enum import Enum
11
+ from typing import Any
12
+
13
+
14
+ class InputType(Enum):
15
+ """Supported input types for workflow parameters."""
16
+
17
+ STRING = "string"
18
+ INTEGER = "integer"
19
+ NUMBER = "number"
20
+ BOOLEAN = "boolean"
21
+ ARRAY = "array"
22
+ OBJECT = "object"
23
+
24
+
25
+ @dataclass
26
+ class WorkflowInput:
27
+ """Definition of a workflow input parameter.
28
+
29
+ Attributes:
30
+ name: The input parameter name.
31
+ input_type: The type of the input (string, integer, boolean, etc.).
32
+ required: Whether this input is required.
33
+ description: Human-readable description of the input.
34
+ default: Default value if not provided.
35
+ enum_values: List of allowed values for enum inputs.
36
+ pattern: Regex pattern for string validation.
37
+ min_length: Minimum length for string inputs.
38
+ max_length: Maximum length for string inputs.
39
+ minimum: Minimum value for numeric inputs.
40
+ maximum: Maximum value for numeric inputs.
41
+ """
42
+
43
+ name: str
44
+ input_type: InputType = InputType.STRING
45
+ required: bool = False
46
+ description: str = ""
47
+ default: Any = None
48
+ enum_values: list[str] | None = None
49
+ pattern: str | None = None
50
+ min_length: int | None = None
51
+ max_length: int | None = None
52
+ minimum: float | None = None
53
+ maximum: float | None = None
54
+
55
+ def to_dict(self) -> dict[str, Any]:
56
+ """Convert to dictionary for API response."""
57
+ result: dict[str, Any] = {
58
+ "name": self.name,
59
+ "type": self.input_type.value,
60
+ "required": self.required,
61
+ }
62
+ if self.description:
63
+ result["description"] = self.description
64
+ if self.default is not None:
65
+ result["default"] = self.default
66
+ if self.enum_values:
67
+ result["enum"] = self.enum_values
68
+ if self.pattern:
69
+ result["pattern"] = self.pattern
70
+ if self.min_length is not None:
71
+ result["minLength"] = self.min_length
72
+ if self.max_length is not None:
73
+ result["maxLength"] = self.max_length
74
+ if self.minimum is not None:
75
+ result["minimum"] = self.minimum
76
+ if self.maximum is not None:
77
+ result["maximum"] = self.maximum
78
+ return result
79
+
80
+
81
+ @dataclass
82
+ class WorkflowStep:
83
+ """Definition of a single step in a workflow.
84
+
85
+ Attributes:
86
+ step_id: Unique identifier for this step within the workflow.
87
+ description: Human-readable description of what this step does.
88
+ operation_id: The BPA API operation ID (optional).
89
+ mcp_tool: The MCP tool to invoke for this step (derived from operationId).
90
+ request_body: The request body template with input references.
91
+ parameters: Path/query parameters for the API call.
92
+ success_criteria: Conditions for step success.
93
+ on_success: Actions to take on success (goto next step, end).
94
+ on_failure: Actions to take on failure.
95
+ outputs: Output mappings from response to step outputs.
96
+ condition: Optional condition for conditional step execution.
97
+ """
98
+
99
+ step_id: str
100
+ description: str = ""
101
+ operation_id: str | None = None
102
+ mcp_tool: str | None = None
103
+ request_body: dict[str, Any] = field(default_factory=dict)
104
+ parameters: list[dict[str, Any]] = field(default_factory=list)
105
+ success_criteria: list[dict[str, Any]] = field(default_factory=list)
106
+ on_success: list[dict[str, Any]] = field(default_factory=list)
107
+ on_failure: list[dict[str, Any]] = field(default_factory=list)
108
+ outputs: dict[str, str] = field(default_factory=dict)
109
+ condition: str | None = None
110
+
111
+ def to_dict(self) -> dict[str, Any]:
112
+ """Convert to dictionary for API response."""
113
+ result: dict[str, Any] = {
114
+ "step_id": self.step_id,
115
+ "description": self.description,
116
+ }
117
+ if self.mcp_tool:
118
+ result["tool"] = self.mcp_tool
119
+ if self.outputs:
120
+ result["outputs"] = list(self.outputs.keys())
121
+ if self.condition:
122
+ result["condition"] = self.condition
123
+ return result
124
+
125
+
126
+ @dataclass
127
+ class WorkflowDefinition:
128
+ """Complete definition of an Arazzo workflow.
129
+
130
+ Attributes:
131
+ workflow_id: Unique identifier for the workflow.
132
+ summary: Short summary of what the workflow does.
133
+ description: Detailed description with usage examples.
134
+ category: Category for grouping related workflows.
135
+ inputs: List of input parameter definitions.
136
+ steps: List of workflow steps to execute.
137
+ outputs: Output mappings from step outputs to workflow outputs.
138
+ failure_actions: Actions to take on workflow failure.
139
+ source_file: Path to the source Arazzo file.
140
+ """
141
+
142
+ workflow_id: str
143
+ summary: str = ""
144
+ description: str = ""
145
+ category: str = "general"
146
+ inputs: list[WorkflowInput] = field(default_factory=list)
147
+ steps: list[WorkflowStep] = field(default_factory=list)
148
+ outputs: dict[str, str] = field(default_factory=dict)
149
+ failure_actions: list[dict[str, Any]] = field(default_factory=list)
150
+ source_file: str = ""
151
+
152
+ @property
153
+ def required_inputs(self) -> list[str]:
154
+ """Get list of required input names."""
155
+ return [inp.name for inp in self.inputs if inp.required]
156
+
157
+ @property
158
+ def optional_inputs(self) -> list[str]:
159
+ """Get list of optional input names."""
160
+ return [inp.name for inp in self.inputs if not inp.required]
161
+
162
+ def get_input(self, name: str) -> WorkflowInput | None:
163
+ """Get input definition by name."""
164
+ for inp in self.inputs:
165
+ if inp.name == name:
166
+ return inp
167
+ return None
168
+
169
+ def to_catalog_entry(self) -> dict[str, Any]:
170
+ """Convert to catalog entry format (summary view)."""
171
+ return {
172
+ "id": self.workflow_id,
173
+ "summary": self.summary,
174
+ "category": self.category,
175
+ "required_inputs": self.required_inputs,
176
+ "optional_inputs": self.optional_inputs,
177
+ }
178
+
179
+ def to_detail_dict(self) -> dict[str, Any]:
180
+ """Convert to detailed format for workflow_describe."""
181
+ return {
182
+ "id": self.workflow_id,
183
+ "summary": self.summary,
184
+ "description": self.description,
185
+ "category": self.category,
186
+ "inputs": {inp.name: inp.to_dict() for inp in self.inputs},
187
+ "steps": [step.to_dict() for step in self.steps],
188
+ "outputs": list(self.outputs.keys()),
189
+ "source_file": self.source_file,
190
+ }
191
+
192
+
193
+ # Mapping from Arazzo operationId to MCP tool names
194
+ OPERATION_TO_TOOL_MAP: dict[str, str] = {
195
+ # Service operations
196
+ "createService": "service_create",
197
+ "updateService": "service_update",
198
+ "getService": "service_get",
199
+ "listServices": "service_list",
200
+ # Registration operations
201
+ "createRegistration": "registration_create",
202
+ "updateRegistration": "registration_update",
203
+ "getRegistration": "registration_get",
204
+ "listRegistrations": "registration_list",
205
+ # Role operations
206
+ "createRole": "role_create",
207
+ "updateRole": "role_update",
208
+ "deleteRole": "role_delete",
209
+ "getRole": "role_get",
210
+ "listRoles": "role_list",
211
+ # Bot operations
212
+ "createBot": "bot_create",
213
+ "updateBot": "bot_update",
214
+ "getBot": "bot_get",
215
+ "listBots": "bot_list",
216
+ # Determinant operations
217
+ "createTextDeterminant": "textdeterminant_create",
218
+ "updateTextDeterminant": "textdeterminant_update",
219
+ "createSelectDeterminant": "selectdeterminant_create",
220
+ "createNumericDeterminant": "numericdeterminant_create",
221
+ "createBooleanDeterminant": "booleandeterminant_create",
222
+ "createDateDeterminant": "datedeterminant_create",
223
+ "createClassificationDeterminant": "classificationdeterminant_create",
224
+ "createGridDeterminant": "griddeterminant_create",
225
+ "createRadioDeterminant": "selectdeterminant_create",
226
+ "getDeterminant": "determinant_get",
227
+ "listDeterminants": "determinant_list",
228
+ "deleteDeterminant": "determinant_delete",
229
+ # Document requirement operations
230
+ "createDocumentRequirement": "documentrequirement_create",
231
+ "updateDocumentRequirement": "documentrequirement_update",
232
+ "deleteDocumentRequirement": "documentrequirement_delete",
233
+ "listDocumentRequirements": "documentrequirement_list",
234
+ # Cost operations
235
+ "createFixedCost": "cost_create_fixed",
236
+ "createFormulaCost": "cost_create_formula",
237
+ "updateCost": "cost_update",
238
+ "deleteCost": "cost_delete",
239
+ # Field operations
240
+ "getField": "field_get",
241
+ "listFields": "field_list",
242
+ # Service-registration link operations
243
+ "linkServiceRegistration": "serviceregistration_link",
244
+ # Registration institution operations
245
+ "assignRegistrationInstitution": "registrationinstitution_create",
246
+ "listRegistrationInstitutions": "registrationinstitution_list",
247
+ "getRegistrationInstitution": "registrationinstitution_get",
248
+ "deleteRegistrationInstitution": "registrationinstitution_delete",
249
+ # Service lifecycle operations
250
+ "publishService": "service_publish",
251
+ "activateService": "service_activate",
252
+ # Delete operations
253
+ "deleteRegistration": "registration_delete",
254
+ "deleteBot": "bot_delete",
255
+ # Classification operations
256
+ "listClassifications": "classification_list",
257
+ "getClassification": "classification_get",
258
+ "createClassification": "classification_create",
259
+ "updateClassification": "classification_update",
260
+ "exportCatalogToCsv": "classification_export_csv",
261
+ # Notification operations
262
+ "listNotifications": "notification_list",
263
+ "createNotification": "notification_create",
264
+ # Role status operations
265
+ "getRoleStatus": "rolestatus_get",
266
+ "createUserDefinedRoleStatus": "rolestatus_create",
267
+ "updateUserDefinedRoleStatus": "rolestatus_update",
268
+ "deleteRoleStatus": "rolestatus_delete",
269
+ }
270
+
271
+
272
+ def derive_category(workflow_id: str, summary: str, description: str) -> str:
273
+ """Derive workflow category from its ID and content.
274
+
275
+ Args:
276
+ workflow_id: The workflow ID.
277
+ summary: The workflow summary.
278
+ description: The workflow description.
279
+
280
+ Returns:
281
+ A category string for grouping.
282
+ """
283
+ workflow_lower = workflow_id.lower()
284
+ combined = f"{summary} {description}".lower()
285
+
286
+ # Service creation (Story 10-6: catch createCompleteService, createMinimalService)
287
+ if (
288
+ "create" in workflow_lower and "service" in workflow_lower
289
+ ) or "create a service" in combined:
290
+ return "service-creation"
291
+
292
+ # Role configuration
293
+ if "role" in workflow_lower or "role" in combined:
294
+ return "roles-configuration"
295
+
296
+ # Bot configuration
297
+ if "bot" in workflow_lower or "automation" in combined:
298
+ return "automation"
299
+
300
+ # Form configuration
301
+ if "form" in workflow_lower or "field" in workflow_lower:
302
+ return "forms"
303
+
304
+ # Payment configuration
305
+ if "payment" in workflow_lower or "cost" in workflow_lower:
306
+ return "payments"
307
+
308
+ # Determinant configuration
309
+ if "determinant" in workflow_lower:
310
+ return "determinants"
311
+
312
+ # Document configuration
313
+ if "document" in workflow_lower:
314
+ return "documents"
315
+
316
+ # Notification configuration
317
+ if "notification" in workflow_lower:
318
+ return "notifications"
319
+
320
+ # Classification configuration (includes catalog operations)
321
+ if "classification" in workflow_lower or "catalog" in workflow_lower:
322
+ return "classifications"
323
+
324
+ # Institution configuration
325
+ if "institution" in workflow_lower:
326
+ return "institutions"
327
+
328
+ # Workflow configuration
329
+ if "workflow" in workflow_lower:
330
+ return "workflow"
331
+
332
+ # Publishing
333
+ if "publish" in workflow_lower:
334
+ return "publishing"
335
+
336
+ return "general"