suprema-biostar-mcp 1.0.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.
Files changed (61) hide show
  1. biostar_x_mcp_server/__init__.py +25 -0
  2. biostar_x_mcp_server/__main__.py +15 -0
  3. biostar_x_mcp_server/config.py +87 -0
  4. biostar_x_mcp_server/handlers/__init__.py +35 -0
  5. biostar_x_mcp_server/handlers/access_handler.py +2162 -0
  6. biostar_x_mcp_server/handlers/audit_handler.py +489 -0
  7. biostar_x_mcp_server/handlers/auth_handler.py +216 -0
  8. biostar_x_mcp_server/handlers/base_handler.py +228 -0
  9. biostar_x_mcp_server/handlers/card_handler.py +746 -0
  10. biostar_x_mcp_server/handlers/device_handler.py +4344 -0
  11. biostar_x_mcp_server/handlers/door_handler.py +3969 -0
  12. biostar_x_mcp_server/handlers/event_handler.py +1331 -0
  13. biostar_x_mcp_server/handlers/file_handler.py +212 -0
  14. biostar_x_mcp_server/handlers/help_web_handler.py +379 -0
  15. biostar_x_mcp_server/handlers/log_handler.py +1051 -0
  16. biostar_x_mcp_server/handlers/navigation_handler.py +109 -0
  17. biostar_x_mcp_server/handlers/occupancy_handler.py +541 -0
  18. biostar_x_mcp_server/handlers/user_handler.py +3568 -0
  19. biostar_x_mcp_server/schemas/__init__.py +21 -0
  20. biostar_x_mcp_server/schemas/access.py +158 -0
  21. biostar_x_mcp_server/schemas/audit.py +73 -0
  22. biostar_x_mcp_server/schemas/auth.py +24 -0
  23. biostar_x_mcp_server/schemas/cards.py +128 -0
  24. biostar_x_mcp_server/schemas/devices.py +496 -0
  25. biostar_x_mcp_server/schemas/doors.py +306 -0
  26. biostar_x_mcp_server/schemas/events.py +104 -0
  27. biostar_x_mcp_server/schemas/files.py +7 -0
  28. biostar_x_mcp_server/schemas/help.py +29 -0
  29. biostar_x_mcp_server/schemas/logs.py +33 -0
  30. biostar_x_mcp_server/schemas/occupancy.py +19 -0
  31. biostar_x_mcp_server/schemas/tool_response.py +29 -0
  32. biostar_x_mcp_server/schemas/users.py +166 -0
  33. biostar_x_mcp_server/server.py +335 -0
  34. biostar_x_mcp_server/session.py +221 -0
  35. biostar_x_mcp_server/tool_manager.py +172 -0
  36. biostar_x_mcp_server/tools/__init__.py +45 -0
  37. biostar_x_mcp_server/tools/access.py +510 -0
  38. biostar_x_mcp_server/tools/audit.py +227 -0
  39. biostar_x_mcp_server/tools/auth.py +59 -0
  40. biostar_x_mcp_server/tools/cards.py +269 -0
  41. biostar_x_mcp_server/tools/categories.py +197 -0
  42. biostar_x_mcp_server/tools/devices.py +1552 -0
  43. biostar_x_mcp_server/tools/doors.py +865 -0
  44. biostar_x_mcp_server/tools/events.py +305 -0
  45. biostar_x_mcp_server/tools/files.py +28 -0
  46. biostar_x_mcp_server/tools/help.py +80 -0
  47. biostar_x_mcp_server/tools/logs.py +123 -0
  48. biostar_x_mcp_server/tools/navigation.py +89 -0
  49. biostar_x_mcp_server/tools/occupancy.py +91 -0
  50. biostar_x_mcp_server/tools/users.py +1113 -0
  51. biostar_x_mcp_server/utils/__init__.py +31 -0
  52. biostar_x_mcp_server/utils/category_mapper.py +206 -0
  53. biostar_x_mcp_server/utils/decorators.py +101 -0
  54. biostar_x_mcp_server/utils/language_detector.py +51 -0
  55. biostar_x_mcp_server/utils/search.py +42 -0
  56. biostar_x_mcp_server/utils/timezone.py +122 -0
  57. suprema_biostar_mcp-1.0.1.dist-info/METADATA +163 -0
  58. suprema_biostar_mcp-1.0.1.dist-info/RECORD +61 -0
  59. suprema_biostar_mcp-1.0.1.dist-info/WHEEL +4 -0
  60. suprema_biostar_mcp-1.0.1.dist-info/entry_points.txt +2 -0
  61. suprema_biostar_mcp-1.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,227 @@
