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.
- mcp_eregistrations_bpa/__init__.py +121 -0
- mcp_eregistrations_bpa/__main__.py +6 -0
- mcp_eregistrations_bpa/arazzo/__init__.py +21 -0
- mcp_eregistrations_bpa/arazzo/expression.py +379 -0
- mcp_eregistrations_bpa/audit/__init__.py +56 -0
- mcp_eregistrations_bpa/audit/context.py +66 -0
- mcp_eregistrations_bpa/audit/logger.py +236 -0
- mcp_eregistrations_bpa/audit/models.py +131 -0
- mcp_eregistrations_bpa/auth/__init__.py +64 -0
- mcp_eregistrations_bpa/auth/callback.py +391 -0
- mcp_eregistrations_bpa/auth/cas.py +409 -0
- mcp_eregistrations_bpa/auth/oidc.py +252 -0
- mcp_eregistrations_bpa/auth/permissions.py +162 -0
- mcp_eregistrations_bpa/auth/token_manager.py +348 -0
- mcp_eregistrations_bpa/bpa_client/__init__.py +84 -0
- mcp_eregistrations_bpa/bpa_client/client.py +740 -0
- mcp_eregistrations_bpa/bpa_client/endpoints.py +193 -0
- mcp_eregistrations_bpa/bpa_client/errors.py +276 -0
- mcp_eregistrations_bpa/bpa_client/models.py +203 -0
- mcp_eregistrations_bpa/config.py +349 -0
- mcp_eregistrations_bpa/db/__init__.py +21 -0
- mcp_eregistrations_bpa/db/connection.py +64 -0
- mcp_eregistrations_bpa/db/migrations.py +168 -0
- mcp_eregistrations_bpa/exceptions.py +39 -0
- mcp_eregistrations_bpa/py.typed +0 -0
- mcp_eregistrations_bpa/rollback/__init__.py +19 -0
- mcp_eregistrations_bpa/rollback/manager.py +616 -0
- mcp_eregistrations_bpa/server.py +152 -0
- mcp_eregistrations_bpa/tools/__init__.py +372 -0
- mcp_eregistrations_bpa/tools/actions.py +155 -0
- mcp_eregistrations_bpa/tools/analysis.py +352 -0
- mcp_eregistrations_bpa/tools/audit.py +399 -0
- mcp_eregistrations_bpa/tools/behaviours.py +1042 -0
- mcp_eregistrations_bpa/tools/bots.py +627 -0
- mcp_eregistrations_bpa/tools/classifications.py +575 -0
- mcp_eregistrations_bpa/tools/costs.py +765 -0
- mcp_eregistrations_bpa/tools/debug_strategies.py +351 -0
- mcp_eregistrations_bpa/tools/debugger.py +1230 -0
- mcp_eregistrations_bpa/tools/determinants.py +2235 -0
- mcp_eregistrations_bpa/tools/document_requirements.py +670 -0
- mcp_eregistrations_bpa/tools/export.py +899 -0
- mcp_eregistrations_bpa/tools/fields.py +162 -0
- mcp_eregistrations_bpa/tools/form_errors.py +36 -0
- mcp_eregistrations_bpa/tools/formio_helpers.py +971 -0
- mcp_eregistrations_bpa/tools/forms.py +1269 -0
- mcp_eregistrations_bpa/tools/jsonlogic_builder.py +466 -0
- mcp_eregistrations_bpa/tools/large_response.py +163 -0
- mcp_eregistrations_bpa/tools/messages.py +523 -0
- mcp_eregistrations_bpa/tools/notifications.py +241 -0
- mcp_eregistrations_bpa/tools/registration_institutions.py +680 -0
- mcp_eregistrations_bpa/tools/registrations.py +897 -0
- mcp_eregistrations_bpa/tools/role_status.py +447 -0
- mcp_eregistrations_bpa/tools/role_units.py +400 -0
- mcp_eregistrations_bpa/tools/roles.py +1236 -0
- mcp_eregistrations_bpa/tools/rollback.py +335 -0
- mcp_eregistrations_bpa/tools/services.py +674 -0
- mcp_eregistrations_bpa/tools/workflows.py +2487 -0
- mcp_eregistrations_bpa/tools/yaml_transformer.py +991 -0
- mcp_eregistrations_bpa/workflows/__init__.py +28 -0
- mcp_eregistrations_bpa/workflows/loader.py +440 -0
- mcp_eregistrations_bpa/workflows/models.py +336 -0
- mcp_eregistrations_bpa-0.8.5.dist-info/METADATA +965 -0
- mcp_eregistrations_bpa-0.8.5.dist-info/RECORD +66 -0
- mcp_eregistrations_bpa-0.8.5.dist-info/WHEEL +4 -0
- mcp_eregistrations_bpa-0.8.5.dist-info/entry_points.txt +2 -0
- mcp_eregistrations_bpa-0.8.5.dist-info/licenses/LICENSE +86 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""MCP tools for BPA field operations.
|
|
2
|
+
|
|
3
|
+
This module provides tools for listing and retrieving BPA form fields.
|
|
4
|
+
Fields are accessed through service endpoints (service-centric API design).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.server.fastmcp.exceptions import ToolError
|
|
12
|
+
|
|
13
|
+
from mcp_eregistrations_bpa.bpa_client import BPAClient
|
|
14
|
+
from mcp_eregistrations_bpa.bpa_client.errors import (
|
|
15
|
+
BPAClientError,
|
|
16
|
+
BPANotFoundError,
|
|
17
|
+
translate_error,
|
|
18
|
+
)
|
|
19
|
+
from mcp_eregistrations_bpa.tools.large_response import large_response_handler
|
|
20
|
+
|
|
21
|
+
__all__ = ["field_list", "field_get", "register_field_tools"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@large_response_handler(
|
|
25
|
+
threshold_bytes=50 * 1024, # 50KB threshold for list tools
|
|
26
|
+
navigation={
|
|
27
|
+
"list_all": "jq '.fields'",
|
|
28
|
+
"find_by_type": "jq '.fields[] | select(.type == \"textfield\")'",
|
|
29
|
+
"find_by_key": "jq '.fields[] | select(.key | contains(\"search\"))'",
|
|
30
|
+
"required_only": "jq '.fields[] | select(.required == true)'",
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
async def field_list(
|
|
34
|
+
service_id: str | int,
|
|
35
|
+
limit: int = 50,
|
|
36
|
+
offset: int = 0,
|
|
37
|
+
type_filter: str | None = None,
|
|
38
|
+
required_only: bool = False,
|
|
39
|
+
) -> dict[str, Any]:
|
|
40
|
+
"""List fields for a service with pagination and filtering.
|
|
41
|
+
|
|
42
|
+
Large responses (>50KB) are saved to file with navigation hints.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
service_id: The service ID to list fields for.
|
|
46
|
+
limit: Maximum number of fields to return (default: 50).
|
|
47
|
+
offset: Number of fields to skip (default: 0).
|
|
48
|
+
type_filter: Filter by field type (e.g., "select", "textfield").
|
|
49
|
+
required_only: Filter to only required fields (default: False).
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
dict with fields, total, has_more, service_id.
|
|
53
|
+
"""
|
|
54
|
+
# Normalize pagination parameters
|
|
55
|
+
if limit <= 0:
|
|
56
|
+
limit = 50
|
|
57
|
+
if offset < 0:
|
|
58
|
+
offset = 0
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
async with BPAClient() as client:
|
|
62
|
+
fields_data = await client.get_list(
|
|
63
|
+
"/service/{service_id}/fields",
|
|
64
|
+
path_params={"service_id": service_id},
|
|
65
|
+
resource_type="field",
|
|
66
|
+
)
|
|
67
|
+
except BPAClientError as e:
|
|
68
|
+
raise translate_error(e, resource_type="field")
|
|
69
|
+
|
|
70
|
+
# Transform to consistent output format with snake_case keys
|
|
71
|
+
all_fields = []
|
|
72
|
+
for field in fields_data:
|
|
73
|
+
field_obj: dict[str, Any] = {
|
|
74
|
+
"key": field.get("key"),
|
|
75
|
+
"name": field.get("name"),
|
|
76
|
+
"type": field.get("type"),
|
|
77
|
+
"required": field.get("required", False),
|
|
78
|
+
"label": field.get("label"),
|
|
79
|
+
}
|
|
80
|
+
# Only include component_key if it has a value (remove null noise)
|
|
81
|
+
if field.get("componentKey"):
|
|
82
|
+
field_obj["component_key"] = field.get("componentKey")
|
|
83
|
+
all_fields.append(field_obj)
|
|
84
|
+
|
|
85
|
+
# Apply filters before sorting/pagination
|
|
86
|
+
if type_filter is not None:
|
|
87
|
+
all_fields = [f for f in all_fields if f.get("type") == type_filter]
|
|
88
|
+
|
|
89
|
+
if required_only:
|
|
90
|
+
all_fields = [f for f in all_fields if f.get("required") is True]
|
|
91
|
+
|
|
92
|
+
# Sort by key for consistent pagination ordering
|
|
93
|
+
all_fields.sort(key=lambda f: f.get("key") or "")
|
|
94
|
+
|
|
95
|
+
# Calculate total before pagination
|
|
96
|
+
total = len(all_fields)
|
|
97
|
+
|
|
98
|
+
# Apply pagination
|
|
99
|
+
paginated_fields = all_fields[offset : offset + limit]
|
|
100
|
+
|
|
101
|
+
# Calculate has_more
|
|
102
|
+
has_more = (offset + limit) < total
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"fields": paginated_fields,
|
|
106
|
+
"total": total,
|
|
107
|
+
"has_more": has_more,
|
|
108
|
+
"service_id": service_id,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def field_get(service_id: str | int, field_key: str) -> dict[str, Any]:
|
|
113
|
+
"""Get details of a BPA field by service ID and field key.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
service_id: The service containing the field.
|
|
117
|
+
field_key: The field key/identifier within the service.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
dict with key, name, label, type, required, component_key, service_id.
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
async with BPAClient() as client:
|
|
124
|
+
try:
|
|
125
|
+
field_data = await client.get(
|
|
126
|
+
"/service/{service_id}/fields/{field_key}",
|
|
127
|
+
path_params={"service_id": service_id, "field_key": field_key},
|
|
128
|
+
resource_type="field",
|
|
129
|
+
resource_id=field_key,
|
|
130
|
+
)
|
|
131
|
+
except BPANotFoundError:
|
|
132
|
+
raise ToolError(
|
|
133
|
+
f"Field '{field_key}' not found in service '{service_id}'. "
|
|
134
|
+
"Use 'field_list' with the service_id to see available fields."
|
|
135
|
+
)
|
|
136
|
+
except ToolError:
|
|
137
|
+
raise
|
|
138
|
+
except BPAClientError as e:
|
|
139
|
+
raise translate_error(e, resource_type="field", resource_id=field_key)
|
|
140
|
+
|
|
141
|
+
result = {
|
|
142
|
+
"key": field_data.get("key"),
|
|
143
|
+
"name": field_data.get("name"),
|
|
144
|
+
"label": field_data.get("label"),
|
|
145
|
+
"type": field_data.get("type"),
|
|
146
|
+
"required": field_data.get("required", False),
|
|
147
|
+
"service_id": service_id,
|
|
148
|
+
}
|
|
149
|
+
# Only include component_key if it has a value (remove null noise)
|
|
150
|
+
if field_data.get("componentKey"):
|
|
151
|
+
result["component_key"] = field_data.get("componentKey")
|
|
152
|
+
return result
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def register_field_tools(mcp: Any) -> None:
|
|
156
|
+
"""Register field tools with the MCP server.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
mcp: The FastMCP server instance.
|
|
160
|
+
"""
|
|
161
|
+
mcp.tool()(field_list)
|
|
162
|
+
mcp.tool()(field_get)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Form tool error codes for programmatic handling.
|
|
2
|
+
|
|
3
|
+
This module defines error codes for Form MCP tool operations.
|
|
4
|
+
Error codes follow the format: FORM_XXX where XXX is a 3-digit number.
|
|
5
|
+
|
|
6
|
+
Usage in ToolError messages:
|
|
7
|
+
raise ToolError(f"[{FormErrorCode.DUPLICATE_KEY}] Component key already exists")
|
|
8
|
+
|
|
9
|
+
The format "[ERROR_CODE] message" allows automation tools to:
|
|
10
|
+
1. Parse the error code programmatically
|
|
11
|
+
2. Handle specific error types differently
|
|
12
|
+
3. Provide localized error messages
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FormErrorCode:
|
|
19
|
+
"""Error codes for Form MCP tool operations.
|
|
20
|
+
|
|
21
|
+
Error codes are strings in the format FORM_XXX.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# Validation errors (001-010)
|
|
25
|
+
INVALID_FORM_TYPE = "FORM_001"
|
|
26
|
+
SERVICE_NOT_FOUND = "FORM_002"
|
|
27
|
+
COMPONENT_NOT_FOUND = "FORM_003"
|
|
28
|
+
DUPLICATE_KEY = "FORM_004"
|
|
29
|
+
INVALID_PARENT = "FORM_005"
|
|
30
|
+
MISSING_REQUIRED_PROPERTY = "FORM_006"
|
|
31
|
+
KEY_CHANGE_NOT_ALLOWED = "FORM_007"
|
|
32
|
+
INVALID_POSITION = "FORM_008"
|
|
33
|
+
CIRCULAR_REFERENCE = "FORM_009"
|
|
34
|
+
|
|
35
|
+
# Additional operation errors (010-020)
|
|
36
|
+
NO_UPDATES_PROVIDED = "FORM_010"
|