@wilnertech/halopsa-mcp-server 1.0.2 → 1.2.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.
Files changed (78) hide show
  1. package/.env.example +18 -18
  2. package/LICENSE +21 -21
  3. package/README.md +290 -205
  4. package/dist/api/client.d.ts +7 -2
  5. package/dist/api/client.d.ts.map +1 -1
  6. package/dist/api/client.js +35 -8
  7. package/dist/api/client.js.map +1 -1
  8. package/dist/cache/memory-cache.d.ts +7 -0
  9. package/dist/cache/memory-cache.d.ts.map +1 -1
  10. package/dist/cache/memory-cache.js +7 -0
  11. package/dist/cache/memory-cache.js.map +1 -1
  12. package/dist/cache/prewarm.d.ts +3 -1
  13. package/dist/cache/prewarm.d.ts.map +1 -1
  14. package/dist/cache/prewarm.js +17 -1
  15. package/dist/cache/prewarm.js.map +1 -1
  16. package/dist/schemas/common.d.ts +30 -99
  17. package/dist/schemas/common.d.ts.map +1 -1
  18. package/dist/schemas/common.js +2 -2
  19. package/dist/schemas/common.js.map +1 -1
  20. package/dist/tools/assets.d.ts +87 -297
  21. package/dist/tools/assets.d.ts.map +1 -1
  22. package/dist/tools/assets.js +7 -3
  23. package/dist/tools/assets.js.map +1 -1
  24. package/dist/tools/batch-operations.d.ts +49 -81
  25. package/dist/tools/batch-operations.d.ts.map +1 -1
  26. package/dist/tools/batch-operations.js +62 -0
  27. package/dist/tools/batch-operations.js.map +1 -1
  28. package/dist/tools/clients.d.ts +24 -92
  29. package/dist/tools/clients.d.ts.map +1 -1
  30. package/dist/tools/reference-data.d.ts +44 -72
  31. package/dist/tools/reference-data.d.ts.map +1 -1
  32. package/dist/tools/reference-data.js +27 -0
  33. package/dist/tools/reference-data.js.map +1 -1
  34. package/dist/tools/registrations.d.ts +7 -1
  35. package/dist/tools/registrations.d.ts.map +1 -1
  36. package/dist/tools/registrations.js +43 -7
  37. package/dist/tools/registrations.js.map +1 -1
  38. package/dist/tools/registry.d.ts +12 -5
  39. package/dist/tools/registry.d.ts.map +1 -1
  40. package/dist/tools/registry.js +26 -2
  41. package/dist/tools/registry.js.map +1 -1
  42. package/dist/tools/sites.d.ts +28 -111
  43. package/dist/tools/sites.d.ts.map +1 -1
  44. package/dist/tools/sites.js +4 -2
  45. package/dist/tools/sites.js.map +1 -1
  46. package/dist/tools/ticket-actions.d.ts +50 -0
  47. package/dist/tools/ticket-actions.d.ts.map +1 -0
  48. package/dist/tools/ticket-actions.js +224 -0
  49. package/dist/tools/ticket-actions.js.map +1 -0
  50. package/dist/tools/ticket-custom-fields.d.ts +33 -0
  51. package/dist/tools/ticket-custom-fields.d.ts.map +1 -0
  52. package/dist/tools/ticket-custom-fields.js +155 -0
  53. package/dist/tools/ticket-custom-fields.js.map +1 -0
  54. package/dist/tools/ticket-reference-data.d.ts +88 -0
  55. package/dist/tools/ticket-reference-data.d.ts.map +1 -0
  56. package/dist/tools/ticket-reference-data.js +185 -0
  57. package/dist/tools/ticket-reference-data.js.map +1 -0
  58. package/dist/tools/tickets.d.ts +190 -0
  59. package/dist/tools/tickets.d.ts.map +1 -0
  60. package/dist/tools/tickets.js +592 -0
  61. package/dist/tools/tickets.js.map +1 -0
  62. package/dist/tools/users.d.ts +55 -193
  63. package/dist/tools/users.d.ts.map +1 -1
  64. package/dist/tools/users.js +7 -3
  65. package/dist/tools/users.js.map +1 -1
  66. package/dist/types/tickets.d.ts +193 -0
  67. package/dist/types/tickets.d.ts.map +1 -0
  68. package/dist/types/tickets.js +14 -0
  69. package/dist/types/tickets.js.map +1 -0
  70. package/dist/utils/formatter.d.ts +34 -1
  71. package/dist/utils/formatter.d.ts.map +1 -1
  72. package/dist/utils/formatter.js +203 -6
  73. package/dist/utils/formatter.js.map +1 -1
  74. package/package.json +68 -61
  75. package/dist/utils/zod-to-schema.d.ts +0 -29
  76. package/dist/utils/zod-to-schema.d.ts.map +0 -1
  77. package/dist/utils/zod-to-schema.js +0 -182
  78. package/dist/utils/zod-to-schema.js.map +0 -1