1
+ from mcp.types import Tool
2
+
3
+ # Audit search tool
4
+ AUDIT_SEARCH_TOOL = Tool(
5
+ name="audit-search",
6
+ description="Search audit trail logs in the BioStar 2 system",
7
+ inputSchema={
8
+ "type": "object",
9
+ "properties": {
10
+ "conditions": {
11
+ "type": "array",
12
+ "items": {
13
+ "type": "object",
14
+ "properties": {
15
+ "column": {
16
+ "type": "string",
17
+ "description": "Column to search (e.g., 'datetime', 'user_id', 'target_type')"
18
+ },
19
+ "operator": {
20
+ "type": "integer",
21
+ "description": "Search operator (0=EQUAL, 1=NOT_EQUAL, 2=CONTAINS, 3=BETWEEN, 5=GREATER, 6=LESS)"
22
+ },
23
+ "values": {
24
+ "type": "array",
25
+ "items": {"type": "string"},
26
+ "description": "Values to search for"
27
+ }
28
+ },
29
+ "required": ["column", "operator", "values"]
30
+ },
31
+ "description": "Search conditions for audit trail"
32
+ },
33
+ "limit": {
34
+ "type": "integer",
35
+ "description": "Maximum number of results",
36
+ "default": 100
37
+ },
38
+ "offset": {
39
+ "type": "integer",
40
+ "description": "Offset for pagination",
41
+ "default": 0
42
+ }
43
+ },
44
+ "required": []
45
+ }
46
+ )
47
+
48
+ # Audit search user tool
49
+ AUDIT_SEARCH_USER_TOOL = Tool(
50
+ name="audit-search-user",
51
+ description="Search for users by name",
52
+ inputSchema={
53
+ "type": "object",
54
+ "properties": {
55
+ "search": {
56
+ "type": "string",
57
+ "description": "Search string for user name"
58
+ },
59
+ "limit": {
60
+ "type": "integer",
61
+ "description": "Maximum number of results",
62
+ "default": 201
63
+ },
64
+ "offset": {
65
+ "type": "integer",
66
+ "description": "Offset for pagination",
67
+ "default": 0
68
+ }
69
+ },
70
+ "required": []
71
+ }
72
+ )
73
+
74
+ # Audit search operator level tool
75
+ AUDIT_SEARCH_OPERATOR_LEVEL_TOOL = Tool(
76
+ name="audit-search-operator-level",
77
+ description="Search for operator permission levels",
78
+ inputSchema={
79
+ "type": "object",
80
+ "properties": {
81
+ "search": {
82
+ "type": "string",
83
+ "description": "Search string for permission level"
84
+ },
85
+ "limit": {
86
+ "type": "integer",
87
+ "description": "Maximum number of results",
88
+ "default": 201
89
+ },
90
+ "offset": {
91
+ "type": "integer",
92
+ "description": "Offset for pagination",
93
+ "default": 0
94
+ }
95
+ },
96
+ "required": []
97
+ }
98
+ )
99
+
100
+ # Audit search IP list tool
101
+ AUDIT_SEARCH_IP_LIST_TOOL = Tool(
102
+ name="audit-search-ip-list",
103
+ description="Search for IP addresses",
104
+ inputSchema={
105
+ "type": "object",
106
+ "properties": {
107
+ "search": {
108
+ "type": "string",
109
+ "description": "Search string for IP address"
110
+ },
111
+ "limit": {
112
+ "type": "integer",
113
+ "description": "Maximum number of results",
114
+ "default": 201
115
+ },
116
+ "offset": {
117
+ "type": "integer",
118
+ "description": "Offset for pagination",
119
+ "default": 0
120
+ }
121
+ },
122
+ "required": []
123
+ }
124
+ )
125
+
126
+ # Audit search target list tool
127
+ AUDIT_SEARCH_TARGET_LIST_TOOL = Tool(
128
+ name="audit-search-target-list",
129
+ description="Search for audit targets",
130
+ inputSchema={
131
+ "type": "object",
132
+ "properties": {
133
+ "search": {
134
+ "type": "string",
135
+ "description": "Search string for target"
136
+ },
137
+ "limit": {
138
+ "type": "integer",
139
+ "description": "Maximum number of results",
140
+ "default": 201
141
+ },
142
+ "offset": {
143
+ "type": "integer",
144
+ "description": "Offset for pagination",
145
+ "default": 0
146
+ }
147
+ },
148
+ "required": []
149
+ }
150
+ )
151
+
152
+ AUDIT_CSV_EXPORT_TOOL = Tool(
153
+ name="audit-csv-export",
154
+ description="Export audit trail data to CSV via /api/audit/export and copy the file to the Windows Downloads folder.",
155
+ inputSchema={
156
+ "type": "object",
157
+ "properties": {
158
+ "conditions": {
159
+ "type": "array",
160
+ "items": {
161
+ "type": "object",
162
+ "properties": {
163
+ "column": {"type": "string"},
164
+ "operator": {"type": "integer"},
165
+ "values": {"type": "array", "items": {"type": "string"}}
166
+ },
167
+ "required": ["column", "operator", "values"]
168
+ },
169
+ "description": "Filter conditions (use 'DATE' for time)."
170
+ },
171
+ "columns": {
172
+ "type": "array",
173
+ "items": {"type": "string"},
174
+ "description": "CSV columns (UPPERCASE per API spec).",
175
+ "default": ["DATE","USRID","PERM","IP","MENU","TARGET","METHOD","CONTENT"]
176
+ },
177
+ "headers": {
178
+ "type": "array",
179
+ "items": {"type": "string"},
180
+ "description": "CSV header names (same length as columns).",
181
+ "default": ["Datetime","User","Operator Level","IP","Category","Target","Action","Modification"]
182
+ },
183
+ "offset": {
184
+ "type": "integer",
185
+ "description": "Offset for export pagination.",
186
+ "default": 0
187
+ },
188
+ "time_offset_minutes": {
189
+ "type": "integer",
190
+ "description": "Timezone offset in minutes (e.g., UTC+8 => 480).",
191
+ "default": 0
192
+ },
193
+ "start_datetime": {
194
+ "type": "string",
195
+ "description": "Convenience: start time (ISO). Builds a DATE condition if 'conditions' omitted."
196
+ },
197
+ "end_datetime": {
198
+ "type": "string",
199
+ "description": "Convenience: end time (ISO). Builds a DATE condition if 'conditions' omitted."
200
+ },
201
+ "copy_to_downloads": {
202
+ "type": "boolean",
203
+ "description": "Copy exported CSV to Windows Downloads folder.",
204
+ "default": True
205
+ },
206
+ "dest_dir": {
207
+ "type": "string",
208
+ "description": "Optional absolute destination directory (overrides Downloads)."
209
+ },
210
+ "target_username": {
211
+ "type": "string",
212
+ "description": "If provided, copies to C:\\Users\\<name>\\Downloads."
213
+ }
214
+ },
215
+ "required": []
216
+ }
217
+ )
218
+
219
+ # Export all audit tools
220
+ AUDIT_TOOLS = [
221
+ AUDIT_SEARCH_TOOL,
222
+ AUDIT_SEARCH_USER_TOOL,
223
+ AUDIT_SEARCH_OPERATOR_LEVEL_TOOL,
224
+ AUDIT_SEARCH_IP_LIST_TOOL,
225
+ AUDIT_SEARCH_TARGET_LIST_TOOL,
226
+ AUDIT_CSV_EXPORT_TOOL
227
+ ]
@@ -0,0 +1,59 @@
1
+ from mcp.types import Tool
2
+
3
+ # Authentication tools
4
+ LOGIN_TOOL = Tool(
5
+ name="login",
6
+ description="[ACTION TOOL - DEVELOPER USE ONLY] Perform actual login to BioStar X system via API. Use this ONLY when user explicitly asks to 'login now', 'authenticate now', 'connect now', or wants to perform actual system login operation. This is for programmatic API access, NOT for explaining how users login. For user login explanations, use vector-search-manual instead. By default uses credentials from .env file (developer configuration), but you can optionally provide different credentials.",
7
+ inputSchema={
8
+ "type": "object",
9
+ "properties": {
10
+ "username": {
11
+ "type": "string",
12
+ "description": "Optional: BioStar 2 username (defaults to BIOSTAR_USERNAME from .env)"
13
+ },
14
+ "password": {
15
+ "type": "string",
16
+ "description": "Optional: BioStar 2 password (defaults to BIOSTAR_PASSWORD from .env)"
17
+ }
18
+ },
19
+ "required": []
20
+ }
21
+ )
22
+
23
+ LOGOUT_TOOL = Tool(
24
+ name="logout",
25
+ description="[ACTION TOOL - DEVELOPER USE ONLY] Perform actual logout from BioStar X system via API. Use this ONLY when user explicitly asks to 'logout now' or wants to perform actual system logout operation. This is for programmatic API access, NOT for explaining how users logout. For user logout explanations, use vector-search-manual instead.",
26
+ inputSchema={
27
+ "type": "object",
28
+ "properties": {},
29
+ "required": []
30
+ }
31
+ )
32
+
33
+ GET_SESSION_INFO_TOOL = Tool(
34
+ name="get-session-info",
35
+ description="[ACTION TOOL - DEVELOPER USE ONLY] Get current API session information including user details. Use this ONLY when user explicitly asks to 'check session', 'get session info', or wants to query actual session status. This is for programmatic API access, NOT for explaining session management to users. For user session explanations, use vector-search-manual instead.",
36
+ inputSchema={
37
+ "type": "object",
38
+ "properties": {},
39
+ "required": []
40
+ }
41
+ )
42
+
43
+ GET_SERVER_PREFERENCES_TOOL = Tool(
44
+ name="get-server-preferences",
45
+ description="Get BioStar server preferences including timezone, language, date/time format. This is essential for displaying event times in the correct timezone.",
46
+ inputSchema={
47
+ "type": "object",
48
+ "properties": {},
49
+ "required": []
50
+ }
51
+ )
52
+
53
+ # List of all auth tools
54
+ AUTH_TOOLS = [
55
+ LOGIN_TOOL,
56
+ LOGOUT_TOOL,
57
+ GET_SESSION_INFO_TOOL,
58
+ GET_SERVER_PREFERENCES_TOOL
59
+ ]
@@ -0,0 +1,269 @@
1
+ from mcp.types import Tool
2
+
3
+ # ──────────────────────────────────────────────────────────────────────────────
4
+ # Card creation tools (one tool per card type)
5
+ # Names follow: create-card-{type}
6
+ # ──────────────────────────────────────────────────────────────────────────────
7
+
8
+ CREATE_CARD_CSN_TOOL = Tool(
9
+ name="create-card-csn",
10
+ description=(
11
+ "Create a **CSN** card via POST /api/cards.\n"
12
+ "Required: card_id.\n"
13
+ "Rules: ASCII digits only (0-9), no leading '0', length 1-32.\n"
14
+ "If 'card_type_type' is omitted, it will be auto-resolved from /api/cards/types (with fallback).\n"
15
+ "Optional: assign_to_user_id to immediately assign the created card to a user.\n"
16
+ "Use this tool to perform the action. Do NOT attempt to do this without the tool."
17
+ ),
18
+ inputSchema={
19
+ "type": "object",
20
+ "properties": {
21
+ "card_id": {
22
+ "oneOf": [{"type": "string"}, {"type": "integer"}],
23
+ "description": "Value shown/read when scanning the card"
24
+ },
25
+ "card_type_type": {
26
+ "type": "integer",
27
+ "description": "Type allocation of the card type; auto-resolved if omitted"
28
+ },
29
+ "assign_to_user_id": {
30
+ "oneOf": [{"type": "string"}, {"type": "integer"}],
31
+ "description": "If provided, assign the created card to this user immediately"
32
+ },
33
+ "skip_availability_check": {
34
+ "type": "boolean",
35
+ "description": "Skip server-side availability check before create (default: false)"
36
+ },
37
+ "dry_run": {
38
+ "type": "boolean",
39
+ "description": "Return the request body without calling the API (default: false)"
40
+ }
41
+ },
42
+ "required": ["card_id"]
43
+ }
44
+ )
45
+
46
+ CREATE_CARD_WIEGAND_TOOL = Tool(
47
+ name="create-card-wiegand",
48
+ description=(
49
+ "Create a **Wiegand** card via POST /api/cards.\n"
50
+ "Required: card_id (numeric), faciliy_code, card_number, and either wiegand_format_id or wiegand_format(alias).\n"
51
+ "The handler strictly validates ranges per format and will fail with: "
52
+ "'Format entered incorrectly. Support value is x~y.' When out of range.\n"
53
+ "display_card_id (if provided) must be numeric 'FC-ID' (e.g., '12-3456') and must match facility/card values.\n"
54
+ "If the user doesn't know the format id, call 'get-wiegand-format-presets' first and ask them to pick one."
55
+ ),
56
+ inputSchema={
57
+ "type": "object",
58
+ "properties": {
59
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}], "description": "Numeric required"},
60
+ "wiegand_format_id": {"type": "integer", "description": "Format id (e.g., 0=26bit/H10301, 1=HID37/H10302)"},
61
+ "wiegand_format": {"type": "string", "description": "Format alias (e.g., '26bit', 'H10301', 'HID37')"},
62
+ "facility_code": {"type": "integer", "description": "Facility Code (required)"},
63
+ "card_number": {"type": "integer", "description": "Card Number (required)"},
64
+ "display_card_id": {"type": "string", "description": "Override display (must be 'FC-ID', e.g., '12-3456')"},
65
+ "card_type_type": {"type": "integer"},
66
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
67
+ "skip_availability_check": {"type": "boolean"},
68
+ "dry_run": {"type": "boolean"},
69
+ },
70
+ "allOf": [
71
+ {
72
+ "anyOf": [
73
+ {"required": ["card_id", "wiegand_format_id"]},
74
+ {"required": ["card_id", "wiegand_format"]},
75
+ ]
76
+ },
77
+ {"required": ["facility_code", "card_number"]}
78
+ ],
79
+ }
80
+ )
81
+
82
+ CREATE_CARD_SECURE_CREDENTIAL_TOOL = Tool(
83
+ name="create-card-secure-credential",
84
+ description=(
85
+ "Create a **Secure Credential (Smart card)** via POST /api/cards.\n"
86
+ "Required: card_id. If 'card_type_type' is omitted, it will be auto-resolved."
87
+ ),
88
+ inputSchema={
89
+ "type": "object",
90
+ "properties": {
91
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
92
+ "card_type_type": {"type": "integer"},
93
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
94
+ "skip_availability_check": {"type": "boolean"},
95
+ "dry_run": {"type": "boolean"}
96
+ },
97
+ "required": ["card_id"]
98
+ }
99
+ )
100
+
101
+ CREATE_CARD_ACCESS_ON_CARD_TOOL = Tool(
102
+ name="create-card-access-on-card",
103
+ description=(
104
+ "Create an **Access on Card (Smart card)** via POST /api/cards.\n"
105
+ "Required: card_id. If 'card_type_type' is omitted, it will be auto-resolved."
106
+ ),
107
+ inputSchema={
108
+ "type": "object",
109
+ "properties": {
110
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
111
+ "card_type_type": {"type": "integer"},
112
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
113
+ "skip_availability_check": {"type": "boolean"},
114
+ "dry_run": {"type": "boolean"}
115
+ },
116
+ "required": ["card_id"]
117
+ }
118
+ )
119
+
120
+ CREATE_CARD_MOBILE_CSN_TOOL = Tool(
121
+ name="create-card-mobile-csn",
122
+ description=(
123
+ "Create a **Mobile CSN** card via POST /api/cards.\n"
124
+ "Required: card_id. Optional: isUserPhoto, isDepartment, isTitle, "
125
+ "start_datetime, expiry_datetime, display_card_id."
126
+ ),
127
+ inputSchema={
128
+ "type": "object",
129
+ "properties": {
130
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
131
+ "card_type_type": {"type": "integer"},
132
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
133
+ "isUserPhoto": {"type": "boolean"},
134
+ "isDepartment": {"type": "boolean"},
135
+ "isTitle": {"type": "boolean"},
136
+ "start_datetime": {"type": "string"},
137
+ "expiry_datetime": {"type": "string"},
138
+ "display_card_id": {"type": "string"},
139
+ "skip_availability_check": {"type": "boolean"},
140
+ "dry_run": {"type": "boolean"}
141
+ },
142
+ "required": ["card_id"]
143
+ }
144
+ )
145
+
146
+ CREATE_CARD_WIEGAND_MOBILE_TOOL = Tool(
147
+ name="create-card-wiegand-mobile",
148
+ description=(
149
+ "Create a **Wiegand Mobile** card via POST /api/cards.\n"
150
+ "Required: card_id (numeric), facility_code, card_number, and either wiegand_format_id or wiegand_format(alias).\n"
151
+ "Handler strictly validates ranges per format and rejects invalid values with the supported ranges."
152
+ ),
153
+ inputSchema={
154
+ "type": "object",
155
+ "properties": {
156
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
157
+ "wiegand_format_id": {"type": "integer"},
158
+ "wiegand_format": {"type": "string"},
159
+ "facility_code": {"type": "integer"},
160
+ "card_number": {"type": "integer"},
161
+ "display_card_id": {"type": "string"},
162
+ "card_type_type": {"type": "integer"},
163
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
164
+ "skip_availability_check": {"type": "boolean"},
165
+ "dry_run": {"type": "boolean"}
166
+ },
167
+ "allOf": [
168
+ {
169
+ "anyOf": [
170
+ {"required": ["card_id", "wiegand_format_id"]},
171
+ {"required": ["card_id", "wiegand_format"]},
172
+ ]
173
+ },
174
+ {"required": ["facility_code", "card_number"]}
175
+ ],
176
+ }
177
+ )
178
+
179
+ CREATE_CARD_QR_BARCODE_TOOL = Tool(
180
+ name="create-card-qr-barcode",
181
+ description=(
182
+ "Create a **QR/Barcode** card via POST /api/cards.\n"
183
+ "Required: card_id. If 'card_type_type' is omitted, it will be auto-resolved."
184
+ ),
185
+ inputSchema={
186
+ "type": "object",
187
+ "properties": {
188
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
189
+ "card_type_type": {"type": "integer"},
190
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
191
+ "skip_availability_check": {"type": "boolean"},
192
+ "dry_run": {"type": "boolean"}
193
+ },
194
+ "required": ["card_id"]
195
+ }
196
+ )
197
+
198
+ CREATE_CARD_BIOSTAR2_QR_TOOL = Tool(
199
+ name="create-card-biostar2-qr",
200
+ description=(
201
+ "Create a **BioStar 2 QR** card via POST /api/cards.\n"
202
+ "Required: card_id. If 'card_type_type' is omitted, it will be auto-resolved."
203
+ ),
204
+ inputSchema={
205
+ "type": "object",
206
+ "properties": {
207
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
208
+ "card_type_type": {"type": "integer"},
209
+ "assign_to_user_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
210
+ "skip_availability_check": {"type": "boolean"},
211
+ "dry_run": {"type": "boolean"}
212
+ },
213
+ "required": ["card_id"]
214
+ }
215
+ )
216
+
217
+ # ──────────────────────────────────────────────────────────────────────────────
218
+ # Supporting tools (UX helpers)
219
+ # ──────────────────────────────────────────────────────────────────────────────
220
+
221
+ GET_CARD_TYPES_TOOL = Tool(
222
+ name="get-card-types",
223
+ description=(
224
+ "Fetch valid card types and their 'type' allocations from GET /api/cards/types.\n"
225
+ "Use this to determine valid values for 'card_type.type' when creating cards."
226
+ ),
227
+ inputSchema={"type": "object", "properties": {}, "required": []}
228
+ )
229
+
230
+ CHECK_CARD_AVAILABILITY_TOOL = Tool(
231
+ name="check-card-availability",
232
+ description=(
233
+ "Check if a given card_id is available (not existing) before creation.\n"
234
+ "If the endpoint is unavailable in your BioStar version, the handler will return a best-effort result."
235
+ ),
236
+ inputSchema={
237
+ "type": "object",
238
+ "properties": {
239
+ "card_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]}
240
+ },
241
+ "required": ["card_id"]
242
+ }
243
+ )
244
+
245
+ GET_WIEGAND_FORMAT_PRESETS_TOOL = Tool(
246
+ name="get-wiegand-format-presets",
247
+ description=(
248
+ "Return common Wiegand formats with IDs, aliases, and supported ranges (facility_code/card_number).\n"
249
+ "Use this to prompt the user to pick a format before creating a Wiegand/Wiegand Mobile card."
250
+ ),
251
+ inputSchema={"type": "object", "properties": {}, "required": []}
252
+ )
253
+
254
+ # Group for easy import
255
+ CARD_TOOLS = [
256
+ CREATE_CARD_CSN_TOOL,
257
+ CREATE_CARD_WIEGAND_TOOL,
258
+
259
+ # CREATE_CARD_SECURE_CREDENTIAL_TOOL,
260
+ # CREATE_CARD_ACCESS_ON_CARD_TOOL,
261
+ # CREATE_CARD_MOBILE_CSN_TOOL,
262
+ # CREATE_CARD_WIEGAND_MOBILE_TOOL,
263
+ # CREATE_CARD_QR_BARCODE_TOOL,
264
+ # CREATE_CARD_BIOSTAR2_QR_TOOL,
265
+
266
+ GET_CARD_TYPES_TOOL,
267
+ CHECK_CARD_AVAILABILITY_TOOL,
268
+ GET_WIEGAND_FORMAT_PRESETS_TOOL,
269
+ ]