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.
- biostar_x_mcp_server/__init__.py +25 -0
- biostar_x_mcp_server/__main__.py +15 -0
- biostar_x_mcp_server/config.py +87 -0
- biostar_x_mcp_server/handlers/__init__.py +35 -0
- biostar_x_mcp_server/handlers/access_handler.py +2162 -0
- biostar_x_mcp_server/handlers/audit_handler.py +489 -0
- biostar_x_mcp_server/handlers/auth_handler.py +216 -0
- biostar_x_mcp_server/handlers/base_handler.py +228 -0
- biostar_x_mcp_server/handlers/card_handler.py +746 -0
- biostar_x_mcp_server/handlers/device_handler.py +4344 -0
- biostar_x_mcp_server/handlers/door_handler.py +3969 -0
- biostar_x_mcp_server/handlers/event_handler.py +1331 -0
- biostar_x_mcp_server/handlers/file_handler.py +212 -0
- biostar_x_mcp_server/handlers/help_web_handler.py +379 -0
- biostar_x_mcp_server/handlers/log_handler.py +1051 -0
- biostar_x_mcp_server/handlers/navigation_handler.py +109 -0
- biostar_x_mcp_server/handlers/occupancy_handler.py +541 -0
- biostar_x_mcp_server/handlers/user_handler.py +3568 -0
- biostar_x_mcp_server/schemas/__init__.py +21 -0
- biostar_x_mcp_server/schemas/access.py +158 -0
- biostar_x_mcp_server/schemas/audit.py +73 -0
- biostar_x_mcp_server/schemas/auth.py +24 -0
- biostar_x_mcp_server/schemas/cards.py +128 -0
- biostar_x_mcp_server/schemas/devices.py +496 -0
- biostar_x_mcp_server/schemas/doors.py +306 -0
- biostar_x_mcp_server/schemas/events.py +104 -0
- biostar_x_mcp_server/schemas/files.py +7 -0
- biostar_x_mcp_server/schemas/help.py +29 -0
- biostar_x_mcp_server/schemas/logs.py +33 -0
- biostar_x_mcp_server/schemas/occupancy.py +19 -0
- biostar_x_mcp_server/schemas/tool_response.py +29 -0
- biostar_x_mcp_server/schemas/users.py +166 -0
- biostar_x_mcp_server/server.py +335 -0
- biostar_x_mcp_server/session.py +221 -0
- biostar_x_mcp_server/tool_manager.py +172 -0
- biostar_x_mcp_server/tools/__init__.py +45 -0
- biostar_x_mcp_server/tools/access.py +510 -0
- biostar_x_mcp_server/tools/audit.py +227 -0
- biostar_x_mcp_server/tools/auth.py +59 -0
- biostar_x_mcp_server/tools/cards.py +269 -0
- biostar_x_mcp_server/tools/categories.py +197 -0
- biostar_x_mcp_server/tools/devices.py +1552 -0
- biostar_x_mcp_server/tools/doors.py +865 -0
- biostar_x_mcp_server/tools/events.py +305 -0
- biostar_x_mcp_server/tools/files.py +28 -0
- biostar_x_mcp_server/tools/help.py +80 -0
- biostar_x_mcp_server/tools/logs.py +123 -0
- biostar_x_mcp_server/tools/navigation.py +89 -0
- biostar_x_mcp_server/tools/occupancy.py +91 -0
- biostar_x_mcp_server/tools/users.py +1113 -0
- biostar_x_mcp_server/utils/__init__.py +31 -0
- biostar_x_mcp_server/utils/category_mapper.py +206 -0
- biostar_x_mcp_server/utils/decorators.py +101 -0
- biostar_x_mcp_server/utils/language_detector.py +51 -0
- biostar_x_mcp_server/utils/search.py +42 -0
- biostar_x_mcp_server/utils/timezone.py +122 -0
- suprema_biostar_mcp-1.0.1.dist-info/METADATA +163 -0
- suprema_biostar_mcp-1.0.1.dist-info/RECORD +61 -0
- suprema_biostar_mcp-1.0.1.dist-info/WHEEL +4 -0
- suprema_biostar_mcp-1.0.1.dist-info/entry_points.txt +2 -0
- suprema_biostar_mcp-1.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1113 @@
|
|
|
1
|
+
from mcp.types import Tool
|
|
2
|
+
|
|
3
|
+
# User management tools
|
|
4
|
+
GET_USERS_TOOL = Tool(
|
|
5
|
+
name="get-users",
|
|
6
|
+
description="[ACTION TOOL] Retrieve a list of all users from BioStar X system. Use this when user asks to 'list users', 'show users', 'get all users', 'display users', or needs user information. This performs actual system operations - do NOT use vector search for this.",
|
|
7
|
+
inputSchema={
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {},
|
|
10
|
+
"required": []
|
|
11
|
+
}
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
CREATE_USER_TOOL = Tool(
|
|
15
|
+
name="create-user",
|
|
16
|
+
description="[ACTION TOOL] Create a new user in BioStar X system. Use this when user explicitly asks to 'create user', 'add user', 'register user', 'new user', or 'make user'. This performs actual system operations - do NOT use vector search for this.",
|
|
17
|
+
inputSchema={
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"name": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "User's full name (max 48 characters)"
|
|
23
|
+
},
|
|
24
|
+
"email": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "User's email address"
|
|
27
|
+
},
|
|
28
|
+
"department": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Department name (max 64 characters)"
|
|
31
|
+
},
|
|
32
|
+
"user_title": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "Job title"
|
|
35
|
+
},
|
|
36
|
+
"phone": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Phone number"
|
|
39
|
+
},
|
|
40
|
+
"disabled": {
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"description": "Whether the user is disabled (default: false)"
|
|
43
|
+
},
|
|
44
|
+
"access_groups": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": {"type": "integer"},
|
|
47
|
+
"description": "List of access group IDs"
|
|
48
|
+
},
|
|
49
|
+
"pin": {
|
|
50
|
+
"type": "integer",
|
|
51
|
+
"description": "PIN number (up to 32 digits)"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"required": ["name"]
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
GET_USER_TOOL = Tool(
|
|
59
|
+
name="get-user",
|
|
60
|
+
description="Get detailed information about a specific user",
|
|
61
|
+
inputSchema={
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {
|
|
64
|
+
"user_id": {
|
|
65
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
66
|
+
"description": "The ID of the user to retrieve"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"required": ["user_id"]
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
UPDATE_USER_TOOL = Tool(
|
|
74
|
+
name="update-user",
|
|
75
|
+
description="Update an existing user's information. Supports flexible date formats (20251225, 12.25.2025, 2025-12-25) and access group names.",
|
|
76
|
+
inputSchema={
|
|
77
|
+
"type": "object",
|
|
78
|
+
"properties": {
|
|
79
|
+
"user_id": {
|
|
80
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
81
|
+
"description": "ID of the user to update"
|
|
82
|
+
},
|
|
83
|
+
"name": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "Current name of the user (used to find if user_id not provided)"
|
|
86
|
+
},
|
|
87
|
+
"new_name": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "New name for the user"
|
|
90
|
+
},
|
|
91
|
+
"email": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"description": "Email address"
|
|
94
|
+
},
|
|
95
|
+
"department": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"description": "Department name"
|
|
98
|
+
},
|
|
99
|
+
"user_title": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"description": "Job title"
|
|
102
|
+
},
|
|
103
|
+
"phone": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"description": "Phone number"
|
|
106
|
+
},
|
|
107
|
+
"disabled": {
|
|
108
|
+
"type": "boolean",
|
|
109
|
+
"description": "Enable or disable the user"
|
|
110
|
+
},
|
|
111
|
+
"user_group_id": {
|
|
112
|
+
"type": "integer",
|
|
113
|
+
"description": "ID of the user group to assign"
|
|
114
|
+
},
|
|
115
|
+
"access_groups": {
|
|
116
|
+
"type": "array",
|
|
117
|
+
"items": {"type": "integer"},
|
|
118
|
+
"description": "List of access group IDs"
|
|
119
|
+
},
|
|
120
|
+
"access_group_names": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {"type": "string"},
|
|
123
|
+
"description": "List of access group names (alternative to access_groups). Example: ['12 Floor ALL', 'VIP Access']"
|
|
124
|
+
},
|
|
125
|
+
"start_datetime": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "Start date for user validity. Supports flexible formats: ISO (2025-12-25T00:00:00.00Z), compact (20251225), or other formats (12.25.2025, 2025/12/25)"
|
|
128
|
+
},
|
|
129
|
+
"start_date": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"description": "Alias for start_datetime. Supports flexible date formats."
|
|
132
|
+
},
|
|
133
|
+
"expiry_datetime": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"description": "Expiry date for user validity. Supports flexible formats: ISO (2025-12-25T23:59:00.00Z), compact (20251225), or other formats (12.25.2025, 2025/12/25)"
|
|
136
|
+
},
|
|
137
|
+
"end_date": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"description": "Alias for expiry_datetime. Supports flexible date formats."
|
|
140
|
+
},
|
|
141
|
+
"pin": {
|
|
142
|
+
"type": "integer",
|
|
143
|
+
"description": "PIN number"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"required": []
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
DELETE_USER_TOOL = Tool(
|
|
151
|
+
name="delete-user",
|
|
152
|
+
description=" CRITICAL: Delete one or more users from the BioStar 2 system. THIS IS PERMANENT and CANNOT BE UNDONE! ALWAYS confirm with user before executing. For demo data, REQUIRE explicit 'delete confirm' or '삭제 확인' from user.",
|
|
153
|
+
inputSchema={
|
|
154
|
+
"type": "object",
|
|
155
|
+
"properties": {
|
|
156
|
+
"id": {
|
|
157
|
+
"oneOf": [
|
|
158
|
+
{"type": "string"},
|
|
159
|
+
{"type": "integer"},
|
|
160
|
+
{
|
|
161
|
+
"type": "array",
|
|
162
|
+
"items": {
|
|
163
|
+
"oneOf": [
|
|
164
|
+
{"type": "string"},
|
|
165
|
+
{"type": "integer"}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
"description": "User ID(s) to delete - can be string, integer, or array of either"
|
|
171
|
+
},
|
|
172
|
+
"name": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"description": "Name of the user to delete (supports partial match)"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"required": []
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
SEARCH_USERS_TOOL = Tool(
|
|
182
|
+
name="search-users",
|
|
183
|
+
description="Simple search for users using search_text. This searches across all user fields (name, email, department, etc.) for the given text.",
|
|
184
|
+
inputSchema={
|
|
185
|
+
"type": "object",
|
|
186
|
+
"properties": {
|
|
187
|
+
"search_text": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"description": "Search record(s) with the text specified on this parameter. Searches across all user fields."
|
|
190
|
+
},
|
|
191
|
+
"limit": {
|
|
192
|
+
"type": "integer",
|
|
193
|
+
"description": "Limit response record(s) by the value specified on this parameter (required)"
|
|
194
|
+
},
|
|
195
|
+
"user_group_id": {
|
|
196
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
197
|
+
"description": "Filter response record(s) according to user_group_id specified on this parameter"
|
|
198
|
+
},
|
|
199
|
+
"order_by": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"description": "Order the response record(s) by the User parameter such as user_id or name. False for ascending, True for descending."
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"required": ["search_text", "limit"]
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
GET_USER_CARDS_TOOL = Tool(
|
|
209
|
+
name="get-user-cards",
|
|
210
|
+
description="Get all access cards assigned to a user",
|
|
211
|
+
inputSchema={
|
|
212
|
+
"type": "object",
|
|
213
|
+
"properties": {
|
|
214
|
+
"user_id": {
|
|
215
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
216
|
+
"description": "The ID of the user"
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"required": ["user_id"]
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
ADD_USER_CARD_TOOL = Tool(
|
|
224
|
+
name="add-user-card",
|
|
225
|
+
description="Add an access card to a user",
|
|
226
|
+
inputSchema={
|
|
227
|
+
"type": "object",
|
|
228
|
+
"properties": {
|
|
229
|
+
"user_id": {
|
|
230
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
231
|
+
"description": "The ID of the user"
|
|
232
|
+
},
|
|
233
|
+
"card_number": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"description": "The card number to add"
|
|
236
|
+
},
|
|
237
|
+
"card_type": {
|
|
238
|
+
"type": "string",
|
|
239
|
+
"description": "Type of card (e.g., 'CSN', 'WIEGAND')"
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"required": ["user_id", "card_number"]
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
DELETE_USER_CARD_TOOL = Tool(
|
|
247
|
+
name="delete-user-card",
|
|
248
|
+
description="Remove an access card from a user",
|
|
249
|
+
inputSchema={
|
|
250
|
+
"type": "object",
|
|
251
|
+
"properties": {
|
|
252
|
+
"user_id": {
|
|
253
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
254
|
+
"description": "The ID of the user"
|
|
255
|
+
},
|
|
256
|
+
"card_id": {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"description": "The ID of the card to remove"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"required": ["user_id", "card_id"]
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
BULK_ADD_USERS_TOOL = Tool(
|
|
266
|
+
name="bulk-add-users",
|
|
267
|
+
description=(
|
|
268
|
+
"Create multiple users at once with optional user-group assignment (single or multiple groups, round-robin or explicit counts). "
|
|
269
|
+
"If user_group_name (or user_group_names/group_allocations.group_name) matches multiple groups, "
|
|
270
|
+
"the tool MUST return an error with needs_selection=true, a candidates list, and a selection_token. "
|
|
271
|
+
"The caller must ask the user to choose and then re-call the tool with user_group_id and selection_token. "
|
|
272
|
+
"Do not auto-pick a group."
|
|
273
|
+
),
|
|
274
|
+
inputSchema={
|
|
275
|
+
"type": "object",
|
|
276
|
+
"properties": {
|
|
277
|
+
"base_name": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"description": "Base prefix for user names (e.g., 'user' creates user001, user002, ...)"
|
|
280
|
+
},
|
|
281
|
+
"count": {
|
|
282
|
+
"type": "integer",
|
|
283
|
+
"description": "Number of users to create (max 30)"
|
|
284
|
+
},
|
|
285
|
+
# --- NEW: single-group assignment ---
|
|
286
|
+
"user_group_id": {
|
|
287
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
288
|
+
"description": "Assign ALL created users to this user group id."
|
|
289
|
+
},
|
|
290
|
+
"user_group_name": {
|
|
291
|
+
"type": "string",
|
|
292
|
+
"description": "Assign ALL created users to the group resolved by this name (substring match, 0/1/many flow)."
|
|
293
|
+
},
|
|
294
|
+
# --- NEW: multi-group distribution by names ---
|
|
295
|
+
"user_group_names": {
|
|
296
|
+
"type": "array",
|
|
297
|
+
"items": {"type": "string"},
|
|
298
|
+
"description": "List of group names to distribute across. If 'distribution' is 'round_robin', users are assigned cyclically."
|
|
299
|
+
},
|
|
300
|
+
"group_counts": {
|
|
301
|
+
"type": "array",
|
|
302
|
+
"items": {"type": "integer"},
|
|
303
|
+
"description": "Used with 'user_group_names' when distribution='by_counts'. Must match names length and sum to 'count'."
|
|
304
|
+
},
|
|
305
|
+
"distribution": {
|
|
306
|
+
"type": "string",
|
|
307
|
+
"enum": ["round_robin", "by_counts"],
|
|
308
|
+
"description": "How to distribute when multiple groups are provided. Default: 'round_robin'.",
|
|
309
|
+
"default": "round_robin"
|
|
310
|
+
},
|
|
311
|
+
# --- NEW: explicit allocations list ---
|
|
312
|
+
"group_allocations": {
|
|
313
|
+
"type": "array",
|
|
314
|
+
"description": "Explicit allocations, e.g., [{'group_name':'product_line','count':10}, {'group_id':1260,'count':5}]. Counts must sum to 'count'.",
|
|
315
|
+
"items": {
|
|
316
|
+
"type": "object",
|
|
317
|
+
"properties": {
|
|
318
|
+
"group_id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
|
|
319
|
+
"group_name": {"type": "string"},
|
|
320
|
+
"count": {"type": "integer"}
|
|
321
|
+
},
|
|
322
|
+
"anyOf": [
|
|
323
|
+
{"required": ["group_id", "count"]},
|
|
324
|
+
{"required": ["group_name", "count"]}
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"required": ["base_name", "count"]
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
EXPORT_USERS_CSV_TOOL = Tool(
|
|
334
|
+
name="export-users-csv",
|
|
335
|
+
description=(
|
|
336
|
+
"Export user data to CSV and optionally copy the file to the Windows Downloads folder. "
|
|
337
|
+
"Supports exporting ALL users matching advanced search criteria (no limit). "
|
|
338
|
+
"Use adv_criteria for filtering by group, department, email, etc. without loading all data into memory."
|
|
339
|
+
),
|
|
340
|
+
inputSchema={
|
|
341
|
+
"type": "object",
|
|
342
|
+
"properties": {
|
|
343
|
+
"ids": {
|
|
344
|
+
"type": "array",
|
|
345
|
+
"items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
|
|
346
|
+
"description": "List of user IDs to export, or ['*'] for all users. If provided, other filters are ignored."
|
|
347
|
+
},
|
|
348
|
+
"search_text": {
|
|
349
|
+
"type": "string",
|
|
350
|
+
"description": "Simple search text (searches all fields). For large result sets, use adv_criteria instead."
|
|
351
|
+
},
|
|
352
|
+
"limit": {
|
|
353
|
+
"type": "integer",
|
|
354
|
+
"description": "DEPRECATED: Max users when using search_text (default 50). Use adv_criteria for unlimited results.",
|
|
355
|
+
"default": 50
|
|
356
|
+
},
|
|
357
|
+
"adv_criteria": {
|
|
358
|
+
"type": "object",
|
|
359
|
+
"description": (
|
|
360
|
+
"Advanced search criteria to filter users server-side (no limit). "
|
|
361
|
+
"Example: {\"user_group_id\": \"1260\", \"user_name\": \"John\", \"user_email\": \"gmail\"}. "
|
|
362
|
+
"Server will export ALL matching users directly to CSV without limit."
|
|
363
|
+
),
|
|
364
|
+
"properties": {
|
|
365
|
+
"user_group_id": {"type": "string"},
|
|
366
|
+
"user_group_ids": {"type": "array", "items": {"type": "integer"}},
|
|
367
|
+
"user_name": {"type": "string"},
|
|
368
|
+
"user_email": {"type": "string"},
|
|
369
|
+
"user_department": {"type": "string"},
|
|
370
|
+
"user_phone": {"type": "string"},
|
|
371
|
+
"user_title": {"type": "string"},
|
|
372
|
+
"user_status": {"type": "boolean"},
|
|
373
|
+
"user_operator_level_id": {"type": "string"}
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"copy_to_downloads": {
|
|
377
|
+
"type": "boolean",
|
|
378
|
+
"description": "Copy the exported CSV into a Windows Downloads folder",
|
|
379
|
+
"default": True
|
|
380
|
+
},
|
|
381
|
+
"dest_dir": {
|
|
382
|
+
"type": "string",
|
|
383
|
+
"description": "Absolute destination directory for the copy (overrides Downloads)"
|
|
384
|
+
},
|
|
385
|
+
"target_username": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"description": "Windows username for Downloads path (C:\\Users\\<name>\\Downloads)"
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
"required": []
|
|
391
|
+
}
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
ADVANCED_SEARCH_USERS_TOOL = Tool(
|
|
396
|
+
name="advanced-search-users",
|
|
397
|
+
description="Perform advanced search for users with multiple criteria including name, email, department, title, phone, access groups, custom fields, etc. user_email: ASCII lowercase provider token (no '@', no TLD). If a full email is given, extract the provider. ",
|
|
398
|
+
inputSchema={
|
|
399
|
+
"type": "object",
|
|
400
|
+
"properties": {
|
|
401
|
+
"limit": {
|
|
402
|
+
"type": "integer",
|
|
403
|
+
"description": "The maximum number of users to return. Default is 50."
|
|
404
|
+
},
|
|
405
|
+
"offset": {
|
|
406
|
+
"type": "string",
|
|
407
|
+
"description": "The number of users to skip before starting to return results. Default is 0."
|
|
408
|
+
},
|
|
409
|
+
"user_id": {
|
|
410
|
+
"type": "string",
|
|
411
|
+
"description": "The User ID to search, supports like search"
|
|
412
|
+
},
|
|
413
|
+
"user_group_id": {
|
|
414
|
+
"type": "string",
|
|
415
|
+
"description": "Group ID for search user. Also gets the child user group"
|
|
416
|
+
},
|
|
417
|
+
"user_group_ids": {
|
|
418
|
+
"type": "array",
|
|
419
|
+
"items": {"type": "integer"},
|
|
420
|
+
"description": "Array of Group IDs for advanced search parameter"
|
|
421
|
+
},
|
|
422
|
+
"user_name": {
|
|
423
|
+
"type": "string",
|
|
424
|
+
"description": "User name for Advance Search parameter, supports like search both encrypted and unencrypted"
|
|
425
|
+
},
|
|
426
|
+
"user_email": {
|
|
427
|
+
"type": "string",
|
|
428
|
+
"description": "User email, supports like search both encrypted and unencrypted"
|
|
429
|
+
},
|
|
430
|
+
"user_phone": {
|
|
431
|
+
"type": "string",
|
|
432
|
+
"description": "User Phone for Advance Search parameter, supports like search both encrypted and unencrypted"
|
|
433
|
+
},
|
|
434
|
+
"user_department": {
|
|
435
|
+
"type": "string",
|
|
436
|
+
"description": "User Department for Advance Search parameter, supports like search on unencrypted and exact search on encrypted"
|
|
437
|
+
},
|
|
438
|
+
"user_access_group_ids": {
|
|
439
|
+
"type": "string",
|
|
440
|
+
"description": "User access group id for advance search parameter, supports multiple value with format String with Delimiter , i.e 1,2,3"
|
|
441
|
+
},
|
|
442
|
+
"user_title": {
|
|
443
|
+
"type": "string",
|
|
444
|
+
"description": "User title for advance search parameter, supports like search on unencrypted and exact search on encrypted"
|
|
445
|
+
},
|
|
446
|
+
"user_card": {
|
|
447
|
+
"type": "string",
|
|
448
|
+
"description": "User card ID"
|
|
449
|
+
},
|
|
450
|
+
"user_status": {
|
|
451
|
+
"type": "boolean",
|
|
452
|
+
"description": "User status for advance search parameter Operator level (required by API). Defaults to '0' if omitted."
|
|
453
|
+
},
|
|
454
|
+
"user_operator_level_id": {
|
|
455
|
+
"type": "string",
|
|
456
|
+
"description": "User operator level id for Advance Search parameter"
|
|
457
|
+
},
|
|
458
|
+
"user_custom_field_1": {
|
|
459
|
+
"type": "string",
|
|
460
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
461
|
+
},
|
|
462
|
+
"user_custom_field_2": {
|
|
463
|
+
"type": "string",
|
|
464
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
465
|
+
},
|
|
466
|
+
"user_custom_field_3": {
|
|
467
|
+
"type": "string",
|
|
468
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
469
|
+
},
|
|
470
|
+
"user_custom_field_4": {
|
|
471
|
+
"type": "string",
|
|
472
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
473
|
+
},
|
|
474
|
+
"user_custom_field_5": {
|
|
475
|
+
"type": "string",
|
|
476
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
477
|
+
},
|
|
478
|
+
"user_custom_field_6": {
|
|
479
|
+
"type": "string",
|
|
480
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
481
|
+
},
|
|
482
|
+
"user_custom_field_7": {
|
|
483
|
+
"type": "string",
|
|
484
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
485
|
+
},
|
|
486
|
+
"user_custom_field_8": {
|
|
487
|
+
"type": "string",
|
|
488
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
489
|
+
},
|
|
490
|
+
"user_custom_field_9": {
|
|
491
|
+
"type": "string",
|
|
492
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
493
|
+
},
|
|
494
|
+
"user_custom_field_10": {
|
|
495
|
+
"type": "string",
|
|
496
|
+
"description": "Custom fields for advance search parameter support like search on unencrypted and exact search on encrypted"
|
|
497
|
+
},
|
|
498
|
+
"order_by": {
|
|
499
|
+
"type": "string",
|
|
500
|
+
"description": "Order, will accept with format properties:false, for example if we want to order by name, it will be user_name:false. false = ASCENDING and true = DESCENDING"
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
"required": []
|
|
504
|
+
}
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
UNASSIGN_USER_CARDS_TOOL = Tool(
|
|
508
|
+
name="unassign-user-cards",
|
|
509
|
+
description=(
|
|
510
|
+
"Detach one, multiple, or all cards from a user by updating the user's cards via "
|
|
511
|
+
"PUT /api/users/{user_id}. "
|
|
512
|
+
"Supply BioStar card **row ids** to remove (e.g., ['17','18']). "
|
|
513
|
+
"If remove_all=true, sends {'User': {'cards': []}}."
|
|
514
|
+
),
|
|
515
|
+
inputSchema={
|
|
516
|
+
"type": "object",
|
|
517
|
+
"properties": {
|
|
518
|
+
"user_id": {
|
|
519
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
520
|
+
"description": "Target user id. If omitted, provide 'name' to resolve."
|
|
521
|
+
},
|
|
522
|
+
"name": {
|
|
523
|
+
"type": "string",
|
|
524
|
+
"description": "User name (used to resolve if user_id is not provided; fails on multiple matches)."
|
|
525
|
+
},
|
|
526
|
+
"remove_all": {
|
|
527
|
+
"type": "boolean",
|
|
528
|
+
"description": "If true, detach all cards from the user."
|
|
529
|
+
},
|
|
530
|
+
"remove_card_row_ids": {
|
|
531
|
+
"type": "array",
|
|
532
|
+
"items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
|
|
533
|
+
"description": "BioStar **card row id(s)** to detach (e.g., ['17','18'])."
|
|
534
|
+
},
|
|
535
|
+
"ignore_missing": {
|
|
536
|
+
"type": "boolean",
|
|
537
|
+
"default": False,
|
|
538
|
+
"description": "If false, fail when any requested row id is not assigned to the user."
|
|
539
|
+
},
|
|
540
|
+
"dry_run": {
|
|
541
|
+
"type": "boolean",
|
|
542
|
+
"default": False,
|
|
543
|
+
"description": "If true, return the planned PUT body without calling the API."
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
"anyOf": [
|
|
547
|
+
{"required": ["user_id"]},
|
|
548
|
+
{"required": ["name"]}
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
CREATE_USER_GROUP_TOOL = Tool(
|
|
554
|
+
name="create-user-group",
|
|
555
|
+
description=(
|
|
556
|
+
"Create a new user group in BioStar 2. "
|
|
557
|
+
"Blocks if a group with the same name already exists (case-insensitive). "
|
|
558
|
+
"If 'depth' is omitted, it will be computed as parent.depth + 1 (max total levels: 8; root=0)."
|
|
559
|
+
),
|
|
560
|
+
inputSchema={
|
|
561
|
+
"type": "object",
|
|
562
|
+
"properties": {
|
|
563
|
+
"name": {
|
|
564
|
+
"type": "string",
|
|
565
|
+
"description": "Name of the new user group (max 48 chars)"
|
|
566
|
+
},
|
|
567
|
+
"parent_id": {
|
|
568
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
569
|
+
"description": "Parent group ID (e.g., 1 for 'All Users')"
|
|
570
|
+
},
|
|
571
|
+
"depth": {
|
|
572
|
+
"type": "integer",
|
|
573
|
+
"description": "Depth of the new group. If omitted, computed automatically."
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
"required": ["name", "parent_id"]
|
|
577
|
+
}
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
GET_USER_GROUPS_TOOL = Tool(
|
|
582
|
+
name="get-user-groups",
|
|
583
|
+
description="Retrieve a list of all user groups from the BioStar 2 system (GET /api/user_groups).",
|
|
584
|
+
inputSchema={
|
|
585
|
+
"type": "object",
|
|
586
|
+
"properties": {},
|
|
587
|
+
"required": []
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
ADD_USER_TO_GROUP_TOOL = Tool(
|
|
593
|
+
name="add-user-to-group",
|
|
594
|
+
description="Assign a user to a specific user group using PUT /api/users/{user_id}. Validates existence and handles 0/1/many selections for both user and group.",
|
|
595
|
+
inputSchema={
|
|
596
|
+
"type": "object",
|
|
597
|
+
"properties": {
|
|
598
|
+
"user_id": {
|
|
599
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
600
|
+
"description": "Target user id (if omitted, 'name' is used to resolve)."
|
|
601
|
+
},
|
|
602
|
+
"name": {
|
|
603
|
+
"type": "string",
|
|
604
|
+
"description": "Target user name (0/1/many flow)."
|
|
605
|
+
},
|
|
606
|
+
"user_group_id": {
|
|
607
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
608
|
+
"description": "Destination user group id."
|
|
609
|
+
},
|
|
610
|
+
"group_name": {
|
|
611
|
+
"type": "string",
|
|
612
|
+
"description": "Destination group name (substring match; 0/1/many flow)."
|
|
613
|
+
},
|
|
614
|
+
"group_search_text": {
|
|
615
|
+
"type": "string",
|
|
616
|
+
"description": "Alias of group_name."
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
"anyOf": [
|
|
620
|
+
{"required": ["user_id", "user_group_id"]},
|
|
621
|
+
{"required": ["user_id", "group_name"]},
|
|
622
|
+
{"required": ["name", "user_group_id"]},
|
|
623
|
+
{"required": ["name", "group_name"]}
|
|
624
|
+
]
|
|
625
|
+
}
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
REMOVE_USER_FROM_GROUP_TOOL = Tool(
|
|
629
|
+
name="remove-user-from-group",
|
|
630
|
+
description="Exclude a user from a specific group by moving to a destination group via PUT /api/users/{user_id}. Validates target and supports 0/1/many selection.",
|
|
631
|
+
inputSchema={
|
|
632
|
+
"type": "object",
|
|
633
|
+
"properties": {
|
|
634
|
+
"user_id": {
|
|
635
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
636
|
+
"description": "Target user id (if omitted, 'name' is used to resolve)."
|
|
637
|
+
},
|
|
638
|
+
"name": {
|
|
639
|
+
"type": "string",
|
|
640
|
+
"description": "Target user name (0/1/many flow)."
|
|
641
|
+
},
|
|
642
|
+
"from_user_group_id": {
|
|
643
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
644
|
+
"description": "(Optional) Enforce that the user is currently in this group."
|
|
645
|
+
},
|
|
646
|
+
"from_group_name": {
|
|
647
|
+
"type": "string",
|
|
648
|
+
"description": "(Optional) From-group name (substring match; 0/1/many flow)."
|
|
649
|
+
},
|
|
650
|
+
"from_group_search_text": {
|
|
651
|
+
"type": "string",
|
|
652
|
+
"description": "(Optional) Alias of from_group_name."
|
|
653
|
+
},
|
|
654
|
+
"destination_group_id": {
|
|
655
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
656
|
+
"description": "(Optional) Destination group id. If omitted, will try parent or fallback to id=1."
|
|
657
|
+
},
|
|
658
|
+
"destination_group_name": {
|
|
659
|
+
"type": "string",
|
|
660
|
+
"description": "(Optional) Destination group name (substring match; 0/1/many flow)."
|
|
661
|
+
},
|
|
662
|
+
"destination_group_search_text": {
|
|
663
|
+
"type": "string",
|
|
664
|
+
"description": "(Optional) Alias of destination_group_name."
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
"anyOf": [
|
|
668
|
+
{"required": ["user_id"]},
|
|
669
|
+
{"required": ["name"]}
|
|
670
|
+
]
|
|
671
|
+
}
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
BULK_EDIT_USERS_TOOL = Tool(
|
|
676
|
+
name="bulk-edit-users",
|
|
677
|
+
description=(
|
|
678
|
+
"Bulk update multiple users at once using the fixed endpoint "
|
|
679
|
+
"PUT https://192.168.120.71/api/users?adv=mode1. "
|
|
680
|
+
"Provide 'adv_criteria' to select targets and any combination of: "
|
|
681
|
+
"new_user_group_id/new_user_group (user group change), "
|
|
682
|
+
"start_datetime/expiry_datetime (period), "
|
|
683
|
+
"access_group_ids/access_groups or clear_access_groups (access levels/groups). "
|
|
684
|
+
"Use 'dry_run=true' to preview the request payload without calling the API."
|
|
685
|
+
),
|
|
686
|
+
inputSchema={
|
|
687
|
+
"type": "object",
|
|
688
|
+
"properties": {
|
|
689
|
+
"adv_criteria": {
|
|
690
|
+
"type": "object",
|
|
691
|
+
"description": "Advanced criteria object to select target users (e.g., {'user_group_id': 4037})."
|
|
692
|
+
},
|
|
693
|
+
"new_user_group_id": {
|
|
694
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
695
|
+
"description": "Destination user group id for all matched users."
|
|
696
|
+
},
|
|
697
|
+
"new_user_group": {
|
|
698
|
+
"type": "object",
|
|
699
|
+
"description": "Full user_group_id object to pass-through (e.g., {'id':'4036','name':'ACE'})."
|
|
700
|
+
},
|
|
701
|
+
"start_datetime": {
|
|
702
|
+
"type": "string",
|
|
703
|
+
"description": "ISO8601 start datetime, e.g., '2001-01-01T00:00:00'."
|
|
704
|
+
},
|
|
705
|
+
"expiry_datetime": {
|
|
706
|
+
"type": "string",
|
|
707
|
+
"description": "ISO8601 expiry datetime, e.g., '2034-12-31T23:59:00'."
|
|
708
|
+
},
|
|
709
|
+
"access_group_ids": {
|
|
710
|
+
"type": "array",
|
|
711
|
+
"items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
|
|
712
|
+
"description": "List of Access Group IDs to assign (minimal form [{'id': <id>}])."
|
|
713
|
+
},
|
|
714
|
+
"access_groups": {
|
|
715
|
+
"type": "array",
|
|
716
|
+
"items": {"type": "object"},
|
|
717
|
+
"description": "Full AccessGroup objects to pass-through (supports 'accessLevels', 'users', etc.)."
|
|
718
|
+
},
|
|
719
|
+
"clear_access_groups": {
|
|
720
|
+
"type": "boolean",
|
|
721
|
+
"description": "If true, sets 'access_groups': [] (overrides access_group_ids/access_groups).",
|
|
722
|
+
"default": False
|
|
723
|
+
},
|
|
724
|
+
"dry_run": {
|
|
725
|
+
"type": "boolean",
|
|
726
|
+
"description": "If true, returns the planned payload without calling the API.",
|
|
727
|
+
"default": False
|
|
728
|
+
},
|
|
729
|
+
"timeout": {
|
|
730
|
+
"type": "integer",
|
|
731
|
+
"description": "HTTP timeout seconds (1-120). Default: 30.",
|
|
732
|
+
"default": 30
|
|
733
|
+
}
|
|
734
|
+
},
|
|
735
|
+
"required": ["adv_criteria"],
|
|
736
|
+
"allOf": [
|
|
737
|
+
{
|
|
738
|
+
"anyOf": [
|
|
739
|
+
{"required": ["new_user_group_id"]},
|
|
740
|
+
{"required": ["new_user_group"]},
|
|
741
|
+
{"required": ["start_datetime"]},
|
|
742
|
+
{"required": ["expiry_datetime"]},
|
|
743
|
+
{"required": ["access_group_ids"]},
|
|
744
|
+
{"required": ["access_groups"]},
|
|
745
|
+
{"required": ["clear_access_groups"]}
|
|
746
|
+
]
|
|
747
|
+
}
|
|
748
|
+
]
|
|
749
|
+
}
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
IMPORT_USERS_CSV_TOOL = Tool(
|
|
754
|
+
name="import-users-csv",
|
|
755
|
+
description=(
|
|
756
|
+
"Import users from a CSV into BioStar.\n- Always use this tool whenever the user asks to add/import users via a CSV (e.g., 'add users from CSV', 'import users').\n- The server download directory prefix is applied automatically to file paths: C:\\Program Files\\BioStar X\\nginx\\html\\download (override via session.config.download_dir).\n- Inputs: either 'file_path' to upload or ('uri' + 'fileName') if the file already exists on the server."
|
|
757
|
+
),
|
|
758
|
+
inputSchema={
|
|
759
|
+
"type": "object",
|
|
760
|
+
"properties": {
|
|
761
|
+
"file_path": {
|
|
762
|
+
"type": "string",
|
|
763
|
+
"description": "Local CSV path to upload via /api/attachments (optional if uri+fileName provided)"
|
|
764
|
+
},
|
|
765
|
+
"uri": {
|
|
766
|
+
"type": "string",
|
|
767
|
+
"description": "Attachment URI already uploaded to BioStar 2 (used when file_path is not provided)"
|
|
768
|
+
},
|
|
769
|
+
"fileName": {
|
|
770
|
+
"type": "string",
|
|
771
|
+
"description": "Attachment fileName already uploaded (used when file_path is not provided)"
|
|
772
|
+
},
|
|
773
|
+
"original_file_name": {
|
|
774
|
+
"type": "string",
|
|
775
|
+
"description": "Original filename to show in BioStar 2 (defaults to fileName)"
|
|
776
|
+
},
|
|
777
|
+
"start_line": {
|
|
778
|
+
"type": "integer",
|
|
779
|
+
"description": "CSV import start line (1-based). Usually header=1, data starts at 2. Default=2",
|
|
780
|
+
"default": 2
|
|
781
|
+
},
|
|
782
|
+
"timeout": {
|
|
783
|
+
"type": "integer",
|
|
784
|
+
"description": "HTTP timeout seconds (default 60)",
|
|
785
|
+
"default": 60
|
|
786
|
+
},
|
|
787
|
+
"use_server_columns": {
|
|
788
|
+
"type": "boolean",
|
|
789
|
+
"description": "Fetch /api/users/csv_option to determine columns; fallback to known default.",
|
|
790
|
+
"default": True
|
|
791
|
+
},
|
|
792
|
+
"columns": {
|
|
793
|
+
"type": "array",
|
|
794
|
+
"items": {"type": "string"},
|
|
795
|
+
"description": "Override columns list (if omitted, will use server columns or fallback)."
|
|
796
|
+
},
|
|
797
|
+
"headers": {
|
|
798
|
+
"type": "array",
|
|
799
|
+
"items": {"type": "string"},
|
|
800
|
+
"description": "Header mapping aligned with 'columns'. If omitted, applies safe default mapping."
|
|
801
|
+
},
|
|
802
|
+
"data_rows": {
|
|
803
|
+
"type": "array",
|
|
804
|
+
"items": {"type": "string"},
|
|
805
|
+
"description": "Optional inline CSV line strings to send via 'Data' (header line should NOT be included)."
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
"required": []
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
IMPORT_USERS_CSV_SMART_TOOL = Tool(
|
|
813
|
+
name="import-users-csv-smart",
|
|
814
|
+
description=(
|
|
815
|
+
"Smart CSV import for BioStar 2 with automatic post-processing.\n"
|
|
816
|
+
"- Use when the CSV may be missing required headers or has minimal columns.\n"
|
|
817
|
+
"- Automatically adds/fills required headers (user_group, start_datetime, expiry_datetime) with defaults.\n"
|
|
818
|
+
"- AUTO-UPDATE FEATURE: After creating users, automatically updates User Groups, Access Groups, and Dates if present in CSV.\n"
|
|
819
|
+
"- Supports flexible date formats (20251225, 12.25.2025, 2025-12-25) and auto-converts to ISO 8601.\n"
|
|
820
|
+
"- CSV columns recognized: 'User Group', 'Access Group', 'Start Date', 'End Date' (case-insensitive).\n"
|
|
821
|
+
"- Fetches the exact server column list via /api/users/csv_option and builds a full-length mapping to prevent '211 not defined'.\n"
|
|
822
|
+
"- Delegates the actual import to the strict importer (import-users-csv) by passing enhanced bytes and the full mapping.\n"
|
|
823
|
+
"CRITICAL: Always use the tool's default values unless the user explicitly specifies different values. Do not override default_group_name based on context or assumptions.\n"
|
|
824
|
+
"Defaults: user_group='All Users', start_datetime='2001-01-01 00:00', expiry_datetime='2030-12-31 23:59', auto_update=true.\n"
|
|
825
|
+
"Tip: set dry_run=true to preview the planned mapping without sending the import request."
|
|
826
|
+
),
|
|
827
|
+
inputSchema={
|
|
828
|
+
"type": "object",
|
|
829
|
+
"properties": {
|
|
830
|
+
# ----- Input sources (same loader as strict tool) -----
|
|
831
|
+
"file_path": {
|
|
832
|
+
"type": "string",
|
|
833
|
+
"description": "Local path or http(s) URL; smart search also checks common locations (/mnt/data, CWD, Downloads, session.config.upload_inbox_dir)."
|
|
834
|
+
},
|
|
835
|
+
"uri": {
|
|
836
|
+
"type": "string",
|
|
837
|
+
"description": "If the CSV already exists in the server download dir, pass the basename here."
|
|
838
|
+
},
|
|
839
|
+
"fileName": {
|
|
840
|
+
"type": "string",
|
|
841
|
+
"description": "Usually the same as 'uri' when referencing an existing server file."
|
|
842
|
+
},
|
|
843
|
+
"original_file_name": {
|
|
844
|
+
"type": "string",
|
|
845
|
+
"description": "Original filename for display; defaults to the basename of the uploaded file."
|
|
846
|
+
},
|
|
847
|
+
"file_base64": {
|
|
848
|
+
"type": "string",
|
|
849
|
+
"description": "Provide raw CSV content as Base64 (highest priority input)."
|
|
850
|
+
},
|
|
851
|
+
"file_text": {
|
|
852
|
+
"type": "string",
|
|
853
|
+
"description": "Provide raw CSV text (will be encoded with 'charset', default utf-8-sig)."
|
|
854
|
+
},
|
|
855
|
+
"file_bytes": {
|
|
856
|
+
"type": "array",
|
|
857
|
+
"items": {"type": "integer"},
|
|
858
|
+
"description": "Provide raw CSV bytes as an array of integers (0-255)."
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
# ----- Behavior & defaults -----
|
|
862
|
+
"delimiter": {
|
|
863
|
+
"type": "string",
|
|
864
|
+
"description": "Optional delimiter override. Auto-sniff by default.",
|
|
865
|
+
"enum": [",", ";", "|", "\\t"]
|
|
866
|
+
},
|
|
867
|
+
"charset": {
|
|
868
|
+
"type": "string",
|
|
869
|
+
"description": "Decode charset for file_text/bytes (default: utf-8-sig).",
|
|
870
|
+
"default": "utf-8-sig"
|
|
871
|
+
},
|
|
872
|
+
"default_group_name": {
|
|
873
|
+
"type": "string",
|
|
874
|
+
"description": "Default user_group value when missing/empty.",
|
|
875
|
+
"default": "All Users"
|
|
876
|
+
},
|
|
877
|
+
"default_start_datetime": {
|
|
878
|
+
"type": "string",
|
|
879
|
+
"description": "Default start_datetime when missing/empty.",
|
|
880
|
+
"default": "2001-01-01 00:00"
|
|
881
|
+
},
|
|
882
|
+
"default_expiry_datetime": {
|
|
883
|
+
"type": "string",
|
|
884
|
+
"description": "Default expiry_datetime when missing/empty.",
|
|
885
|
+
"default": "2030-12-31 23:59"
|
|
886
|
+
},
|
|
887
|
+
"start_line": {
|
|
888
|
+
"type": "integer",
|
|
889
|
+
"description": "CSV data start line (1-based). Enhanced CSV includes a header at line 1, so data starts at 2.",
|
|
890
|
+
"default": 2
|
|
891
|
+
},
|
|
892
|
+
"timeout": {
|
|
893
|
+
"type": "integer",
|
|
894
|
+
"description": "HTTP timeout seconds.",
|
|
895
|
+
"default": 60
|
|
896
|
+
},
|
|
897
|
+
"dry_run": {
|
|
898
|
+
"type": "boolean",
|
|
899
|
+
"description": "If true, return the planned mapping/details without calling the import API.",
|
|
900
|
+
"default": False
|
|
901
|
+
},
|
|
902
|
+
"auto_update": {
|
|
903
|
+
"type": "boolean",
|
|
904
|
+
"description": "If true, automatically update User Groups, Access Groups, and Dates from CSV after import. Enabled by default.",
|
|
905
|
+
"default": True
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
"required": []
|
|
909
|
+
}
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
# --- Add this near other Tool definitions in users.py ---
|
|
913
|
+
|
|
914
|
+
EXPORT_NON_ACCESSED_USERS_CSV_TOOL = Tool(
|
|
915
|
+
name="export-non-accessed-users-csv",
|
|
916
|
+
description=(
|
|
917
|
+
"Export users who have NOT accessed a specific door within a given time period to CSV. "
|
|
918
|
+
"This tool first identifies non-accessed users by analyzing event logs, then exports only those users to CSV. "
|
|
919
|
+
"Perfect for finding inactive users or users who didn't use a specific entry point."
|
|
920
|
+
),
|
|
921
|
+
inputSchema={
|
|
922
|
+
"type": "object",
|
|
923
|
+
"properties": {
|
|
924
|
+
"door_id": {
|
|
925
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
|
926
|
+
"description": "Door ID to check access for"
|
|
927
|
+
},
|
|
928
|
+
"door_name": {
|
|
929
|
+
"type": "string",
|
|
930
|
+
"description": "Door name (alternative to door_id, will search for matching door)"
|
|
931
|
+
},
|
|
932
|
+
"days": {
|
|
933
|
+
"type": "integer",
|
|
934
|
+
"description": "Number of days to look back (default: 7)",
|
|
935
|
+
"default": 7
|
|
936
|
+
},
|
|
937
|
+
"hours": {
|
|
938
|
+
"type": "integer",
|
|
939
|
+
"description": "Number of hours to look back (alternative to days)"
|
|
940
|
+
},
|
|
941
|
+
"copy_to_downloads": {
|
|
942
|
+
"type": "boolean",
|
|
943
|
+
"description": "Copy the exported CSV into Windows Downloads folder",
|
|
944
|
+
"default": True
|
|
945
|
+
},
|
|
946
|
+
"dest_dir": {
|
|
947
|
+
"type": "string",
|
|
948
|
+
"description": "Absolute destination directory for the copy (overrides Downloads)"
|
|
949
|
+
},
|
|
950
|
+
"target_username": {
|
|
951
|
+
"type": "string",
|
|
952
|
+
"description": "Windows username for Downloads path"
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
"anyOf": [
|
|
956
|
+
{"required": ["door_id"]},
|
|
957
|
+
{"required": ["door_name"]}
|
|
958
|
+
]
|
|
959
|
+
}
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
BULK_UPDATE_USERS_FROM_FILE_TOOL = Tool(
|
|
963
|
+
name="bulk-update-users-from-file",
|
|
964
|
+
description=(
|
|
965
|
+
"Read a CSV/Excel-like file and update users in bulk:\n"
|
|
966
|
+
"- Columns recognized (case/spacing tolerant): 'name', 'group' (user group), 'access group' (Access Group), 'start date', 'end date'.\n"
|
|
967
|
+
"- Date columns support flexible formats: 20251225, 12.25.2025, 2025-12-25, etc. Automatically converted to ISO 8601 format.\n"
|
|
968
|
+
"- Flow: list-all-users -> resolve each Name (0/1/many) -> PUT /api/users/{id} to change user_group and dates -> "
|
|
969
|
+
"POST /api/v2/access_groups to map group names -> for each Access Group, PUT /api/access_groups/{id} with new_users.\n"
|
|
970
|
+
"- If any name is ambiguous (0 or >1), the tool MUST return needs_selection=true with candidates and a selection_token.\n"
|
|
971
|
+
"- The caller should re-call with 'name_resolutions' to confirm the exact user_id for those names.\n"
|
|
972
|
+
"- Supports dry_run to preview without making updates."
|
|
973
|
+
),
|
|
974
|
+
inputSchema={
|
|
975
|
+
"type": "object",
|
|
976
|
+
"properties": {
|
|
977
|
+
# --- file inputs (choose one way) ---
|
|
978
|
+
"file_path": {
|
|
979
|
+
"type": "string",
|
|
980
|
+
"description": "Absolute/local path to the uploaded CSV file (e.g., C:\\path\\to\\file.csv or /mnt/data/file.csv)."
|
|
981
|
+
},
|
|
982
|
+
"uri": {
|
|
983
|
+
"type": "string",
|
|
984
|
+
"description": "Attachment URI on the server, if already uploaded via /api/attachments."
|
|
985
|
+
},
|
|
986
|
+
"fileName": {
|
|
987
|
+
"type": "string",
|
|
988
|
+
"description": "Original file name when using 'uri'."
|
|
989
|
+
},
|
|
990
|
+
"file_bytes": {
|
|
991
|
+
"type": "string",
|
|
992
|
+
"description": "Base64-encoded file content; use with 'original_file_name'."
|
|
993
|
+
},
|
|
994
|
+
"original_file_name": {
|
|
995
|
+
"type": "string",
|
|
996
|
+
"description": "Original file name when using 'file_bytes'."
|
|
997
|
+
},
|
|
998
|
+
|
|
999
|
+
# --- parsing options ---
|
|
1000
|
+
"charset": {
|
|
1001
|
+
"type": "string",
|
|
1002
|
+
"description": "Text encoding for CSV decode. Default: 'utf-8-sig'."
|
|
1003
|
+
},
|
|
1004
|
+
"delimiter": {
|
|
1005
|
+
"type": "string",
|
|
1006
|
+
"description": "Override CSV delimiter. Auto-detected if omitted."
|
|
1007
|
+
},
|
|
1008
|
+
|
|
1009
|
+
# --- ambiguity resolution ---
|
|
1010
|
+
"selection_token": {
|
|
1011
|
+
"type": "string",
|
|
1012
|
+
"description": "Token provided from a previous ambiguous run; optional verification."
|
|
1013
|
+
},
|
|
1014
|
+
"name_resolutions": {
|
|
1015
|
+
"type": "object",
|
|
1016
|
+
"description": "Map of display name -> chosen user_id for conflicted names, e.g., {'Alice Johnson':'258258750'}.",
|
|
1017
|
+
"additionalProperties": {
|
|
1018
|
+
"oneOf": [{"type": "string"}, {"type": "integer"}]
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
|
|
1022
|
+
# --- execution controls ---
|
|
1023
|
+
"dry_run": {
|
|
1024
|
+
"type": "boolean",
|
|
1025
|
+
"description": "If true, build the plan but do not call the update APIs.",
|
|
1026
|
+
"default": False
|
|
1027
|
+
},
|
|
1028
|
+
"max_bulk_size": {
|
|
1029
|
+
"type": "integer",
|
|
1030
|
+
"description": "Max users per /api/users/bulk call (<=100). Default: 100.",
|
|
1031
|
+
"default": 100
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
"anyOf": [
|
|
1035
|
+
{"required": ["file_path"]},
|
|
1036
|
+
{"required": ["uri", "fileName"]},
|
|
1037
|
+
{"required": ["file_bytes", "original_file_name"]}
|
|
1038
|
+
]
|
|
1039
|
+
}
|
|
1040
|
+
)
|
|
1041
|
+
|
|
1042
|
+
# Helper function tools for user data processing
|
|
1043
|
+
FORMAT_PHONE_NUMBER_TOOL = Tool(
|
|
1044
|
+
name="format-phone-number",
|
|
1045
|
+
description="Clean and format phone number by removing all non-digit characters. Example: '1) 415-732-9042' becomes '14157329042'",
|
|
1046
|
+
inputSchema={
|
|
1047
|
+
"type": "object",
|
|
1048
|
+
"properties": {
|
|
1049
|
+
"phone": {
|
|
1050
|
+
"type": "string",
|
|
1051
|
+
"description": "Raw phone number string to clean"
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
"required": ["phone"]
|
|
1055
|
+
}
|
|
1056
|
+
)
|
|
1057
|
+
|
|
1058
|
+
FORMAT_PIN_FROM_PHONE_TOOL = Tool(
|
|
1059
|
+
name="format-pin-from-phone",
|
|
1060
|
+
description="Extract last 8 digits from phone number to generate PIN. Example: '14157329042' becomes '73290426'",
|
|
1061
|
+
inputSchema={
|
|
1062
|
+
"type": "object",
|
|
1063
|
+
"properties": {
|
|
1064
|
+
"phone": {
|
|
1065
|
+
"type": "string",
|
|
1066
|
+
"description": "Phone number (digits only) to extract PIN from"
|
|
1067
|
+
}
|
|
1068
|
+
},
|
|
1069
|
+
"required": ["phone"]
|
|
1070
|
+
}
|
|
1071
|
+
)
|
|
1072
|
+
|
|
1073
|
+
FORMAT_DATETIME_RANGE_TOOL = Tool(
|
|
1074
|
+
name="format-datetime-range",
|
|
1075
|
+
description="Convert a date string (YYYY-MM-DD) to BioStar datetime range (start: 00:00:00, end: 23:59:00). Example: '2025-12-25' becomes ('2025-12-25T00:00:00.00Z', '2025-12-25T23:59:00.00Z')",
|
|
1076
|
+
inputSchema={
|
|
1077
|
+
"type": "object",
|
|
1078
|
+
"properties": {
|
|
1079
|
+
"date_str": {
|
|
1080
|
+
"type": "string",
|
|
1081
|
+
"description": "Date string in YYYY-MM-DD format"
|
|
1082
|
+
}
|
|
1083
|
+
},
|
|
1084
|
+
"required": ["date_str"]
|
|
1085
|
+
}
|
|
1086
|
+
)
|
|
1087
|
+
|
|
1088
|
+
# List of all user tools
|
|
1089
|
+
USER_TOOLS = [
|
|
1090
|
+
GET_USERS_TOOL,
|
|
1091
|
+
CREATE_USER_TOOL,
|
|
1092
|
+
GET_USER_TOOL,
|
|
1093
|
+
UPDATE_USER_TOOL,
|
|
1094
|
+
DELETE_USER_TOOL,
|
|
1095
|
+
SEARCH_USERS_TOOL,
|
|
1096
|
+
ADVANCED_SEARCH_USERS_TOOL,
|
|
1097
|
+
GET_USER_CARDS_TOOL,
|
|
1098
|
+
UNASSIGN_USER_CARDS_TOOL,
|
|
1099
|
+
BULK_ADD_USERS_TOOL,
|
|
1100
|
+
EXPORT_USERS_CSV_TOOL,
|
|
1101
|
+
EXPORT_NON_ACCESSED_USERS_CSV_TOOL,
|
|
1102
|
+
GET_USER_GROUPS_TOOL,
|
|
1103
|
+
CREATE_USER_GROUP_TOOL,
|
|
1104
|
+
ADD_USER_TO_GROUP_TOOL,
|
|
1105
|
+
REMOVE_USER_FROM_GROUP_TOOL,
|
|
1106
|
+
BULK_EDIT_USERS_TOOL,
|
|
1107
|
+
IMPORT_USERS_CSV_TOOL,
|
|
1108
|
+
IMPORT_USERS_CSV_SMART_TOOL,
|
|
1109
|
+
BULK_UPDATE_USERS_FROM_FILE_TOOL,
|
|
1110
|
+
FORMAT_PHONE_NUMBER_TOOL,
|
|
1111
|
+
FORMAT_PIN_FROM_PHONE_TOOL,
|
|
1112
|
+
FORMAT_DATETIME_RANGE_TOOL
|
|
1113
|
+
]
|