@@ -0,0 +1,224 @@
1
+ /**
2
+ * HaloPSA Ticket Action tools.
3
+ *
4
+ * Actions are the journal entries on a ticket — notes, email replies,
5
+ * status changes, time entries, etc. Halo's create endpoint is
6
+ * `POST /api/Actions` with an **array body** (mirrors Tickets/Asset
7
+ * convention). The list endpoint is `GET /api/Actions?ticket_id={id}`.
8
+ *
9
+ * The list response is cached briefly (1min) because action lists update
10
+ * any time someone touches the ticket; staleness > 1min would mislead
11
+ * agents reading the journal.
12
+ */
13
+ import { z } from 'zod';
14
+ import { HaloPSAError } from '../api/errors.js';
15
+ import { formatResponse, stripWriteResponse } from '../utils/formatter.js';
16
+ import { TTL } from '../cache/memory-cache.js';
17
+ import { FormatOptionsSchema } from '../schemas/common.js';
18
+ // =============================================================================
19
+ // Schemas
20
+ // =============================================================================
21
+ export const AddTicketActionArgsSchema = z.object({
22
+ ticket_id: z.number().int()
23
+ .describe('HaloPSA ticket ID to attach the action to'),
24
+ note: z.string().min(1)
25
+ .describe('Note body (plain text or HTML)'),
26
+ outcome_id: z.number().int().optional()
27
+ .describe('Outcome enum ID (Public Note, Private Note, Email Reply, etc.). Halo REQUIRES this on most tenants — without it, POST /Actions returns 400 "An Outcome must be entered for this Action". Look up valid outcomes for your agent in Halo admin → Configuration → Tickets → Outcomes.'),
28
+ email_reply: z.boolean().optional()
29
+ .describe('If true, sends the note as an email reply to the ticket requester'),
30
+ hiddenfromuser: z.boolean().optional()
31
+ .describe('If true, hides the action from the customer portal'),
32
+ format_options: FormatOptionsSchema,
33
+ });
34
+ export const ListTicketActionsArgsSchema = z.object({
35
+ ticket_id: z.number().int()
36
+ .describe('Filter actions to a single ticket'),
37
+ count: z.number().int().min(1).max(100).optional()
38
+ .describe('Results per page (max 100)'),
39
+ page_no: z.number().int().min(1).optional()
40
+ .describe('Page number (1-indexed)'),
41
+ format_options: FormatOptionsSchema,
42
+ });
43
+ // =============================================================================
44
+ // Helpers
45
+ // =============================================================================
46
+ const ACTION_PREVIEW_LEN = 200;
47
+ /**
48
+ * Regex to detect Halo 400 messages that indicate a missing or invalid
49
+ * outcome_id — covers both "An Outcome must be entered for this Action"
50
+ * and "You do not have access to this Action at the moment."
51
+ */
52
+ const OUTCOME_ERROR_RE = /Outcome must be entered|access to this Action/i;
53
+ /**
54
+ * Scan an arbitrary object for any key whose name contains "outcome"
55
+ * (case-insensitive) and whose value is an array. Returns that array,
56
+ * or an empty array if nothing is found.
57
+ */
58
+ function extractOutcomeHint(obj) {
59
+ for (const key of Object.keys(obj)) {
60
+ if (/outcome/i.test(key)) {
61
+ const val = obj[key];
62
+ if (Array.isArray(val)) {
63
+ return val;
64
+ }
65
+ }
66
+ }
67
+ return [];
68
+ }
69
+ /**
70
+ * When POST /Actions returns a 400 matching the outcome-required pattern,
71
+ * fetch the parent ticket and its tickettype config, then return a structured
72
+ * "refusal" object (not a thrown error) so the caller sees discovery info.
73
+ */
74
+ async function buildOutcomeDiscoveryRefusal(client, ticketId, haloError) {
75
+ const discoveryWarnings = [];
76
+ // --- Step 1: fetch the parent ticket ---
77
+ let tickettypeId;
78
+ let tickettypeName;
79
+ try {
80
+ const ticket = await client.get(`/Tickets/${ticketId}`, { includedetails: true });
81
+ tickettypeId = ticket.tickettype_id;
82
+ tickettypeName = ticket.tickettype_name;
83
+ }
84
+ catch (innerErr) {
85
+ const msg = innerErr instanceof Error ? innerErr.message : String(innerErr);
86
+ discoveryWarnings.push('ticket lookup failed: ' + msg);
87
+ return {
88
+ action_created: false,
89
+ halo_error: haloError,
90
+ diagnosis: 'outcome_id is required for this tickettype and was either missing or invalid',
91
+ tickettype_id: null,
92
+ tickettype_name: null,
93
+ valid_outcomes_hint: [],
94
+ discovery_warning: discoveryWarnings.join('; '),
95
+ remediation: 'Either retry with a valid outcome_id (check Halo admin: Configuration > Tickets > Outcomes), ' +
96
+ 'or fall back to update_halopsa_ticket to set details_html / status_id without going through the Actions surface.',
97
+ };
98
+ }
99
+ // --- Step 2: fetch the tickettype config ---
100
+ let validOutcomesHint = [];
101
+ if (tickettypeId !== undefined) {
102
+ try {
103
+ const ttConfig = await client.get(`/TicketType/${tickettypeId}`, { includedetails: true });
104
+ validOutcomesHint = extractOutcomeHint(ttConfig);
105
+ }
106
+ catch (innerErr) {
107
+ const msg = innerErr instanceof Error ? innerErr.message : String(innerErr);
108
+ discoveryWarnings.push('tickettype lookup failed: ' + msg);
109
+ }
110
+ }
111
+ const result = {
112
+ action_created: false,
113
+ halo_error: haloError,
114
+ diagnosis: 'outcome_id is required for this tickettype and was either missing or invalid',
115
+ tickettype_id: tickettypeId ?? null,
116
+ tickettype_name: tickettypeName ?? null,
117
+ valid_outcomes_hint: validOutcomesHint,
118
+ remediation: 'Either retry with a valid outcome_id from the list above, ' +
119
+ 'or fall back to update_halopsa_ticket to set details_html / status_id without going through the Actions surface.',
120
+ };
121
+ if (discoveryWarnings.length > 0) {
122
+ result['discovery_warning'] = discoveryWarnings.join('; ');
123
+ }
124
+ return result;
125
+ }
126
+ /**
127
+ * Compact action shape — id/who/datetime/outcome plus a `note_preview`
128
+ * truncated to 200 chars so list responses stay LLM-friendly.
129
+ */
130
+ function compactAction(action) {
131
+ const note = action.note ?? action.note_html ?? '';
132
+ return {
133
+ id: action.id,
134
+ ticket_id: action.ticket_id,
135
+ who: action.who,
136
+ datetime: action.datetime,
137
+ outcome: action.outcome,
138
+ note_preview: note.length > ACTION_PREVIEW_LEN
139
+ ? note.slice(0, ACTION_PREVIEW_LEN) + '…'
140
+ : note,
141
+ };
142
+ }
143
+ function unwrapActionList(response) {
144
+ if (Array.isArray(response)) {
145
+ return { actions: response, record_count: response.length };
146
+ }
147
+ return {
148
+ actions: response.actions ?? [],
149
+ record_count: response.record_count ?? response.actions?.length ?? 0,
150
+ };
151
+ }
152
+ // =============================================================================
153
+ // Implementations
154
+ // =============================================================================
155
+ export async function addTicketAction(client, args) {
156
+ const payload = {
157
+ ticket_id: args.ticket_id,
158
+ note: args.note,
159
+ };
160
+ if (args.outcome_id !== undefined)
161
+ payload.outcome_id = args.outcome_id;
162
+ if (args.email_reply !== undefined)
163
+ payload.email_reply = args.email_reply;
164
+ if (args.hiddenfromuser !== undefined)
165
+ payload.hiddenfromuser = args.hiddenfromuser;
166
+ // Halo's array-body write may return `[{...}]` or `{...}` depending on
167
+ // tenant — normalize to a single object before formatting.
168
+ let raw;
169
+ try {
170
+ raw = await client.post('/Actions', [payload]);
171
+ }
172
+ catch (error) {
173
+ // When Halo returns 400 for a missing or invalid outcome_id, surface a
174
+ // structured refusal with discovery info instead of re-throwing the raw
175
+ // error. This lets the caller retry with a valid outcome_id.
176
+ const haloMessage = error instanceof HaloPSAError ? error.message : String(error);
177
+ if (OUTCOME_ERROR_RE.test(haloMessage)) {
178
+ const refusal = await buildOutcomeDiscoveryRefusal(client, args.ticket_id, haloMessage);
179
+ return JSON.stringify(refusal);
180
+ }
181
+ throw error;
182
+ }
183
+ const created = Array.isArray(raw) ? raw[0] : raw;
184
+ client.invalidateCache(`ticket-actions:${args.ticket_id}*`);
185
+ client.invalidateCache(`ticket:${args.ticket_id}*`);
186
+ const format = args.format_options?.format ?? 'compact';
187
+ return formatResponse(stripWriteResponse(created, format, 'action'), { format });
188
+ }
189
+ export async function listTicketActions(client, args) {
190
+ const params = { ticket_id: args.ticket_id };
191
+ if (args.count !== undefined)
192
+ params.count = args.count;
193
+ if (args.page_no !== undefined)
194
+ params.page_no = args.page_no;
195
+ const formatOpts = args.format_options || { format: 'compact' };
196
+ const response = await client.getCached('/Actions', params, {
197
+ enabled: true,
198
+ ttl: TTL.TICKET_ACTION_LIST,
199
+ keyPrefix: `ticket-actions:${args.ticket_id}`,
200
+ });
201
+ const { actions, record_count } = unwrapActionList(response);
202
+ // Compact mode: substitute the preview-shaped objects so the response
203
+ // never echoes back full HTML bodies on a journal listing.
204
+ const items = formatOpts.format === 'compact'
205
+ ? actions.map(compactAction)
206
+ : actions;
207
+ return formatResponse(items, formatOpts, { record_count });
208
+ }
209
+ // =============================================================================
210
+ // Tool Definitions
211
+ // =============================================================================
212
+ export const addTicketActionTool = {
213
+ name: 'add_halopsa_ticket_action',
214
+ description: 'Append an action (note, email reply, status change journal entry) to a HaloPSA ticket. POST /Actions with array body wrapper. Invalidates ticket and action caches.',
215
+ schema: AddTicketActionArgsSchema,
216
+ handler: addTicketAction,
217
+ };
218
+ export const listTicketActionsTool = {
219
+ name: 'list_halopsa_ticket_actions',
220
+ description: 'List actions/journal entries on a HaloPSA ticket. Compact response includes a 200-char note_preview; pass format_options.format="detailed" for full notes. Cached 1min.',
221
+ schema: ListTicketActionsArgsSchema,
222
+ handler: listTicketActions,
223
+ };
224
+ //# sourceMappingURL=ticket-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-actions.js","sourceRoot":"","sources":["../../src/tools/ticket-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * HaloPSA Ticket Custom Field tools.
3
+ *
4
+ * Two complementary inspection paths:
5
+ * 1. `list_halopsa_ticket_custom_fields` — preferred. Calls
6
+ * GET /api/FieldInfo?type=1&tickettype_id={id}. If the tenant
7
+ * returns a non-empty field list, that's the canonical schema.
8
+ * 2. `get_halopsa_ticket_field_schema` — fallback. Samples N recent
9
+ * tickets of a given type and derives field shape from their
10
+ * `customfields[]` arrays. Mirrors `getAssetFieldSchemaTool`.
11
+ *
12
+ * The dual approach exists because Halo's `/FieldInfo` endpoint behaves
13
+ * inconsistently across tenants — some installs gate it behind admin
14
+ * scope, others return empty arrays for non-admin agents. The sampling
15
+ * path is robust but lossy (only fields that ARE used on existing
16
+ * tickets show up).
17
+ */
18
+ import { z } from 'zod';
19
+ import type { HaloPSAAPIClient } from '../api/client.js';
20
+ import type { ZodToolDefinition } from './registry.js';
21
+ export declare const ListTicketCustomFieldsArgsSchema: z.ZodObject<{
22
+ tickettype_id: z.ZodNumber;
23
+ }, z.core.$strip>;
24
+ export declare const GetTicketFieldSchemaArgsSchema: z.ZodObject<{
25
+ tickettype_id: z.ZodNumber;
26
+ client_id: z.ZodOptional<z.ZodNumber>;
27
+ sample_size: z.ZodOptional<z.ZodNumber>;
28
+ }, z.core.$strip>;
29
+ export declare function listTicketCustomFields(client: HaloPSAAPIClient, args: z.infer<typeof ListTicketCustomFieldsArgsSchema>): Promise<string>;
30
+ export declare function getTicketFieldSchema(client: HaloPSAAPIClient, args: z.infer<typeof GetTicketFieldSchemaArgsSchema>): Promise<string>;
31
+ export declare const listTicketCustomFieldsTool: ZodToolDefinition;
32
+ export declare const getTicketFieldSchemaTool: ZodToolDefinition;
33
+ //# sourceMappingURL=ticket-custom-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-custom-fields.d.ts","sourceRoot":"","sources":["../../src/tools/ticket-custom-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;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;AAWvD,eAAO,MAAM,gCAAgC;;iBAG3C,CAAC;AAEH,eAAO,MAAM,8BAA8B;;;;iBAOzC,CAAC;AAgDH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,GACrD,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GACnD,OAAO,CAAC,MAAM,CAAC,CAyDjB;AAMD,eAAO,MAAM,0BAA0B,EAAE,iBAKxC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,iBAKtC,CAAC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * HaloPSA Ticket Custom Field tools.
3
+ *
4
+ * Two complementary inspection paths:
5
+ * 1. `list_halopsa_ticket_custom_fields` — preferred. Calls
6
+ * GET /api/FieldInfo?type=1&tickettype_id={id}. If the tenant
7
+ * returns a non-empty field list, that's the canonical schema.
8
+ * 2. `get_halopsa_ticket_field_schema` — fallback. Samples N recent
9
+ * tickets of a given type and derives field shape from their
10
+ * `customfields[]` arrays. Mirrors `getAssetFieldSchemaTool`.
11
+ *
12
+ * The dual approach exists because Halo's `/FieldInfo` endpoint behaves
13
+ * inconsistently across tenants — some installs gate it behind admin
14
+ * scope, others return empty arrays for non-admin agents. The sampling
15
+ * path is robust but lossy (only fields that ARE used on existing
16
+ * tickets show up).
17
+ */
18
+ import { z } from 'zod';
19
+ // =============================================================================
20
+ // Schemas
21
+ // =============================================================================
22
+ // These tools return purpose-built analysis objects (field schema summaries,
23
+ // not raw HaloPSA records) so they intentionally do NOT accept format_options
24
+ // — the response shape is fixed.
25
+ export const ListTicketCustomFieldsArgsSchema = z.object({
26
+ tickettype_id: z.number().int()
27
+ .describe('Ticket type ID — schema is per-tickettype'),
28
+ });
29
+ export const GetTicketFieldSchemaArgsSchema = z.object({
30
+ tickettype_id: z.number().int()
31
+ .describe('Ticket type ID — sampling is scoped to this type'),
32
+ client_id: z.number().int().optional()
33
+ .describe('Optional client filter — narrows the sample further'),
34
+ sample_size: z.number().int().min(1).max(100).optional()
35
+ .describe('Number of tickets to inspect (default 50)'),
36
+ });
37
+ // =============================================================================
38
+ // Helpers
39
+ // =============================================================================
40
+ function getValueType(value) {
41
+ if (value === null || value === undefined)
42
+ return 'null';
43
+ if (typeof value === 'string')
44
+ return 'string';
45
+ if (typeof value === 'number')
46
+ return 'number';
47
+ if (typeof value === 'boolean')
48
+ return 'boolean';
49
+ return 'mixed';
50
+ }
51
+ function unwrapList(response, preferredKey) {
52
+ if (Array.isArray(response))
53
+ return response;
54
+ const wrapped = response;
55
+ return wrapped[preferredKey] ?? [];
56
+ }
57
+ // =============================================================================
58
+ // Implementations
59
+ // =============================================================================
60
+ export async function listTicketCustomFields(client, args) {
61
+ // Halo type=1 means ticket fields per the FieldInfo endpoint convention.
62
+ let fields = [];
63
+ let source = 'empty';
64
+ let warning;
65
+ try {
66
+ const response = await client.get('/FieldInfo', { type: 1, tickettype_id: args.tickettype_id });
67
+ fields = unwrapList(response, 'fields');
68
+ if (fields.length > 0) {
69
+ source = 'fieldinfo';
70
+ }
71
+ }
72
+ catch (err) {
73
+ warning = `FieldInfo endpoint failed: ${err instanceof Error ? err.message : String(err)}. ` +
74
+ 'Use get_halopsa_ticket_field_schema for sampling-based schema discovery.';
75
+ }
76
+ const result = {
77
+ tickettype_id: args.tickettype_id,
78
+ source,
79
+ field_count: fields.length,
80
+ fields: fields.map((f) => ({
81
+ id: f.id ?? f.field_id,
82
+ name: f.name ?? f.label,
83
+ type: f.type,
84
+ required: f.required ?? false,
85
+ display_order: f.display_order,
86
+ })),
87
+ ...(warning && { warning }),
88
+ };
89
+ return JSON.stringify(result, null, 2);
90
+ }
91
+ export async function getTicketFieldSchema(client, args) {
92
+ const sampleSize = args.sample_size ?? 50;
93
+ const params = {
94
+ tickettype_id: args.tickettype_id,
95
+ count: sampleSize,
96
+ };
97
+ if (args.client_id !== undefined)
98
+ params.client_id = args.client_id;
99
+ const response = await client.get('/Tickets', params);
100
+ const tickets = Array.isArray(response)
101
+ ? response
102
+ : (response.tickets ?? []);
103
+ const fieldMap = new Map();
104
+ for (const ticket of tickets) {
105
+ const customfields = ticket.customfields ?? [];
106
+ for (const field of customfields) {
107
+ const existing = fieldMap.get(field.id);
108
+ const valueType = getValueType(field.value);
109
+ if (existing) {
110
+ if (existing.sample_values.length < 5 &&
111
+ !existing.sample_values.includes(field.value)) {
112
+ existing.sample_values.push(field.value);
113
+ }
114
+ existing.usage_count++;
115
+ if (existing.value_type !== valueType && existing.value_type !== 'mixed') {
116
+ existing.value_type = 'mixed';
117
+ }
118
+ }
119
+ else {
120
+ fieldMap.set(field.id, {
121
+ field_id: field.id,
122
+ name: field.name,
123
+ sample_values: [field.value],
124
+ value_type: valueType,
125
+ usage_count: 1,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ const fieldSchemas = Array.from(fieldMap.values()).sort((a, b) => a.field_id - b.field_id);
131
+ const result = {
132
+ tickettype_id: args.tickettype_id,
133
+ client_id: args.client_id ?? 'all',
134
+ tickets_analyzed: tickets.length,
135
+ unique_fields: fieldSchemas.length,
136
+ field_schemas: fieldSchemas,
137
+ };
138
+ return JSON.stringify(result, null, 2);
139
+ }
140
+ // =============================================================================
141
+ // Tool Definitions
142
+ // =============================================================================
143
+ export const listTicketCustomFieldsTool = {
144
+ name: 'list_halopsa_ticket_custom_fields',
145
+ description: 'List custom-field definitions for a ticket type via /FieldInfo. Falls back gracefully with a warning if the endpoint is empty/unauthorized — use get_halopsa_ticket_field_schema then.',
146
+ schema: ListTicketCustomFieldsArgsSchema,
147
+ handler: listTicketCustomFields,
148
+ };
149
+ export const getTicketFieldSchemaTool = {
150
+ name: 'get_halopsa_ticket_field_schema',
151
+ description: 'Sample N recent tickets of a given type and derive custom-field schema from their customfields[] arrays. Use when /FieldInfo is unavailable. Returns field_id, name, sample_values, value_type, usage_count per field.',
152
+ schema: GetTicketFieldSchemaArgsSchema,
153
+ handler: getTicketFieldSchema,
154
+ };
155
+ //# sourceMappingURL=ticket-custom-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-custom-fields.js","sourceRoot":"","sources":["../../src/tools/ticket-custom-fields.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * HaloPSA Ticket Reference Data tools.
3
+ *
4
+ * Mirrors the existing pattern in `src/tools/reference-data.ts` for asset
5
+ * reference data. All five tools default to compact responses (token
6
+ * optimization) and use 1-hour cache TTLs because reference data on a
7
+ * Halo tenant changes infrequently — most reads should hit cache.
8
+ *
9
+ * The tools deliberately accept BOTH a `full` boolean shortcut AND the
10
+ * standard `format_options` block so callers can choose their style:
11
+ * `{ full: true }` is the path-of-least-surprise for ad-hoc lookups,
12
+ * while `format_options` keeps parity with the rest of the MCP surface.
13
+ */
14
+ import { z } from 'zod';
15
+ import type { HaloPSAAPIClient } from '../api/client.js';
16
+ import type { ZodToolDefinition } from './registry.js';
17
+ declare const ListTicketTypesArgsSchema: z.ZodObject<{
18
+ full: z.ZodOptional<z.ZodBoolean>;
19
+ format_options: z.ZodOptional<z.ZodObject<{
20
+ format: z.ZodOptional<z.ZodEnum<{
21
+ compact: "compact";
22
+ standard: "standard";
23
+ detailed: "detailed";
24
+ }>>;
25
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
+ omit_empty: z.ZodOptional<z.ZodBoolean>;
27
+ }, z.core.$strip>>;
28
+ }, z.core.$strip>;
29
+ declare const GetTicketTypeArgsSchema: z.ZodObject<{
30
+ tickettype_id: z.ZodNumber;
31
+ format_options: z.ZodOptional<z.ZodObject<{
32
+ format: z.ZodOptional<z.ZodEnum<{
33
+ compact: "compact";
34
+ standard: "standard";
35
+ detailed: "detailed";
36
+ }>>;
37
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
38
+ omit_empty: z.ZodOptional<z.ZodBoolean>;
39
+ }, z.core.$strip>>;
40
+ }, z.core.$strip>;
41
+ declare const ListTicketStatusesArgsSchema: z.ZodObject<{
42
+ full: z.ZodOptional<z.ZodBoolean>;
43
+ format_options: z.ZodOptional<z.ZodObject<{
44
+ format: z.ZodOptional<z.ZodEnum<{
45
+ compact: "compact";
46
+ standard: "standard";
47
+ detailed: "detailed";
48
+ }>>;
49
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
+ omit_empty: z.ZodOptional<z.ZodBoolean>;
51
+ }, z.core.$strip>>;
52
+ }, z.core.$strip>;
53
+ declare const ListTicketPrioritiesArgsSchema: z.ZodObject<{
54
+ full: z.ZodOptional<z.ZodBoolean>;
55
+ format_options: z.ZodOptional<z.ZodObject<{
56
+ format: z.ZodOptional<z.ZodEnum<{
57
+ compact: "compact";
58
+ standard: "standard";
59
+ detailed: "detailed";
60
+ }>>;
61
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
+ omit_empty: z.ZodOptional<z.ZodBoolean>;
63
+ }, z.core.$strip>>;
64
+ }, z.core.$strip>;
65
+ declare const ListTicketCategoriesArgsSchema: z.ZodObject<{
66
+ full: z.ZodOptional<z.ZodBoolean>;
67
+ format_options: z.ZodOptional<z.ZodObject<{
68
+ format: z.ZodOptional<z.ZodEnum<{
69
+ compact: "compact";
70
+ standard: "standard";
71
+ detailed: "detailed";
72
+ }>>;
73
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
74
+ omit_empty: z.ZodOptional<z.ZodBoolean>;
75
+ }, z.core.$strip>>;
76
+ }, z.core.$strip>;
77
+ export declare function listTicketTypes(client: HaloPSAAPIClient, args: z.infer<typeof ListTicketTypesArgsSchema>): Promise<string>;
78
+ export declare function getTicketType(client: HaloPSAAPIClient, args: z.infer<typeof GetTicketTypeArgsSchema>): Promise<string>;
79
+ export declare function listTicketStatuses(client: HaloPSAAPIClient, args: z.infer<typeof ListTicketStatusesArgsSchema>): Promise<string>;
80
+ export declare function listTicketPriorities(client: HaloPSAAPIClient, args: z.infer<typeof ListTicketPrioritiesArgsSchema>): Promise<string>;
81
+ export declare function listTicketCategories(client: HaloPSAAPIClient, args: z.infer<typeof ListTicketCategoriesArgsSchema>): Promise<string>;
82
+ export declare const listTicketTypesTool: ZodToolDefinition;
83
+ export declare const getTicketTypeTool: ZodToolDefinition;
84
+ export declare const listTicketStatusesTool: ZodToolDefinition;
85
+ export declare const listTicketPrioritiesTool: ZodToolDefinition;
86
+ export declare const listTicketCategoriesTool: ZodToolDefinition;
87
+ export {};
88
+ //# sourceMappingURL=ticket-reference-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-reference-data.d.ts","sourceRoot":"","sources":["../../src/tools/ticket-reference-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;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;AAoBvD,QAAA,MAAM,yBAAyB;;;;;;;;;;;iBAI7B,CAAC;AAEH,QAAA,MAAM,uBAAuB;;;;;;;;;;;iBAI3B,CAAC;AAEH,QAAA,MAAM,4BAA4B;;;;;;;;;;;iBAIhC,CAAC;AAEH,QAAA,MAAM,8BAA8B;;;;;;;;;;;iBAIlC,CAAC;AAEH,QAAA,MAAM,8BAA8B;;;;;;;;;;;iBAIlC,CAAC;AAqEH,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,GAC9C,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,GACjD,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GACnD,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GACnD,OAAO,CAAC,MAAM,CAAC,CAejB;AAMD,eAAO,MAAM,mBAAmB,EAAE,iBAKjC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,iBAKpC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,iBAKtC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,iBAKtC,CAAC"}