@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,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HaloPSA Site (Location) tools with token optimization
|
|
3
|
+
* Provides CRUD operations for sites with caching and deduplication
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import type { HaloPSAAPIClient } from '../api/client.js';
|
|
7
|
+
import type { ZodToolDefinition } from './registry.js';
|
|
8
|
+
/**
|
|
9
|
+
* List sites schema
|
|
10
|
+
*/
|
|
11
|
+
export declare const ListSitesArgsSchema: z.ZodObject<{
|
|
12
|
+
client_id: z.ZodOptional<z.ZodNumber>;
|
|
13
|
+
search: z.ZodOptional<z.ZodString>;
|
|
14
|
+
count: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
page_no: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
format_options: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
format: z.ZodOptional<z.ZodEnum<["compact", "standard", "detailed"]>>;
|
|
18
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
19
|
+
omit_empty: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
22
|
+
fields?: string[] | undefined;
|
|
23
|
+
omit_empty?: boolean | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
26
|
+
fields?: string[] | undefined;
|
|
27
|
+
omit_empty?: boolean | undefined;
|
|
28
|
+
}>>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
client_id?: number | undefined;
|
|
31
|
+
count?: number | undefined;
|
|
32
|
+
page_no?: number | undefined;
|
|
33
|
+
search?: string | undefined;
|
|
34
|
+
format_options?: {
|
|
35
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
36
|
+
fields?: string[] | undefined;
|
|
37
|
+
omit_empty?: boolean | undefined;
|
|
38
|
+
} | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
client_id?: number | undefined;
|
|
41
|
+
count?: number | undefined;
|
|
42
|
+
page_no?: number | undefined;
|
|
43
|
+
search?: string | undefined;
|
|
44
|
+
format_options?: {
|
|
45
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
46
|
+
fields?: string[] | undefined;
|
|
47
|
+
omit_empty?: boolean | undefined;
|
|
48
|
+
} | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Get single site schema
|
|
52
|
+
*/
|
|
53
|
+
export declare const GetSiteArgsSchema: z.ZodObject<{
|
|
54
|
+
site_id: z.ZodNumber;
|
|
55
|
+
format_options: z.ZodOptional<z.ZodObject<{
|
|
56
|
+
format: z.ZodOptional<z.ZodEnum<["compact", "standard", "detailed"]>>;
|
|
57
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
58
|
+
omit_empty: z.ZodOptional<z.ZodBoolean>;
|
|
59
|
+
}, "strip", z.ZodTypeAny, {
|
|
60
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
61
|
+
fields?: string[] | undefined;
|
|
62
|
+
omit_empty?: boolean | undefined;
|
|
63
|
+
}, {
|
|
64
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
65
|
+
fields?: string[] | undefined;
|
|
66
|
+
omit_empty?: boolean | undefined;
|
|
67
|
+
}>>;
|
|
68
|
+
}, "strip", z.ZodTypeAny, {
|
|
69
|
+
site_id: number;
|
|
70
|
+
format_options?: {
|
|
71
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
72
|
+
fields?: string[] | undefined;
|
|
73
|
+
omit_empty?: boolean | undefined;
|
|
74
|
+
} | undefined;
|
|
75
|
+
}, {
|
|
76
|
+
site_id: number;
|
|
77
|
+
format_options?: {
|
|
78
|
+
format?: "compact" | "standard" | "detailed" | undefined;
|
|
79
|
+
fields?: string[] | undefined;
|
|
80
|
+
omit_empty?: boolean | undefined;
|
|
81
|
+
} | undefined;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Create site schema
|
|
85
|
+
*/
|
|
86
|
+
export declare const CreateSiteArgsSchema: z.ZodObject<{
|
|
87
|
+
client_id: z.ZodNumber;
|
|
88
|
+
name: z.ZodString;
|
|
89
|
+
maincontact_name: z.ZodOptional<z.ZodString>;
|
|
90
|
+
phonenumber: z.ZodOptional<z.ZodString>;
|
|
91
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
92
|
+
address: z.ZodOptional<z.ZodObject<{
|
|
93
|
+
addressline1: z.ZodOptional<z.ZodString>;
|
|
94
|
+
addressline2: z.ZodOptional<z.ZodString>;
|
|
95
|
+
city: z.ZodOptional<z.ZodString>;
|
|
96
|
+
state: z.ZodOptional<z.ZodString>;
|
|
97
|
+
postalcode: z.ZodOptional<z.ZodString>;
|
|
98
|
+
country: z.ZodOptional<z.ZodString>;
|
|
99
|
+
}, "strip", z.ZodTypeAny, {
|
|
100
|
+
addressline1?: string | undefined;
|
|
101
|
+
addressline2?: string | undefined;
|
|
102
|
+
city?: string | undefined;
|
|
103
|
+
state?: string | undefined;
|
|
104
|
+
postalcode?: string | undefined;
|
|
105
|
+
country?: string | undefined;
|
|
106
|
+
}, {
|
|
107
|
+
addressline1?: string | undefined;
|
|
108
|
+
addressline2?: string | undefined;
|
|
109
|
+
city?: string | undefined;
|
|
110
|
+
state?: string | undefined;
|
|
111
|
+
postalcode?: string | undefined;
|
|
112
|
+
country?: string | undefined;
|
|
113
|
+
}>>;
|
|
114
|
+
}, "strip", z.ZodTypeAny, {
|
|
115
|
+
client_id: number;
|
|
116
|
+
name: string;
|
|
117
|
+
notes?: string | undefined;
|
|
118
|
+
maincontact_name?: string | undefined;
|
|
119
|
+
phonenumber?: string | undefined;
|
|
120
|
+
address?: {
|
|
121
|
+
addressline1?: string | undefined;
|
|
122
|
+
addressline2?: string | undefined;
|
|
123
|
+
city?: string | undefined;
|
|
124
|
+
state?: string | undefined;
|
|
125
|
+
postalcode?: string | undefined;
|
|
126
|
+
country?: string | undefined;
|
|
127
|
+
} | undefined;
|
|
128
|
+
}, {
|
|
129
|
+
client_id: number;
|
|
130
|
+
name: string;
|
|
131
|
+
notes?: string | undefined;
|
|
132
|
+
maincontact_name?: string | undefined;
|
|
133
|
+
phonenumber?: string | undefined;
|
|
134
|
+
address?: {
|
|
135
|
+
addressline1?: string | undefined;
|
|
136
|
+
addressline2?: string | undefined;
|
|
137
|
+
city?: string | undefined;
|
|
138
|
+
state?: string | undefined;
|
|
139
|
+
postalcode?: string | undefined;
|
|
140
|
+
country?: string | undefined;
|
|
141
|
+
} | undefined;
|
|
142
|
+
}>;
|
|
143
|
+
/**
|
|
144
|
+
* Find site match schema (deduplication)
|
|
145
|
+
*/
|
|
146
|
+
export declare const FindSiteMatchArgsSchema: z.ZodObject<{
|
|
147
|
+
name: z.ZodString;
|
|
148
|
+
address: z.ZodOptional<z.ZodString>;
|
|
149
|
+
client_id: z.ZodNumber;
|
|
150
|
+
}, "strip", z.ZodTypeAny, {
|
|
151
|
+
client_id: number;
|
|
152
|
+
name: string;
|
|
153
|
+
address?: string | undefined;
|
|
154
|
+
}, {
|
|
155
|
+
client_id: number;
|
|
156
|
+
name: string;
|
|
157
|
+
address?: string | undefined;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* List sites with optional filtering and token optimization
|
|
161
|
+
* Uses 5-minute cache TTL
|
|
162
|
+
*/
|
|
163
|
+
export declare function listSites(client: HaloPSAAPIClient, args: z.infer<typeof ListSitesArgsSchema>): Promise<string>;
|
|
164
|
+
/**
|
|
165
|
+
* Get a single site by ID with full details
|
|
166
|
+
*/
|
|
167
|
+
export declare function getSite(client: HaloPSAAPIClient, args: z.infer<typeof GetSiteArgsSchema>): Promise<string>;
|
|
168
|
+
/**
|
|
169
|
+
* Create a new site
|
|
170
|
+
* Invalidates site cache on success
|
|
171
|
+
*/
|
|
172
|
+
export declare function createSite(client: HaloPSAAPIClient, args: z.infer<typeof CreateSiteArgsSchema>): Promise<string>;
|
|
173
|
+
/**
|
|
174
|
+
* Find matching site using deduplication algorithm
|
|
175
|
+
* Returns confidence scoring and action recommendation
|
|
176
|
+
*
|
|
177
|
+
* Confidence Thresholds:
|
|
178
|
+
* - 100%: Exact name match -> Auto-update
|
|
179
|
+
* - 95%: Fuzzy name match (>80%) + address validation -> Auto-update
|
|
180
|
+
* - 85%: Fuzzy name match only -> Manual review
|
|
181
|
+
* - 0%: No match -> Create new
|
|
182
|
+
*/
|
|
183
|
+
export declare function findSiteMatch(client: HaloPSAAPIClient, args: z.infer<typeof FindSiteMatchArgsSchema>): Promise<string>;
|
|
184
|
+
export declare const listSitesTool: ZodToolDefinition;
|
|
185
|
+
export declare const getSiteTool: ZodToolDefinition;
|
|
186
|
+
export declare const createSiteTool: ZodToolDefinition;
|
|
187
|
+
export declare const findSiteMatchTool: ZodToolDefinition;
|
|
188
|
+
//# sourceMappingURL=sites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/tools/sites.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAcvD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU9B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoB/B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;EAOlC,CAAC;AAMH;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,GACxC,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GACzC,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAqGjB;AAMD,eAAO,MAAM,aAAa,EAAE,iBAK3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,iBAKzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,iBAK5B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAC"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HaloPSA Site (Location) tools with token optimization
|
|
3
|
+
* Provides CRUD operations for sites with caching and deduplication
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { formatResponse } from '../utils/formatter.js';
|
|
7
|
+
import { getStringSimilarity, getAddressSimilarity } from '../utils/similarity.js';
|
|
8
|
+
import { TTL } from '../cache/memory-cache.js';
|
|
9
|
+
import { FormatOptionsSchema, ConfidenceThresholds } from '../schemas/common.js';
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Zod Schemas for Input Validation
|
|
12
|
+
// =============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* List sites schema
|
|
15
|
+
*/
|
|
16
|
+
export const ListSitesArgsSchema = z.object({
|
|
17
|
+
client_id: z.number().int().optional()
|
|
18
|
+
.describe('Filter by client ID'),
|
|
19
|
+
search: z.string().optional()
|
|
20
|
+
.describe('Search term'),
|
|
21
|
+
count: z.number().int().min(1).max(100).optional()
|
|
22
|
+
.describe('Number of results per page (max 100, default 50)'),
|
|
23
|
+
page_no: z.number().int().min(1).optional()
|
|
24
|
+
.describe('Page number (1-indexed, default 1)'),
|
|
25
|
+
format_options: FormatOptionsSchema,
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Get single site schema
|
|
29
|
+
*/
|
|
30
|
+
export const GetSiteArgsSchema = z.object({
|
|
31
|
+
site_id: z.number().int()
|
|
32
|
+
.describe('HaloPSA site ID'),
|
|
33
|
+
format_options: FormatOptionsSchema,
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Create site schema
|
|
37
|
+
*/
|
|
38
|
+
export const CreateSiteArgsSchema = z.object({
|
|
39
|
+
client_id: z.number().int()
|
|
40
|
+
.describe('Client ID to create site under'),
|
|
41
|
+
name: z.string().min(1)
|
|
42
|
+
.describe('Site name'),
|
|
43
|
+
maincontact_name: z.string().optional()
|
|
44
|
+
.describe('Main contact name'),
|
|
45
|
+
phonenumber: z.string().optional()
|
|
46
|
+
.describe('Phone number'),
|
|
47
|
+
notes: z.string().optional()
|
|
48
|
+
.describe('Additional notes'),
|
|
49
|
+
address: z.object({
|
|
50
|
+
addressline1: z.string().optional(),
|
|
51
|
+
addressline2: z.string().optional(),
|
|
52
|
+
city: z.string().optional(),
|
|
53
|
+
state: z.string().optional(),
|
|
54
|
+
postalcode: z.string().optional(),
|
|
55
|
+
country: z.string().optional(),
|
|
56
|
+
}).optional()
|
|
57
|
+
.describe('Address object'),
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Find site match schema (deduplication)
|
|
61
|
+
*/
|
|
62
|
+
export const FindSiteMatchArgsSchema = z.object({
|
|
63
|
+
name: z.string().min(1)
|
|
64
|
+
.describe('Site name to search for (primary match field)'),
|
|
65
|
+
address: z.string().optional()
|
|
66
|
+
.describe('Address for secondary validation'),
|
|
67
|
+
client_id: z.number().int()
|
|
68
|
+
.describe('Client ID to scope search'),
|
|
69
|
+
});
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// Tool Implementations
|
|
72
|
+
// =============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* List sites with optional filtering and token optimization
|
|
75
|
+
* Uses 5-minute cache TTL
|
|
76
|
+
*/
|
|
77
|
+
export async function listSites(client, args) {
|
|
78
|
+
const params = {};
|
|
79
|
+
// Build query parameters
|
|
80
|
+
if (args.client_id !== undefined) {
|
|
81
|
+
params.client_id = args.client_id;
|
|
82
|
+
}
|
|
83
|
+
if (args.search !== undefined) {
|
|
84
|
+
params.search = args.search;
|
|
85
|
+
}
|
|
86
|
+
if (args.count !== undefined) {
|
|
87
|
+
params.count = args.count;
|
|
88
|
+
}
|
|
89
|
+
if (args.page_no !== undefined) {
|
|
90
|
+
params.page_no = args.page_no;
|
|
91
|
+
}
|
|
92
|
+
const formatOptions = args.format_options || {};
|
|
93
|
+
// Generate cache key based on filters
|
|
94
|
+
const cacheKey = `sites:client_${args.client_id || 'all'}`;
|
|
95
|
+
const response = await client.getCached('/Site', params, {
|
|
96
|
+
enabled: true,
|
|
97
|
+
ttl: TTL.SITE_LIST,
|
|
98
|
+
keyPrefix: cacheKey,
|
|
99
|
+
});
|
|
100
|
+
return formatResponse(response.sites, formatOptions, { record_count: response.record_count });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get a single site by ID with full details
|
|
104
|
+
*/
|
|
105
|
+
export async function getSite(client, args) {
|
|
106
|
+
const formatOptions = args.format_options || {};
|
|
107
|
+
const response = await client.get(`/Site/${args.site_id}`);
|
|
108
|
+
return formatResponse(response, formatOptions);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a new site
|
|
112
|
+
* Invalidates site cache on success
|
|
113
|
+
*/
|
|
114
|
+
export async function createSite(client, args) {
|
|
115
|
+
const siteData = {
|
|
116
|
+
client_id: args.client_id,
|
|
117
|
+
name: args.name,
|
|
118
|
+
};
|
|
119
|
+
// Add optional fields
|
|
120
|
+
if (args.maincontact_name !== undefined) {
|
|
121
|
+
siteData.maincontact_name = args.maincontact_name;
|
|
122
|
+
}
|
|
123
|
+
if (args.phonenumber !== undefined) {
|
|
124
|
+
siteData.phonenumber = args.phonenumber;
|
|
125
|
+
}
|
|
126
|
+
if (args.notes !== undefined) {
|
|
127
|
+
siteData.notes = args.notes;
|
|
128
|
+
}
|
|
129
|
+
if (args.address !== undefined) {
|
|
130
|
+
siteData.address = args.address;
|
|
131
|
+
}
|
|
132
|
+
const response = await client.post('/Site', siteData);
|
|
133
|
+
// Invalidate site caches
|
|
134
|
+
client.invalidateCache(`sites:client_${args.client_id}*`);
|
|
135
|
+
client.invalidateCache('sites:client_all*');
|
|
136
|
+
return formatResponse(response, { format: 'detailed' });
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Find matching site using deduplication algorithm
|
|
140
|
+
* Returns confidence scoring and action recommendation
|
|
141
|
+
*
|
|
142
|
+
* Confidence Thresholds:
|
|
143
|
+
* - 100%: Exact name match -> Auto-update
|
|
144
|
+
* - 95%: Fuzzy name match (>80%) + address validation -> Auto-update
|
|
145
|
+
* - 85%: Fuzzy name match only -> Manual review
|
|
146
|
+
* - 0%: No match -> Create new
|
|
147
|
+
*/
|
|
148
|
+
export async function findSiteMatch(client, args) {
|
|
149
|
+
// Get all sites for client with caching
|
|
150
|
+
const response = await client.getCached('/Site', {
|
|
151
|
+
client_id: args.client_id,
|
|
152
|
+
count: 1000,
|
|
153
|
+
}, {
|
|
154
|
+
enabled: true,
|
|
155
|
+
ttl: TTL.SITE_LIST,
|
|
156
|
+
keyPrefix: `sites:client_${args.client_id}`,
|
|
157
|
+
});
|
|
158
|
+
if (!response.sites || response.sites.length === 0) {
|
|
159
|
+
return JSON.stringify({
|
|
160
|
+
match: null,
|
|
161
|
+
confidence: 0,
|
|
162
|
+
matchField: 'none',
|
|
163
|
+
action: 'CreateNew',
|
|
164
|
+
}, null, 2);
|
|
165
|
+
}
|
|
166
|
+
// 1. Exact name match (100% confidence)
|
|
167
|
+
const exactMatch = response.sites.find((site) => site.name.toLowerCase() === args.name.toLowerCase());
|
|
168
|
+
if (exactMatch) {
|
|
169
|
+
return JSON.stringify({
|
|
170
|
+
match: exactMatch,
|
|
171
|
+
confidence: ConfidenceThresholds.SITE_NAME_EXACT,
|
|
172
|
+
matchField: 'name (exact)',
|
|
173
|
+
action: 'Update',
|
|
174
|
+
}, null, 2);
|
|
175
|
+
}
|
|
176
|
+
// 2. Fuzzy name matching with secondary validation
|
|
177
|
+
let bestMatch = null;
|
|
178
|
+
let highestConfidence = 0;
|
|
179
|
+
let matchField = 'none';
|
|
180
|
+
for (const site of response.sites) {
|
|
181
|
+
const nameSimilarity = getStringSimilarity(site.name, args.name);
|
|
182
|
+
if (nameSimilarity > 0.8) {
|
|
183
|
+
let confidence = nameSimilarity;
|
|
184
|
+
let field = 'name (fuzzy)';
|
|
185
|
+
// Secondary validation: address
|
|
186
|
+
if (args.address && site.address?.addressline1) {
|
|
187
|
+
const addressSimilarity = getAddressSimilarity(site.address.addressline1, args.address);
|
|
188
|
+
if (addressSimilarity > 0.8) {
|
|
189
|
+
// Boost confidence with address validation
|
|
190
|
+
confidence = Math.min(0.95, (nameSimilarity + addressSimilarity) / 2 + 0.1);
|
|
191
|
+
field = 'name+address';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (confidence > highestConfidence) {
|
|
195
|
+
highestConfidence = confidence;
|
|
196
|
+
bestMatch = site;
|
|
197
|
+
matchField = field;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Determine action based on confidence
|
|
202
|
+
if (bestMatch) {
|
|
203
|
+
let action;
|
|
204
|
+
if (highestConfidence >= ConfidenceThresholds.SITE_FUZZY_WITH_ADDRESS) {
|
|
205
|
+
action = 'Update';
|
|
206
|
+
}
|
|
207
|
+
else if (highestConfidence >= ConfidenceThresholds.SITE_FUZZY_ONLY) {
|
|
208
|
+
action = 'ManualReview';
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
action = 'CreateNew';
|
|
212
|
+
}
|
|
213
|
+
return JSON.stringify({
|
|
214
|
+
match: bestMatch,
|
|
215
|
+
confidence: Math.round(highestConfidence * 100) / 100,
|
|
216
|
+
matchField,
|
|
217
|
+
action,
|
|
218
|
+
...(action === 'ManualReview' && {
|
|
219
|
+
warning: `Fuzzy match found (${Math.round(highestConfidence * 100)}% confidence). Manual review recommended.`,
|
|
220
|
+
}),
|
|
221
|
+
}, null, 2);
|
|
222
|
+
}
|
|
223
|
+
// 3. No match found - create new
|
|
224
|
+
return JSON.stringify({
|
|
225
|
+
match: null,
|
|
226
|
+
confidence: 0,
|
|
227
|
+
matchField: 'none',
|
|
228
|
+
action: 'CreateNew',
|
|
229
|
+
}, null, 2);
|
|
230
|
+
}
|
|
231
|
+
// =============================================================================
|
|
232
|
+
// Tool Definitions (for ToolRegistry)
|
|
233
|
+
// =============================================================================
|
|
234
|
+
export const listSitesTool = {
|
|
235
|
+
name: 'list_halopsa_sites',
|
|
236
|
+
description: 'List HaloPSA sites (locations) with caching (5min TTL) and token optimization',
|
|
237
|
+
schema: ListSitesArgsSchema,
|
|
238
|
+
handler: listSites,
|
|
239
|
+
};
|
|
240
|
+
export const getSiteTool = {
|
|
241
|
+
name: 'get_halopsa_site',
|
|
242
|
+
description: 'Get a single HaloPSA site by ID with full details including address',
|
|
243
|
+
schema: GetSiteArgsSchema,
|
|
244
|
+
handler: getSite,
|
|
245
|
+
};
|
|
246
|
+
export const createSiteTool = {
|
|
247
|
+
name: 'create_halopsa_site',
|
|
248
|
+
description: 'Create a new HaloPSA site. Invalidates site cache.',
|
|
249
|
+
schema: CreateSiteArgsSchema,
|
|
250
|
+
handler: createSite,
|
|
251
|
+
};
|
|
252
|
+
export const findSiteMatchTool = {
|
|
253
|
+
name: 'find_halopsa_site_match',
|
|
254
|
+
description: 'Find matching site using fuzzy matching with confidence scoring. Exact name=100%, fuzzy+address=95%, fuzzy only=85%.',
|
|
255
|
+
schema: FindSiteMatchArgsSchema,
|
|
256
|
+
handler: findSiteMatch,
|
|
257
|
+
};
|
|
258
|
+
//# sourceMappingURL=sites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sites.js","sourceRoot":"","sources":["../../src/tools/sites.ts"],"names":[],"mappings":"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"}
|