@wilnertech/halopsa-mcp-server 1.0.0
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.
- package/.env.example +19 -0
- package/LICENSE +21 -0
- package/README.md +270 -0
- package/dist/api/client.d.ts +85 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +297 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/errors.d.ts +60 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +188 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/cache/memory-cache.d.ts +89 -0
- package/dist/cache/memory-cache.d.ts.map +1 -0
- package/dist/cache/memory-cache.js +175 -0
- package/dist/cache/memory-cache.js.map +1 -0
- package/dist/cache/prewarm.d.ts +12 -0
- package/dist/cache/prewarm.d.ts.map +1 -0
- package/dist/cache/prewarm.js +55 -0
- package/dist/cache/prewarm.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/common.d.ts +212 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +127 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/tools/assets.d.ts +482 -0
- package/dist/tools/assets.d.ts.map +1 -0
- package/dist/tools/assets.js +732 -0
- package/dist/tools/assets.js.map +1 -0
- package/dist/tools/batch-operations.d.ts +125 -0
- package/dist/tools/batch-operations.d.ts.map +1 -0
- package/dist/tools/batch-operations.js +207 -0
- package/dist/tools/batch-operations.js.map +1 -0
- package/dist/tools/clients.d.ts +145 -0
- package/dist/tools/clients.d.ts.map +1 -0
- package/dist/tools/clients.js +148 -0
- package/dist/tools/clients.js.map +1 -0
- package/dist/tools/reference-data.d.ts +118 -0
- package/dist/tools/reference-data.d.ts.map +1 -0
- package/dist/tools/reference-data.js +103 -0
- package/dist/tools/reference-data.js.map +1 -0
- package/dist/tools/registrations.d.ts +7 -0
- package/dist/tools/registrations.d.ts.map +1 -0
- package/dist/tools/registrations.js +61 -0
- package/dist/tools/registrations.js.map +1 -0
- package/dist/tools/registry.d.ts +67 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +71 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/sites.d.ts +188 -0
- package/dist/tools/sites.d.ts.map +1 -0
- package/dist/tools/sites.js +258 -0
- package/dist/tools/sites.js.map +1 -0
- package/dist/tools/users.d.ts +317 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +489 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/types/halopsa.d.ts +212 -0
- package/dist/types/halopsa.d.ts.map +1 -0
- package/dist/types/halopsa.js +8 -0
- package/dist/types/halopsa.js.map +1 -0
- package/dist/utils/formatter.d.ts +18 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +178 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/similarity.d.ts +25 -0
- package/dist/utils/similarity.d.ts.map +1 -0
- package/dist/utils/similarity.js +90 -0
- package/dist/utils/similarity.js.map +1 -0
- package/dist/utils/zod-to-schema.d.ts +29 -0
- package/dist/utils/zod-to-schema.d.ts.map +1 -0
- package/dist/utils/zod-to-schema.js +182 -0
- package/dist/utils/zod-to-schema.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HaloPSA User tools with token optimization
|
|
3
|
+
* Provides CRUD operations for users with caching and deduplication
|
|
4
|
+
*
|
|
5
|
+
* CRITICAL: Users are a secondary billing entity
|
|
6
|
+
* - Only ACTIVE users (inactive=false) count toward billing
|
|
7
|
+
* - Duplicates cause billing errors = revenue loss
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { formatResponse } from '../utils/formatter.js';
|
|
11
|
+
import { TTL } from '../cache/memory-cache.js';
|
|
12
|
+
import { FormatOptionsSchema, ConfidenceThresholds } from '../schemas/common.js';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Zod Schemas for Input Validation
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* List users schema
|
|
18
|
+
*/
|
|
19
|
+
export const ListUsersArgsSchema = z.object({
|
|
20
|
+
client_id: z.number().int().optional()
|
|
21
|
+
.describe('Filter by client ID (REQUIRED for multi-tenant environments)'),
|
|
22
|
+
site_id: z.number().int().optional()
|
|
23
|
+
.describe('Filter by site/location ID'),
|
|
24
|
+
search: z.string().optional()
|
|
25
|
+
.describe('Search term'),
|
|
26
|
+
count: z.number().int().min(1).max(100).optional()
|
|
27
|
+
.describe('Number of results per page (max 100, default 50)'),
|
|
28
|
+
page_no: z.number().int().min(1).optional()
|
|
29
|
+
.describe('Page number (1-indexed, default 1)'),
|
|
30
|
+
includeactive: z.boolean().optional()
|
|
31
|
+
.describe('Include active users (default true)'),
|
|
32
|
+
includeinactive: z.boolean().optional()
|
|
33
|
+
.describe('Include inactive users (default false)'),
|
|
34
|
+
format_options: FormatOptionsSchema,
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Get single user schema
|
|
38
|
+
*/
|
|
39
|
+
export const GetUserArgsSchema = z.object({
|
|
40
|
+
user_id: z.number().int()
|
|
41
|
+
.describe('HaloPSA user ID'),
|
|
42
|
+
format_options: FormatOptionsSchema,
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Search users by email schema
|
|
46
|
+
*/
|
|
47
|
+
export const SearchUsersByEmailArgsSchema = z.object({
|
|
48
|
+
email: z.string().email()
|
|
49
|
+
.describe('Email address to search for (primary match field)'),
|
|
50
|
+
client_id: z.number().int().optional()
|
|
51
|
+
.describe('Limit search to specific client'),
|
|
52
|
+
format_options: FormatOptionsSchema,
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Create user schema
|
|
56
|
+
*/
|
|
57
|
+
export const CreateUserArgsSchema = z.object({
|
|
58
|
+
client_id: z.number().int()
|
|
59
|
+
.describe('Client ID to create user under'),
|
|
60
|
+
site_id: z.number().int().optional()
|
|
61
|
+
.describe('Site/location ID'),
|
|
62
|
+
name: z.string().min(1)
|
|
63
|
+
.describe('Full name'),
|
|
64
|
+
emailaddress: z.string().email().optional()
|
|
65
|
+
.describe('Email address (PRIMARY deduplication field)'),
|
|
66
|
+
username: z.string().optional()
|
|
67
|
+
.describe('Windows username'),
|
|
68
|
+
inactive: z.boolean().optional()
|
|
69
|
+
.describe('Inactive status (false=Active, counts for billing)'),
|
|
70
|
+
user_customfields: z.array(z.object({
|
|
71
|
+
id: z.number().int(),
|
|
72
|
+
value: z.string(),
|
|
73
|
+
})).optional()
|
|
74
|
+
.describe('Custom fields array (e.g., UPN)'),
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Update user schema
|
|
78
|
+
*/
|
|
79
|
+
export const UpdateUserArgsSchema = z.object({
|
|
80
|
+
user_id: z.number().int()
|
|
81
|
+
.describe('HaloPSA user ID to update'),
|
|
82
|
+
site_id: z.number().int().optional()
|
|
83
|
+
.describe('Site/location ID'),
|
|
84
|
+
name: z.string().min(1).optional()
|
|
85
|
+
.describe('Full name'),
|
|
86
|
+
emailaddress: z.string().email().optional()
|
|
87
|
+
.describe('Email address'),
|
|
88
|
+
username: z.string().optional()
|
|
89
|
+
.describe('Windows username'),
|
|
90
|
+
inactive: z.boolean().optional()
|
|
91
|
+
.describe('Inactive status'),
|
|
92
|
+
user_customfields: z.array(z.object({
|
|
93
|
+
id: z.number().int(),
|
|
94
|
+
value: z.string(),
|
|
95
|
+
})).optional()
|
|
96
|
+
.describe('Custom fields array'),
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* Find user match schema (deduplication)
|
|
100
|
+
*/
|
|
101
|
+
export const FindUserMatchArgsSchema = z.object({
|
|
102
|
+
email: z.string().email().optional()
|
|
103
|
+
.describe('Email address (primary match field)'),
|
|
104
|
+
upn: z.string().optional()
|
|
105
|
+
.describe('User Principal Name from Entra (secondary match field)'),
|
|
106
|
+
username: z.string().optional()
|
|
107
|
+
.describe('Windows username (tertiary match field)'),
|
|
108
|
+
client_id: z.number().int()
|
|
109
|
+
.describe('Client ID to scope search'),
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* Scan user duplicates schema
|
|
113
|
+
*/
|
|
114
|
+
export const ScanUserDuplicatesArgsSchema = z.object({
|
|
115
|
+
client_id: z.number().int().optional()
|
|
116
|
+
.describe('Limit scan to specific client'),
|
|
117
|
+
format_options: FormatOptionsSchema,
|
|
118
|
+
});
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// Tool Implementations
|
|
121
|
+
// =============================================================================
|
|
122
|
+
/**
|
|
123
|
+
* List users with optional filtering and token optimization
|
|
124
|
+
* Uses 1-minute cache TTL (billing-critical data)
|
|
125
|
+
*/
|
|
126
|
+
export async function listUsers(client, args) {
|
|
127
|
+
const params = {};
|
|
128
|
+
// Build query parameters
|
|
129
|
+
if (args.client_id !== undefined) {
|
|
130
|
+
params.client_id = args.client_id;
|
|
131
|
+
}
|
|
132
|
+
if (args.site_id !== undefined) {
|
|
133
|
+
params.site_id = args.site_id;
|
|
134
|
+
}
|
|
135
|
+
if (args.search !== undefined) {
|
|
136
|
+
params.search = args.search;
|
|
137
|
+
}
|
|
138
|
+
if (args.count !== undefined) {
|
|
139
|
+
params.count = args.count;
|
|
140
|
+
}
|
|
141
|
+
if (args.page_no !== undefined) {
|
|
142
|
+
params.page_no = args.page_no;
|
|
143
|
+
}
|
|
144
|
+
if (args.includeactive !== undefined) {
|
|
145
|
+
params.includeactive = args.includeactive;
|
|
146
|
+
}
|
|
147
|
+
if (args.includeinactive !== undefined) {
|
|
148
|
+
params.includeinactive = args.includeinactive;
|
|
149
|
+
}
|
|
150
|
+
const formatOptions = args.format_options || {};
|
|
151
|
+
// Generate cache key based on filters
|
|
152
|
+
const cacheKey = `users:client_${args.client_id || 'all'}:site_${args.site_id || 'all'}`;
|
|
153
|
+
const response = await client.getCached('/Users', params, {
|
|
154
|
+
enabled: true,
|
|
155
|
+
ttl: TTL.USER_LIST,
|
|
156
|
+
keyPrefix: cacheKey,
|
|
157
|
+
});
|
|
158
|
+
return formatResponse(response.users, formatOptions, { record_count: response.record_count });
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get a single user by ID with full details
|
|
162
|
+
*/
|
|
163
|
+
export async function getUser(client, args) {
|
|
164
|
+
const formatOptions = args.format_options || {};
|
|
165
|
+
const response = await client.get(`/Users/${args.user_id}`);
|
|
166
|
+
return formatResponse(response, formatOptions);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Search users by email address
|
|
170
|
+
* Returns warning if multiple found (potential duplicates)
|
|
171
|
+
*/
|
|
172
|
+
export async function searchUsersByEmail(client, args) {
|
|
173
|
+
const params = {
|
|
174
|
+
search: args.email,
|
|
175
|
+
count: 100,
|
|
176
|
+
includeactive: true,
|
|
177
|
+
includeinactive: true,
|
|
178
|
+
};
|
|
179
|
+
if (args.client_id !== undefined) {
|
|
180
|
+
params.client_id = args.client_id;
|
|
181
|
+
}
|
|
182
|
+
const formatOptions = args.format_options || {};
|
|
183
|
+
// No caching for search results
|
|
184
|
+
const response = await client.get('/Users', params);
|
|
185
|
+
// Filter to exact email matches
|
|
186
|
+
const exactMatches = response.users.filter((user) => user.emailaddress?.toLowerCase() === args.email.toLowerCase());
|
|
187
|
+
if (exactMatches.length === 0) {
|
|
188
|
+
return JSON.stringify({
|
|
189
|
+
email: args.email,
|
|
190
|
+
matches: [],
|
|
191
|
+
count: 0,
|
|
192
|
+
message: 'No users found with this email address',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// Warning if duplicates found
|
|
196
|
+
const warning = exactMatches.length > 1
|
|
197
|
+
? `WARNING: Multiple users found with email ${args.email}. Potential duplicates detected.`
|
|
198
|
+
: undefined;
|
|
199
|
+
const result = {
|
|
200
|
+
email: args.email,
|
|
201
|
+
matches: JSON.parse(formatResponse(exactMatches, formatOptions)),
|
|
202
|
+
count: exactMatches.length,
|
|
203
|
+
...(warning && { warning }),
|
|
204
|
+
};
|
|
205
|
+
return JSON.stringify(result, null, 2);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Create a new user
|
|
209
|
+
* Invalidates user cache on success
|
|
210
|
+
*/
|
|
211
|
+
export async function createUser(client, args) {
|
|
212
|
+
const userData = {
|
|
213
|
+
client_id: args.client_id,
|
|
214
|
+
name: args.name,
|
|
215
|
+
};
|
|
216
|
+
// Add optional fields
|
|
217
|
+
if (args.site_id !== undefined) {
|
|
218
|
+
userData.site_id = args.site_id;
|
|
219
|
+
}
|
|
220
|
+
if (args.emailaddress !== undefined) {
|
|
221
|
+
userData.emailaddress = args.emailaddress;
|
|
222
|
+
}
|
|
223
|
+
if (args.username !== undefined) {
|
|
224
|
+
userData.username = args.username;
|
|
225
|
+
}
|
|
226
|
+
if (args.inactive !== undefined) {
|
|
227
|
+
userData.inactive = args.inactive;
|
|
228
|
+
}
|
|
229
|
+
if (args.user_customfields !== undefined) {
|
|
230
|
+
userData.user_customfields = args.user_customfields;
|
|
231
|
+
}
|
|
232
|
+
const response = await client.post('/Users', userData);
|
|
233
|
+
// Invalidate user caches
|
|
234
|
+
client.invalidateCache(`users:client_${args.client_id}*`);
|
|
235
|
+
client.invalidateCache('users:client_all*');
|
|
236
|
+
return formatResponse(response, { format: 'detailed' });
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Update an existing user
|
|
240
|
+
* Invalidates user cache on success
|
|
241
|
+
*/
|
|
242
|
+
export async function updateUser(client, args) {
|
|
243
|
+
const userData = {};
|
|
244
|
+
// Build update payload with only provided fields
|
|
245
|
+
if (args.site_id !== undefined) {
|
|
246
|
+
userData.site_id = args.site_id;
|
|
247
|
+
}
|
|
248
|
+
if (args.name !== undefined) {
|
|
249
|
+
userData.name = args.name;
|
|
250
|
+
}
|
|
251
|
+
if (args.emailaddress !== undefined) {
|
|
252
|
+
userData.emailaddress = args.emailaddress;
|
|
253
|
+
}
|
|
254
|
+
if (args.username !== undefined) {
|
|
255
|
+
userData.username = args.username;
|
|
256
|
+
}
|
|
257
|
+
if (args.inactive !== undefined) {
|
|
258
|
+
userData.inactive = args.inactive;
|
|
259
|
+
}
|
|
260
|
+
if (args.user_customfields !== undefined) {
|
|
261
|
+
userData.user_customfields = args.user_customfields;
|
|
262
|
+
}
|
|
263
|
+
if (Object.keys(userData).length === 0) {
|
|
264
|
+
return JSON.stringify({
|
|
265
|
+
error: true,
|
|
266
|
+
message: 'At least one field must be provided for update',
|
|
267
|
+
}, null, 2);
|
|
268
|
+
}
|
|
269
|
+
// HaloPSA uses POST for updates
|
|
270
|
+
const response = await client.post(`/Users/${args.user_id}`, userData);
|
|
271
|
+
// Invalidate user caches
|
|
272
|
+
client.invalidateCache('users:*');
|
|
273
|
+
return formatResponse(response, { format: 'detailed' });
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Find matching user using deduplication algorithm
|
|
277
|
+
* Returns confidence scoring and action recommendation
|
|
278
|
+
*
|
|
279
|
+
* Confidence Thresholds:
|
|
280
|
+
* - 100%: Exact email match -> Auto-update
|
|
281
|
+
* - 95%: UPN match (Entra source of truth) -> Auto-update
|
|
282
|
+
* - 70%: Username match only -> Manual review
|
|
283
|
+
* - 0%: No match -> Create new
|
|
284
|
+
*/
|
|
285
|
+
export async function findUserMatch(client, args) {
|
|
286
|
+
// Get all users for client with caching
|
|
287
|
+
const response = await client.getCached('/Users', {
|
|
288
|
+
client_id: args.client_id,
|
|
289
|
+
count: 1000,
|
|
290
|
+
includeactive: true,
|
|
291
|
+
includeinactive: true,
|
|
292
|
+
}, {
|
|
293
|
+
enabled: true,
|
|
294
|
+
ttl: TTL.USER_LIST,
|
|
295
|
+
keyPrefix: `users:client_${args.client_id}`,
|
|
296
|
+
});
|
|
297
|
+
if (!response.users || response.users.length === 0) {
|
|
298
|
+
return JSON.stringify({
|
|
299
|
+
match: null,
|
|
300
|
+
confidence: 0,
|
|
301
|
+
matchField: 'none',
|
|
302
|
+
action: 'CreateNew',
|
|
303
|
+
}, null, 2);
|
|
304
|
+
}
|
|
305
|
+
// 1. Exact email match (100% confidence)
|
|
306
|
+
if (args.email) {
|
|
307
|
+
const emailMatch = response.users.find((user) => user.emailaddress?.toLowerCase() === args.email?.toLowerCase());
|
|
308
|
+
if (emailMatch) {
|
|
309
|
+
return JSON.stringify({
|
|
310
|
+
match: emailMatch,
|
|
311
|
+
confidence: ConfidenceThresholds.USER_EMAIL_EXACT,
|
|
312
|
+
matchField: 'email (exact)',
|
|
313
|
+
action: 'Update',
|
|
314
|
+
}, null, 2);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// 2. UPN match (95% confidence - Entra is source of truth)
|
|
318
|
+
if (args.upn) {
|
|
319
|
+
const upnMatch = response.users.find((user) => {
|
|
320
|
+
const upnField = user.user_customfields?.find((cf) => cf.name.toLowerCase() === 'upn');
|
|
321
|
+
return upnField?.value?.toLowerCase() === args.upn?.toLowerCase();
|
|
322
|
+
});
|
|
323
|
+
if (upnMatch) {
|
|
324
|
+
return JSON.stringify({
|
|
325
|
+
match: upnMatch,
|
|
326
|
+
confidence: ConfidenceThresholds.USER_UPN_MATCH,
|
|
327
|
+
matchField: 'upn (Entra)',
|
|
328
|
+
action: 'Update',
|
|
329
|
+
}, null, 2);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// 3. Username match only (70% confidence - requires manual review)
|
|
333
|
+
if (args.username) {
|
|
334
|
+
const usernameMatch = response.users.find((user) => user.username?.toLowerCase() === args.username?.toLowerCase());
|
|
335
|
+
if (usernameMatch) {
|
|
336
|
+
return JSON.stringify({
|
|
337
|
+
match: usernameMatch,
|
|
338
|
+
confidence: ConfidenceThresholds.USER_USERNAME_ONLY,
|
|
339
|
+
matchField: 'username (no email match)',
|
|
340
|
+
action: 'ManualReview',
|
|
341
|
+
warning: 'Username match found but email does not match. Manual review required.',
|
|
342
|
+
}, null, 2);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// 4. No match found - create new
|
|
346
|
+
return JSON.stringify({
|
|
347
|
+
match: null,
|
|
348
|
+
confidence: 0,
|
|
349
|
+
matchField: 'none',
|
|
350
|
+
action: 'CreateNew',
|
|
351
|
+
}, null, 2);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Scan for duplicate users
|
|
355
|
+
* Returns groups of duplicate entities with confidence scores
|
|
356
|
+
*/
|
|
357
|
+
export async function scanUserDuplicates(client, args) {
|
|
358
|
+
const formatOptions = args.format_options || {};
|
|
359
|
+
const params = {
|
|
360
|
+
count: 1000,
|
|
361
|
+
includeactive: true,
|
|
362
|
+
includeinactive: true,
|
|
363
|
+
};
|
|
364
|
+
if (args.client_id !== undefined) {
|
|
365
|
+
params.client_id = args.client_id;
|
|
366
|
+
}
|
|
367
|
+
const response = await client.getCached('/Users', params, {
|
|
368
|
+
enabled: true,
|
|
369
|
+
ttl: TTL.USER_LIST,
|
|
370
|
+
keyPrefix: args.client_id ? `users:client_${args.client_id}` : 'users:client_all',
|
|
371
|
+
});
|
|
372
|
+
const duplicates = [];
|
|
373
|
+
// Group users by email address to find duplicates
|
|
374
|
+
const emailToUsers = new Map();
|
|
375
|
+
for (const user of response.users) {
|
|
376
|
+
if (user.emailaddress) {
|
|
377
|
+
const normalizedEmail = user.emailaddress.toLowerCase();
|
|
378
|
+
const existing = emailToUsers.get(normalizedEmail) || [];
|
|
379
|
+
existing.push(user);
|
|
380
|
+
emailToUsers.set(normalizedEmail, existing);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// Find emails with multiple users (duplicates)
|
|
384
|
+
for (const [email, users] of emailToUsers.entries()) {
|
|
385
|
+
if (users.length > 1) {
|
|
386
|
+
duplicates.push({
|
|
387
|
+
type: 'user',
|
|
388
|
+
matchField: 'email',
|
|
389
|
+
matchValue: email,
|
|
390
|
+
confidence: 'High', // Exact email match = high confidence
|
|
391
|
+
entity_count: users.length,
|
|
392
|
+
entities: users.map((u) => ({
|
|
393
|
+
id: u.id,
|
|
394
|
+
name: u.name,
|
|
395
|
+
email: u.emailaddress,
|
|
396
|
+
username: u.username,
|
|
397
|
+
})),
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// Also scan by username for medium confidence duplicates
|
|
402
|
+
const usernameToUsers = new Map();
|
|
403
|
+
for (const user of response.users) {
|
|
404
|
+
if (user.username) {
|
|
405
|
+
const normalizedUsername = user.username.toLowerCase();
|
|
406
|
+
const existing = usernameToUsers.get(normalizedUsername) || [];
|
|
407
|
+
existing.push(user);
|
|
408
|
+
usernameToUsers.set(normalizedUsername, existing);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
for (const [username, users] of usernameToUsers.entries()) {
|
|
412
|
+
if (users.length > 1) {
|
|
413
|
+
// Check if these are already captured by email scan
|
|
414
|
+
const emails = new Set(users.map((u) => u.emailaddress?.toLowerCase()).filter(Boolean));
|
|
415
|
+
const isNewDuplicate = emails.size > 1; // Different emails = new duplicate group
|
|
416
|
+
if (isNewDuplicate) {
|
|
417
|
+
duplicates.push({
|
|
418
|
+
type: 'user',
|
|
419
|
+
matchField: 'username',
|
|
420
|
+
matchValue: username,
|
|
421
|
+
confidence: 'Medium', // Username only = medium confidence
|
|
422
|
+
entity_count: users.length,
|
|
423
|
+
entities: users.map((u) => ({
|
|
424
|
+
id: u.id,
|
|
425
|
+
name: u.name,
|
|
426
|
+
email: u.emailaddress,
|
|
427
|
+
username: u.username,
|
|
428
|
+
})),
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const result = {
|
|
434
|
+
client_id: args.client_id || 'all',
|
|
435
|
+
users_scanned: response.users.length,
|
|
436
|
+
duplicates_found: duplicates.length,
|
|
437
|
+
duplicates,
|
|
438
|
+
};
|
|
439
|
+
if (formatOptions.format === 'detailed') {
|
|
440
|
+
return JSON.stringify(result, null, 2);
|
|
441
|
+
}
|
|
442
|
+
return JSON.stringify(result);
|
|
443
|
+
}
|
|
444
|
+
// =============================================================================
|
|
445
|
+
// Tool Definitions (for ToolRegistry)
|
|
446
|
+
// =============================================================================
|
|
447
|
+
export const listUsersTool = {
|
|
448
|
+
name: 'list_halopsa_users',
|
|
449
|
+
description: 'List HaloPSA users with optional filtering, caching (1min TTL), and token optimization. Only inactive=false users count for billing.',
|
|
450
|
+
schema: ListUsersArgsSchema,
|
|
451
|
+
handler: listUsers,
|
|
452
|
+
};
|
|
453
|
+
export const getUserTool = {
|
|
454
|
+
name: 'get_halopsa_user',
|
|
455
|
+
description: 'Get a single HaloPSA user by ID with full details including custom fields (user_customfields)',
|
|
456
|
+
schema: GetUserArgsSchema,
|
|
457
|
+
handler: getUser,
|
|
458
|
+
};
|
|
459
|
+
export const searchUsersByEmailTool = {
|
|
460
|
+
name: 'search_halopsa_users_by_email',
|
|
461
|
+
description: 'Search HaloPSA users by email address (primary match field). Returns warning if multiple found.',
|
|
462
|
+
schema: SearchUsersByEmailArgsSchema,
|
|
463
|
+
handler: searchUsersByEmail,
|
|
464
|
+
};
|
|
465
|
+
export const createUserTool = {
|
|
466
|
+
name: 'create_halopsa_user',
|
|
467
|
+
description: 'Create a new HaloPSA user. Invalidates user cache. Use find_halopsa_user_match first to prevent duplicates.',
|
|
468
|
+
schema: CreateUserArgsSchema,
|
|
469
|
+
handler: createUser,
|
|
470
|
+
};
|
|
471
|
+
export const updateUserTool = {
|
|
472
|
+
name: 'update_halopsa_user',
|
|
473
|
+
description: 'Update an existing HaloPSA user. Invalidates user cache.',
|
|
474
|
+
schema: UpdateUserArgsSchema,
|
|
475
|
+
handler: updateUser,
|
|
476
|
+
};
|
|
477
|
+
export const findUserMatchTool = {
|
|
478
|
+
name: 'find_halopsa_user_match',
|
|
479
|
+
description: 'Find matching user using deduplication algorithm. Email=100%, UPN=95%, Username=70% confidence. CRITICAL for billing accuracy.',
|
|
480
|
+
schema: FindUserMatchArgsSchema,
|
|
481
|
+
handler: findUserMatch,
|
|
482
|
+
};
|
|
483
|
+
export const scanUserDuplicatesTool = {
|
|
484
|
+
name: 'scan_halopsa_user_duplicates',
|
|
485
|
+
description: 'Scan for duplicate users by email/username. Returns groups with confidence scores.',
|
|
486
|
+
schema: ScanUserDuplicatesArgsSchema,
|
|
487
|
+
handler: scanUserDuplicates,
|
|
488
|
+
};
|
|
489
|
+
//# sourceMappingURL=users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/tools/users.ts"],"names":[],"mappings":"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"}
|