@goxtechnologies/connectwise-psa-mcp 1.1.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 (147) hide show
  1. package/data/connectwise_api.db +0 -0
  2. package/data/manage.json +298179 -0
  3. package/dist/index.d.ts +10 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +116 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/operations/analytics-extended.d.ts +6 -0
  8. package/dist/operations/analytics-extended.d.ts.map +1 -0
  9. package/dist/operations/analytics-extended.js +825 -0
  10. package/dist/operations/analytics-extended.js.map +1 -0
  11. package/dist/operations/analytics-msp-assets.d.ts +3 -0
  12. package/dist/operations/analytics-msp-assets.d.ts.map +1 -0
  13. package/dist/operations/analytics-msp-assets.js +180 -0
  14. package/dist/operations/analytics-msp-assets.js.map +1 -0
  15. package/dist/operations/analytics-msp-clients.d.ts +3 -0
  16. package/dist/operations/analytics-msp-clients.d.ts.map +1 -0
  17. package/dist/operations/analytics-msp-clients.js +198 -0
  18. package/dist/operations/analytics-msp-clients.js.map +1 -0
  19. package/dist/operations/analytics-msp-comms.d.ts +3 -0
  20. package/dist/operations/analytics-msp-comms.d.ts.map +1 -0
  21. package/dist/operations/analytics-msp-comms.js +127 -0
  22. package/dist/operations/analytics-msp-comms.js.map +1 -0
  23. package/dist/operations/analytics-msp-contracts.d.ts +3 -0
  24. package/dist/operations/analytics-msp-contracts.d.ts.map +1 -0
  25. package/dist/operations/analytics-msp-contracts.js +91 -0
  26. package/dist/operations/analytics-msp-contracts.js.map +1 -0
  27. package/dist/operations/analytics-msp-financial.d.ts +3 -0
  28. package/dist/operations/analytics-msp-financial.d.ts.map +1 -0
  29. package/dist/operations/analytics-msp-financial.js +300 -0
  30. package/dist/operations/analytics-msp-financial.js.map +1 -0
  31. package/dist/operations/analytics-msp-procurement.d.ts +3 -0
  32. package/dist/operations/analytics-msp-procurement.d.ts.map +1 -0
  33. package/dist/operations/analytics-msp-procurement.js +78 -0
  34. package/dist/operations/analytics-msp-procurement.js.map +1 -0
  35. package/dist/operations/analytics-msp-projects.d.ts +3 -0
  36. package/dist/operations/analytics-msp-projects.d.ts.map +1 -0
  37. package/dist/operations/analytics-msp-projects.js +190 -0
  38. package/dist/operations/analytics-msp-projects.js.map +1 -0
  39. package/dist/operations/analytics-msp-sales.d.ts +3 -0
  40. package/dist/operations/analytics-msp-sales.d.ts.map +1 -0
  41. package/dist/operations/analytics-msp-sales.js +99 -0
  42. package/dist/operations/analytics-msp-sales.js.map +1 -0
  43. package/dist/operations/analytics-msp-schedule.d.ts +3 -0
  44. package/dist/operations/analytics-msp-schedule.d.ts.map +1 -0
  45. package/dist/operations/analytics-msp-schedule.js +339 -0
  46. package/dist/operations/analytics-msp-schedule.js.map +1 -0
  47. package/dist/operations/analytics-msp-team.d.ts +3 -0
  48. package/dist/operations/analytics-msp-team.d.ts.map +1 -0
  49. package/dist/operations/analytics-msp-team.js +195 -0
  50. package/dist/operations/analytics-msp-team.js.map +1 -0
  51. package/dist/operations/analytics-msp-tickets.d.ts +3 -0
  52. package/dist/operations/analytics-msp-tickets.d.ts.map +1 -0
  53. package/dist/operations/analytics-msp-tickets.js +578 -0
  54. package/dist/operations/analytics-msp-tickets.js.map +1 -0
  55. package/dist/operations/analytics-msp-time.d.ts +3 -0
  56. package/dist/operations/analytics-msp-time.d.ts.map +1 -0
  57. package/dist/operations/analytics-msp-time.js +485 -0
  58. package/dist/operations/analytics-msp-time.js.map +1 -0
  59. package/dist/operations/analytics-msp-utils.d.ts +49 -0
  60. package/dist/operations/analytics-msp-utils.d.ts.map +1 -0
  61. package/dist/operations/analytics-msp-utils.js +157 -0
  62. package/dist/operations/analytics-msp-utils.js.map +1 -0
  63. package/dist/operations/analytics.d.ts +9 -0
  64. package/dist/operations/analytics.d.ts.map +1 -0
  65. package/dist/operations/analytics.js +742 -0
  66. package/dist/operations/analytics.js.map +1 -0
  67. package/dist/operations/executor.d.ts +10 -0
  68. package/dist/operations/executor.d.ts.map +1 -0
  69. package/dist/operations/executor.js +243 -0
  70. package/dist/operations/executor.js.map +1 -0
  71. package/dist/operations/registry.d.ts +16 -0
  72. package/dist/operations/registry.d.ts.map +1 -0
  73. package/dist/operations/registry.js +847 -0
  74. package/dist/operations/registry.js.map +1 -0
  75. package/dist/services/api-database.d.ts +38 -0
  76. package/dist/services/api-database.d.ts.map +1 -0
  77. package/dist/services/api-database.js +191 -0
  78. package/dist/services/api-database.js.map +1 -0
  79. package/dist/services/cache.d.ts +12 -0
  80. package/dist/services/cache.d.ts.map +1 -0
  81. package/dist/services/cache.js +32 -0
  82. package/dist/services/cache.js.map +1 -0
  83. package/dist/services/connectwise-api.d.ts +43 -0
  84. package/dist/services/connectwise-api.d.ts.map +1 -0
  85. package/dist/services/connectwise-api.js +198 -0
  86. package/dist/services/connectwise-api.js.map +1 -0
  87. package/dist/services/db-builder.d.ts +11 -0
  88. package/dist/services/db-builder.d.ts.map +1 -0
  89. package/dist/services/db-builder.js +237 -0
  90. package/dist/services/db-builder.js.map +1 -0
  91. package/dist/services/fast-memory.d.ts +39 -0
  92. package/dist/services/fast-memory.d.ts.map +1 -0
  93. package/dist/services/fast-memory.js +147 -0
  94. package/dist/services/fast-memory.js.map +1 -0
  95. package/dist/services/load-env.d.ts +15 -0
  96. package/dist/services/load-env.d.ts.map +1 -0
  97. package/dist/services/load-env.js +59 -0
  98. package/dist/services/load-env.js.map +1 -0
  99. package/dist/tools/batch.d.ts +9 -0
  100. package/dist/tools/batch.d.ts.map +1 -0
  101. package/dist/tools/batch.js +159 -0
  102. package/dist/tools/batch.js.map +1 -0
  103. package/dist/tools/composite.d.ts +9 -0
  104. package/dist/tools/composite.d.ts.map +1 -0
  105. package/dist/tools/composite.js +353 -0
  106. package/dist/tools/composite.js.map +1 -0
  107. package/dist/tools/discovery.d.ts +9 -0
  108. package/dist/tools/discovery.d.ts.map +1 -0
  109. package/dist/tools/discovery.js +245 -0
  110. package/dist/tools/discovery.js.map +1 -0
  111. package/dist/tools/execution.d.ts +9 -0
  112. package/dist/tools/execution.d.ts.map +1 -0
  113. package/dist/tools/execution.js +130 -0
  114. package/dist/tools/execution.js.map +1 -0
  115. package/dist/tools/memory.d.ts +9 -0
  116. package/dist/tools/memory.d.ts.map +1 -0
  117. package/dist/tools/memory.js +152 -0
  118. package/dist/tools/memory.js.map +1 -0
  119. package/dist/tools/operations.d.ts +9 -0
  120. package/dist/tools/operations.d.ts.map +1 -0
  121. package/dist/tools/operations.js +214 -0
  122. package/dist/tools/operations.js.map +1 -0
  123. package/dist/tools/pagination.d.ts +9 -0
  124. package/dist/tools/pagination.d.ts.map +1 -0
  125. package/dist/tools/pagination.js +133 -0
  126. package/dist/tools/pagination.js.map +1 -0
  127. package/dist/tools/validation.d.ts +9 -0
  128. package/dist/tools/validation.d.ts.map +1 -0
  129. package/dist/tools/validation.js +705 -0
  130. package/dist/tools/validation.js.map +1 -0
  131. package/dist/types/index.d.ts +145 -0
  132. package/dist/types/index.d.ts.map +1 -0
  133. package/dist/types/index.js +3 -0
  134. package/dist/types/index.js.map +1 -0
  135. package/dist/types/operations.d.ts +30 -0
  136. package/dist/types/operations.d.ts.map +1 -0
  137. package/dist/types/operations.js +3 -0
  138. package/dist/types/operations.js.map +1 -0
  139. package/dist/utils/conditions.d.ts +20 -0
  140. package/dist/utils/conditions.d.ts.map +1 -0
  141. package/dist/utils/conditions.js +78 -0
  142. package/dist/utils/conditions.js.map +1 -0
  143. package/dist/utils/formatters.d.ts +35 -0
  144. package/dist/utils/formatters.d.ts.map +1 -0
  145. package/dist/utils/formatters.js +337 -0
  146. package/dist/utils/formatters.js.map +1 -0
  147. package/package.json +46 -0
@@ -0,0 +1,339 @@
1
+ // ConnectWise PSA MCP Server — MSP Analytics: Schedule & Capacity (5 handlers)
2
+ import { getAPI } from '../services/connectwise-api.js';
3
+ import { num, nested, daysAgo, round2, groupByDate, pct, hoursDisplay, mdTable, weekdaysBetween, } from './analytics-msp-utils.js';
4
+ // ---------------------------------------------------------------------------
5
+ // Handler registry
6
+ // ---------------------------------------------------------------------------
7
+ export const mspScheduleHandlers = {};
8
+ function reg(name, handler) {
9
+ mspScheduleHandlers[name] = handler;
10
+ }
11
+ // ---------------------------------------------------------------------------
12
+ // Internal helpers
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Compute scheduled hours from a schedule entry.
16
+ * All-day entries have dateStart/dateEnd both at 00:00:00 on the same or
17
+ * consecutive day; they are treated as 0h so they don't inflate capacity
18
+ * numbers (ConnectWise uses them as placeholder blocks, not hour-precise work).
19
+ */
20
+ function scheduledHours(entry) {
21
+ const start = String(entry['dateStart'] ?? '');
22
+ const end = String(entry['dateEnd'] ?? '');
23
+ if (!start || !end)
24
+ return 0;
25
+ // All-day items: both timestamps end in T00:00:00Z (or similar midnight)
26
+ const startMidnight = start.includes('T00:00:00');
27
+ const endMidnight = end.includes('T00:00:00');
28
+ if (startMidnight && endMidnight)
29
+ return 0;
30
+ const diffMs = new Date(end).getTime() - new Date(start).getTime();
31
+ if (!Number.isFinite(diffMs) || diffMs <= 0)
32
+ return 0;
33
+ return diffMs / 3_600_000; // ms → hours
34
+ }
35
+ /** Returns the YYYY-MM-DD date string for a date N weekdays ahead of today. */
36
+ function weekdaysAhead(n) {
37
+ const d = new Date();
38
+ let added = 0;
39
+ while (added < n) {
40
+ d.setUTCDate(d.getUTCDate() + 1);
41
+ const day = d.getUTCDay();
42
+ if (day >= 1 && day <= 5)
43
+ added++;
44
+ }
45
+ return d.toISOString().split('T')[0];
46
+ }
47
+ /** ISO timestamp for today's start-of-day (UTC). */
48
+ function todayISO() {
49
+ return new Date().toISOString().split('T')[0] + 'T00:00:00Z';
50
+ }
51
+ /** ISO timestamp for N days from today start-of-day (UTC). */
52
+ function daysFromNow(n) {
53
+ const d = new Date();
54
+ d.setUTCDate(d.getUTCDate() + n);
55
+ return d.toISOString().split('T')[0] + 'T00:00:00Z';
56
+ }
57
+ // ===========================================================================
58
+ // 1. schedule_vs_actual
59
+ // ===========================================================================
60
+ reg('schedule_vs_actual', async (params) => {
61
+ const identifier = String(params['identifier'] ?? '');
62
+ if (!identifier)
63
+ return 'Error: identifier is required.';
64
+ const startRaw = String(params['start_date'] ?? daysAgo(7));
65
+ const endRaw = String(params['end_date'] ?? todayISO());
66
+ // Normalise to YYYY-MM-DD for weekday enumeration
67
+ const startDate = startRaw.substring(0, 10);
68
+ const endDate = endRaw.substring(0, 10);
69
+ const api = getAPI();
70
+ const [schedResult, timeResult] = await Promise.all([
71
+ api.paginatedFetch('/schedule/entries', `member/identifier='${identifier}' AND dateStart>=[${startRaw}] AND dateStart<=[${endRaw}]`, 'id,dateStart,dateEnd,member/identifier', 2000),
72
+ api.paginatedFetch('/time/entries', `member/identifier='${identifier}' AND timeStart>=[${startRaw}] AND timeStart<=[${endRaw}]`, 'id,actualHours,timeStart,member/identifier', 2000),
73
+ ]);
74
+ // Group schedule entries by date
75
+ const schedByDate = groupByDate(schedResult.items, 'dateStart');
76
+ // Group time entries by date (field: timeStart)
77
+ const timeByDate = groupByDate(timeResult.items, 'timeStart');
78
+ const weekdays = weekdaysBetween(startDate, endDate);
79
+ const rows = [];
80
+ let totalSched = 0;
81
+ let totalLogged = 0;
82
+ for (const day of weekdays) {
83
+ const schedEntries = schedByDate.get(day) ?? [];
84
+ const timeEntries = timeByDate.get(day) ?? [];
85
+ const scheduled = schedEntries.reduce((acc, e) => acc + scheduledHours(e), 0);
86
+ const logged = timeEntries.reduce((acc, e) => acc + num(e['actualHours']), 0);
87
+ const delta = round2(logged - scheduled);
88
+ const coverage = pct(logged, scheduled);
89
+ totalSched += scheduled;
90
+ totalLogged += logged;
91
+ rows.push([
92
+ day,
93
+ hoursDisplay(round2(scheduled)),
94
+ hoursDisplay(round2(logged)),
95
+ (delta >= 0 ? '+' : '') + hoursDisplay(delta),
96
+ coverage,
97
+ ]);
98
+ }
99
+ const summary = [
100
+ `## Schedule vs Actual — ${identifier} (${startDate} to ${endDate})`,
101
+ '',
102
+ `**Total Scheduled:** ${hoursDisplay(round2(totalSched))} | **Total Logged:** ${hoursDisplay(round2(totalLogged))} | **Overall Coverage:** ${pct(totalLogged, totalSched)}`,
103
+ '',
104
+ ].join('\n');
105
+ if (rows.length === 0)
106
+ return summary + '_No weekdays in range._';
107
+ return (summary +
108
+ mdTable(['Date', 'Scheduled', 'Logged', 'Delta', 'Coverage %'], rows));
109
+ });
110
+ // ===========================================================================
111
+ // 2. team_capacity_forecast
112
+ // ===========================================================================
113
+ reg('team_capacity_forecast', async (params) => {
114
+ const daysAhead = Math.max(1, num(params['days_ahead'], 7));
115
+ const startISO = todayISO();
116
+ const endISO = daysFromNow(daysAhead);
117
+ const startDate = startISO.substring(0, 10);
118
+ const endDate = endISO.substring(0, 10);
119
+ const api = getAPI();
120
+ const [membersResult, schedResult] = await Promise.all([
121
+ api.paginatedFetch('/system/members', 'inactiveFlag=false', 'id,identifier,firstName,lastName', 500),
122
+ api.paginatedFetch('/schedule/entries', `dateStart>=[${startISO}] AND dateStart<=[${endISO}]`, 'id,dateStart,dateEnd,member/identifier', 5000),
123
+ ]);
124
+ // Available weekday capacity per member: 8h * weekdays in range
125
+ const weekdays = weekdaysBetween(startDate, endDate);
126
+ const totalCapacityHours = 8 * weekdays.length;
127
+ // Accumulate scheduled hours per member identifier
128
+ const scheduledByMember = {};
129
+ for (const entry of schedResult.items) {
130
+ const id = nested(entry, 'member', 'identifier');
131
+ if (id === 'N/A')
132
+ continue;
133
+ scheduledByMember[id] = (scheduledByMember[id] ?? 0) + scheduledHours(entry);
134
+ }
135
+ // Build result rows for members that have data or are active
136
+ const rows = [];
137
+ for (const member of membersResult.items) {
138
+ const id = String(member['identifier'] ?? '');
139
+ const name = `${member['firstName'] ?? ''} ${member['lastName'] ?? ''}`.trim() || id;
140
+ const scheduled = round2(scheduledByMember[id] ?? 0);
141
+ const available = round2(Math.max(0, totalCapacityHours - scheduled));
142
+ const booked = pct(scheduled, totalCapacityHours);
143
+ rows.push([`${name} (${id})`, hoursDisplay(scheduled), hoursDisplay(available), booked]);
144
+ }
145
+ // Sort descending by scheduled hours
146
+ rows.sort((a, b) => parseFloat(b[1]) - parseFloat(a[1]));
147
+ const summary = [
148
+ `## Team Capacity Forecast — Next ${daysAhead} Days (${startDate} to ${endDate})`,
149
+ '',
150
+ `**Weekdays:** ${weekdays.length} | **Capacity per Member:** ${totalCapacityHours}h | **Members:** ${membersResult.items.length}`,
151
+ '',
152
+ ].join('\n');
153
+ if (rows.length === 0)
154
+ return summary + '_No active members found._';
155
+ return (summary +
156
+ mdTable(['Member', 'Scheduled', 'Available', '% Booked'], rows));
157
+ });
158
+ // ===========================================================================
159
+ // 3. overbooked_detection
160
+ // ===========================================================================
161
+ reg('overbooked_detection', async (params) => {
162
+ const daysAhead = Math.max(1, num(params['days_ahead'], 14));
163
+ const startISO = todayISO();
164
+ const endISO = daysFromNow(daysAhead);
165
+ const startDate = startISO.substring(0, 10);
166
+ const endDate = endISO.substring(0, 10);
167
+ const api = getAPI();
168
+ const schedResult = await api.paginatedFetch('/schedule/entries', `dateStart>=[${startISO}] AND dateStart<=[${endISO}]`, 'id,dateStart,dateEnd,member/identifier', 5000);
169
+ // Accumulate hours per member+date
170
+ const buckets = {}; // key: "identifier|YYYY-MM-DD"
171
+ for (const entry of schedResult.items) {
172
+ const id = nested(entry, 'member', 'identifier');
173
+ if (id === 'N/A')
174
+ continue;
175
+ const day = String(entry['dateStart'] ?? '').substring(0, 10);
176
+ if (!day)
177
+ continue;
178
+ const key = `${id}|${day}`;
179
+ buckets[key] = (buckets[key] ?? 0) + scheduledHours(entry);
180
+ }
181
+ const overbooked = Object.entries(buckets)
182
+ .filter(([, h]) => h > 8)
183
+ .map(([key, h]) => {
184
+ const [identifier, date] = key.split('|');
185
+ return { identifier: identifier ?? '', date: date ?? '', hours: round2(h) };
186
+ })
187
+ .sort((a, b) => b.hours - a.hours);
188
+ const summary = [
189
+ `## Overbooked Detection — Next ${daysAhead} Days (${startDate} to ${endDate})`,
190
+ '',
191
+ `**Overbooked Member-Days:** ${overbooked.length}`,
192
+ '',
193
+ ].join('\n');
194
+ if (overbooked.length === 0) {
195
+ return summary + '_No overbooking detected. All members are within 8h/day._';
196
+ }
197
+ const rows = overbooked.map((r) => [
198
+ r.identifier,
199
+ r.date,
200
+ hoursDisplay(r.hours),
201
+ hoursDisplay(round2(r.hours - 8)),
202
+ ]);
203
+ return (summary +
204
+ mdTable(['Member', 'Date', 'Scheduled Hours', 'Overflow'], rows));
205
+ });
206
+ // ===========================================================================
207
+ // 4. unscheduled_time_report
208
+ // ===========================================================================
209
+ reg('unscheduled_time_report', async (params) => {
210
+ const identifier = String(params['identifier'] ?? '');
211
+ if (!identifier)
212
+ return 'Error: identifier is required.';
213
+ const startRaw = String(params['start_date'] ?? daysAgo(7));
214
+ const endRaw = String(params['end_date'] ?? todayISO());
215
+ const api = getAPI();
216
+ const [schedResult, timeResult] = await Promise.all([
217
+ api.paginatedFetch('/schedule/entries', `member/identifier='${identifier}' AND dateStart>=[${startRaw}] AND dateStart<=[${endRaw}]`, 'id,dateStart,dateEnd,member/identifier', 2000),
218
+ api.paginatedFetch('/time/entries', `member/identifier='${identifier}' AND timeStart>=[${startRaw}] AND timeStart<=[${endRaw}]`, 'id,actualHours,timeStart,timeEnd,chargeToType,chargeToId,notes,member/identifier', 2000),
219
+ ]);
220
+ // Build schedule intervals as [startMs, endMs] pairs
221
+ const schedIntervals = schedResult.items
222
+ .map((e) => {
223
+ const s = new Date(String(e['dateStart'] ?? '')).getTime();
224
+ const en = new Date(String(e['dateEnd'] ?? '')).getTime();
225
+ return [s, en];
226
+ })
227
+ .filter(([s, en]) => Number.isFinite(s) && Number.isFinite(en) && en > s);
228
+ // A time entry is "unscheduled" if it does not overlap any schedule interval.
229
+ function overlapsAnySchedule(timeStart, timeEnd) {
230
+ return schedIntervals.some(([s, en]) => timeStart < en && timeEnd > s);
231
+ }
232
+ const unscheduled = timeResult.items.filter((e) => {
233
+ const ts = new Date(String(e['timeStart'] ?? '')).getTime();
234
+ const hours = num(e['actualHours']);
235
+ // derive timeEnd from timeStart + actualHours if not present
236
+ const teRaw = e['timeEnd'] ? new Date(String(e['timeEnd'])).getTime() : NaN;
237
+ const te = Number.isFinite(teRaw) && teRaw > ts ? teRaw : ts + hours * 3_600_000;
238
+ if (!Number.isFinite(ts))
239
+ return false;
240
+ return !overlapsAnySchedule(ts, te);
241
+ });
242
+ const summary = [
243
+ `## Unscheduled Time Report — ${identifier} (${startRaw.substring(0, 10)} to ${endRaw.substring(0, 10)})`,
244
+ '',
245
+ `**Time Entries:** ${timeResult.items.length} total | **Unscheduled:** ${unscheduled.length} | **Schedule Entries:** ${schedResult.items.length}`,
246
+ '',
247
+ ].join('\n');
248
+ if (unscheduled.length === 0) {
249
+ return summary + '_All time entries overlap with scheduled blocks._';
250
+ }
251
+ const rows = unscheduled.map((e) => {
252
+ const id = String(e['id'] ?? 'N/A');
253
+ const chargeTo = `${e['chargeToType'] ?? 'N/A'} #${e['chargeToId'] ?? 'N/A'}`;
254
+ const hours = hoursDisplay(round2(num(e['actualHours'])));
255
+ const time = String(e['timeStart'] ?? 'N/A').substring(0, 16).replace('T', ' ');
256
+ const notes = String(e['notes'] ?? '').substring(0, 60).replace(/\|/g, '/') || '—';
257
+ return [id, chargeTo, hours, time, notes];
258
+ });
259
+ return (summary +
260
+ mdTable(['Entry ID', 'Charge To', 'Hours', 'Time', 'Notes'], rows));
261
+ });
262
+ // ===========================================================================
263
+ // 5. schedule_coverage_gaps
264
+ // ===========================================================================
265
+ reg('schedule_coverage_gaps', async (params) => {
266
+ const startRaw = String(params['start_date'] ?? todayISO());
267
+ const endRaw = String(params['end_date'] ?? daysFromNow(7));
268
+ const startDate = startRaw.substring(0, 10);
269
+ const endDate = endRaw.substring(0, 10);
270
+ const BUSINESS_START_HOUR = 8; // 8:00 AM UTC
271
+ const BUSINESS_END_HOUR = 17; // 5:00 PM UTC
272
+ const api = getAPI();
273
+ const schedResult = await api.paginatedFetch('/schedule/entries', `dateStart>=[${startRaw}] AND dateStart<=[${endRaw}]`, 'id,dateStart,dateEnd,member/identifier', 5000);
274
+ // Group entries by day
275
+ const entriesByDay = groupByDate(schedResult.items, 'dateStart');
276
+ const weekdays = weekdaysBetween(startDate, endDate);
277
+ const rows = [];
278
+ for (const day of weekdays) {
279
+ const dayEntries = entriesByDay.get(day) ?? [];
280
+ // Build covered minute-level bitmap for the business window (8–17 = 540 min)
281
+ const covered = new Array(540).fill(false);
282
+ const dayStartMs = new Date(`${day}T${String(BUSINESS_START_HOUR).padStart(2, '0')}:00:00Z`).getTime();
283
+ const dayEndMs = new Date(`${day}T${String(BUSINESS_END_HOUR).padStart(2, '0')}:00:00Z`).getTime();
284
+ for (const entry of dayEntries) {
285
+ // Skip all-day placeholders
286
+ if (scheduledHours(entry) === 0)
287
+ continue;
288
+ const eStart = new Date(String(entry['dateStart'] ?? '')).getTime();
289
+ const eEnd = new Date(String(entry['dateEnd'] ?? '')).getTime();
290
+ // Clamp to business window
291
+ const coverStart = Math.max(eStart, dayStartMs);
292
+ const coverEnd = Math.min(eEnd, dayEndMs);
293
+ if (coverEnd <= coverStart)
294
+ continue;
295
+ const startMin = Math.floor((coverStart - dayStartMs) / 60_000);
296
+ const endMin = Math.ceil((coverEnd - dayStartMs) / 60_000);
297
+ for (let m = startMin; m < endMin && m < 540; m++) {
298
+ covered[m] = true;
299
+ }
300
+ }
301
+ // Find uncovered gaps
302
+ let gapStart = null;
303
+ const pushGap = (gapStartMin, gapEndMin) => {
304
+ const durationMin = gapEndMin - gapStartMin;
305
+ if (durationMin < 1)
306
+ return;
307
+ const startHr = BUSINESS_START_HOUR + Math.floor(gapStartMin / 60);
308
+ const startMn = gapStartMin % 60;
309
+ const endHr = BUSINESS_START_HOUR + Math.floor(gapEndMin / 60);
310
+ const endMn = gapEndMin % 60;
311
+ const fmt = (h, m) => `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
312
+ const durationH = round2(durationMin / 60);
313
+ rows.push([day, fmt(startHr, startMn), fmt(endHr, endMn), hoursDisplay(durationH)]);
314
+ };
315
+ for (let m = 0; m <= 540; m++) {
316
+ const isCovered = m < 540 ? covered[m] : false;
317
+ if (!isCovered && gapStart === null) {
318
+ gapStart = m;
319
+ }
320
+ else if (isCovered && gapStart !== null) {
321
+ pushGap(gapStart, m);
322
+ gapStart = null;
323
+ }
324
+ }
325
+ }
326
+ const summary = [
327
+ `## Schedule Coverage Gaps — ${startDate} to ${endDate}`,
328
+ '',
329
+ `**Weekdays Checked:** ${weekdays.length} | **Coverage Gaps Found:** ${rows.length}`,
330
+ '',
331
+ ].join('\n');
332
+ if (rows.length === 0) {
333
+ return (summary +
334
+ '_Full business-hours coverage (08:00-17:00) detected for all weekdays in range._');
335
+ }
336
+ return (summary +
337
+ mdTable(['Date', 'Gap Start', 'Gap End', 'Duration'], rows));
338
+ });
339
+ //# sourceMappingURL=analytics-msp-schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-msp-schedule.js","sourceRoot":"","sources":["../../src/operations/analytics-msp-schedule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type MspHandler } from './analytics-msp-utils.js';
2
+ export declare const mspTeamHandlers: Record<string, MspHandler>;
3
+ //# sourceMappingURL=analytics-msp-team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-msp-team.d.ts","sourceRoot":"","sources":["../../src/operations/analytics-msp-team.ts"],"names":[],"mappings":"AAGA,OAAO,EACoB,KAAK,UAAU,EAGzC,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAM,CAAC"}
@@ -0,0 +1,195 @@
1
+ // ConnectWise PSA MCP Server — MSP Team Analytics Handlers
2
+ import { getAPI } from '../services/connectwise-api.js';
3
+ import { num, nested, daysAgo, round2, pct, hoursDisplay, mdTable, } from './analytics-msp-utils.js';
4
+ export const mspTeamHandlers = {};
5
+ function reg(name, handler) { mspTeamHandlers[name] = handler; }
6
+ // ===========================================================================
7
+ // TEAM ANALYTICS
8
+ // ===========================================================================
9
+ reg('member_performance_summary', async (params) => {
10
+ const api = getAPI();
11
+ const identifier = String(params['identifier'] ?? '');
12
+ if (!identifier)
13
+ return 'Error: identifier required.';
14
+ const days = num(params['days'], 30);
15
+ const [tickets, timeEntries] = await Promise.all([
16
+ api.paginatedFetch('/service/tickets', `member/identifier="${identifier}" AND dateEntered>=[${daysAgo(days)}]`, 'id,closedFlag,dateEntered,closedDate,priority/name', 1000),
17
+ api.paginatedFetch('/time/entries', `member/identifier="${identifier}" AND dateEntered>=[${daysAgo(days)}]`, 'id,actualHours,billableOption,dateEntered', 2000),
18
+ ]);
19
+ const closed = tickets.items.filter(t => t['closedFlag'] === true);
20
+ const open = tickets.items.filter(t => t['closedFlag'] !== true);
21
+ const totalHours = timeEntries.items.reduce((s, e) => s + num(e['actualHours']), 0);
22
+ const billableHours = timeEntries.items
23
+ .filter(e => String(e['billableOption'] ?? '').toLowerCase().includes('billable'))
24
+ .reduce((s, e) => s + num(e['actualHours']), 0);
25
+ // Average resolution time (hours) for closed tickets
26
+ const resolutionTimes = closed
27
+ .filter(t => t['closedDate'] && t['dateEntered'])
28
+ .map(t => (new Date(t['closedDate']).getTime() - new Date(t['dateEntered']).getTime()) / 3600000);
29
+ const avgResolution = resolutionTimes.length > 0
30
+ ? round2(resolutionTimes.reduce((s, v) => s + v, 0) / resolutionTimes.length)
31
+ : 0;
32
+ const lines = [
33
+ `## Member Performance: ${identifier} (last ${days} days)\n`,
34
+ mdTable(['Metric', 'Value'], [
35
+ ['Tickets Closed', String(closed.length)],
36
+ ['Tickets Open', String(open.length)],
37
+ ['Total Tickets', String(tickets.items.length)],
38
+ ['Hours Logged', hoursDisplay(totalHours)],
39
+ ['Billable Hours', hoursDisplay(billableHours)],
40
+ ['Billable %', pct(billableHours, totalHours)],
41
+ ['Avg Resolution Time', `${avgResolution}h`],
42
+ ]),
43
+ ];
44
+ return lines.join('\n');
45
+ });
46
+ reg('team_leaderboard', async (params) => {
47
+ const api = getAPI();
48
+ const metric = String(params['metric'] ?? 'tickets');
49
+ const days = num(params['days'], 30);
50
+ const validMetrics = ['tickets', 'hours', 'utilization'];
51
+ if (!validMetrics.includes(metric)) {
52
+ return `Error: metric must be one of: ${validMetrics.join(', ')}.`;
53
+ }
54
+ const [members, tickets, timeEntries] = await Promise.all([
55
+ api.paginatedFetch('/system/members', 'inactiveFlag=false', 'id,identifier,firstName,lastName', 200),
56
+ api.paginatedFetch('/service/tickets', `closedFlag=true AND closedDate>=[${daysAgo(days)}]`, 'id,member/identifier', 5000),
57
+ api.paginatedFetch('/time/entries', `dateEntered>=[${daysAgo(days)}]`, 'id,actualHours,billableOption,member/identifier', 5000),
58
+ ]);
59
+ const board = {};
60
+ for (const m of members.items) {
61
+ const id = String(m['identifier'] ?? '');
62
+ board[id] = {
63
+ name: `${m['firstName'] ?? ''} ${m['lastName'] ?? ''}`.trim() || id,
64
+ closedTickets: 0,
65
+ totalHours: 0,
66
+ billableHours: 0,
67
+ };
68
+ }
69
+ for (const t of tickets.items) {
70
+ const id = nested(t, 'member', 'identifier');
71
+ if (board[id])
72
+ board[id].closedTickets++;
73
+ }
74
+ // Work hours available over the period (Mon–Fri only)
75
+ const workHoursAvailable = days * 8 * 5 / 7;
76
+ for (const e of timeEntries.items) {
77
+ const id = nested(e, 'member', 'identifier');
78
+ if (!board[id])
79
+ board[id] = { name: id, closedTickets: 0, totalHours: 0, billableHours: 0 };
80
+ board[id].totalHours += num(e['actualHours']);
81
+ if (String(e['billableOption'] ?? '').toLowerCase().includes('billable')) {
82
+ board[id].billableHours += num(e['actualHours']);
83
+ }
84
+ }
85
+ let sorted;
86
+ let valueLabel;
87
+ if (metric === 'tickets') {
88
+ sorted = Object.entries(board).sort((a, b) => b[1].closedTickets - a[1].closedTickets);
89
+ valueLabel = 'Tickets Closed';
90
+ }
91
+ else if (metric === 'hours') {
92
+ sorted = Object.entries(board).sort((a, b) => b[1].totalHours - a[1].totalHours);
93
+ valueLabel = 'Total Hours';
94
+ }
95
+ else {
96
+ sorted = Object.entries(board).sort((a, b) => b[1].totalHours - a[1].totalHours);
97
+ valueLabel = 'Utilization %';
98
+ }
99
+ const active = sorted.filter(([, d]) => d.closedTickets > 0 || d.totalHours > 0);
100
+ if (active.length === 0)
101
+ return `No member activity found in the last ${days} days.`;
102
+ let rank = 0;
103
+ const rows = active.map(([id, d]) => {
104
+ rank++;
105
+ let value;
106
+ if (metric === 'tickets') {
107
+ value = String(d.closedTickets);
108
+ }
109
+ else if (metric === 'hours') {
110
+ value = hoursDisplay(d.totalHours);
111
+ }
112
+ else {
113
+ value = pct(d.totalHours, workHoursAvailable);
114
+ }
115
+ return [String(rank), `${d.name} (${id})`, value];
116
+ });
117
+ return [
118
+ `## Team Leaderboard — ${valueLabel} (last ${days} days)\n`,
119
+ mdTable(['Rank', 'Member', valueLabel], rows),
120
+ ].join('\n');
121
+ });
122
+ reg('member_ticket_distribution', async (params) => {
123
+ const api = getAPI();
124
+ const days = num(params['days'], 30);
125
+ const tickets = await api.paginatedFetch('/service/tickets', `dateEntered>=[${daysAgo(days)}]`, 'id,closedFlag,member/identifier', 5000);
126
+ if (tickets.items.length === 0)
127
+ return `No tickets found in the last ${days} days.`;
128
+ const byMember = {};
129
+ for (const t of tickets.items) {
130
+ const id = nested(t, 'member', 'identifier');
131
+ if (!byMember[id])
132
+ byMember[id] = { assigned: 0, closed: 0, open: 0 };
133
+ byMember[id].assigned++;
134
+ if (t['closedFlag'] === true)
135
+ byMember[id].closed++;
136
+ else
137
+ byMember[id].open++;
138
+ }
139
+ const total = tickets.items.length;
140
+ const sorted = Object.entries(byMember).sort((a, b) => b[1].assigned - a[1].assigned);
141
+ const rows = sorted.map(([id, d]) => [
142
+ id,
143
+ String(d.assigned),
144
+ String(d.closed),
145
+ String(d.open),
146
+ pct(d.assigned, total),
147
+ ]);
148
+ return [
149
+ `## Member Ticket Distribution (last ${days} days)\n`,
150
+ `**Total Tickets:** ${total}\n`,
151
+ mdTable(['Member', 'Assigned', 'Closed', 'Open', '% of Total'], rows),
152
+ ].join('\n');
153
+ });
154
+ reg('dispatch_efficiency', async (params) => {
155
+ const api = getAPI();
156
+ const days = num(params['days'], 30);
157
+ const timeEntries = await api.paginatedFetch('/time/entries', `dateEntered>=[${daysAgo(days)}]`, 'id,actualHours,member/identifier,chargeToType,notes', 5000);
158
+ if (timeEntries.items.length === 0)
159
+ return `No time entries found in the last ${days} days.`;
160
+ const byMember = {};
161
+ for (const e of timeEntries.items) {
162
+ const id = nested(e, 'member', 'identifier');
163
+ if (!byMember[id])
164
+ byMember[id] = { dispatch: 0, productive: 0 };
165
+ const chargeType = String(e['chargeToType'] ?? '').toLowerCase();
166
+ const notes = String(e['notes'] ?? '').toLowerCase();
167
+ const hours = num(e['actualHours']);
168
+ const isDispatch = chargeType.includes('dispatch') || notes.includes('dispatch') || notes.includes('triage');
169
+ if (isDispatch)
170
+ byMember[id].dispatch += hours;
171
+ else
172
+ byMember[id].productive += hours;
173
+ }
174
+ const sorted = Object.entries(byMember)
175
+ .filter(([, d]) => d.dispatch + d.productive > 0)
176
+ .sort((a, b) => (b[1].dispatch + b[1].productive) - (a[1].dispatch + a[1].productive));
177
+ if (sorted.length === 0)
178
+ return `No member time data found in the last ${days} days.`;
179
+ const rows = sorted.map(([id, d]) => {
180
+ const total = d.dispatch + d.productive;
181
+ const ratio = total > 0 ? round2(d.productive / Math.max(d.dispatch, 0.01)) : 0;
182
+ return [
183
+ id,
184
+ hoursDisplay(d.dispatch),
185
+ hoursDisplay(d.productive),
186
+ `${ratio}:1`,
187
+ ];
188
+ });
189
+ return [
190
+ `## Dispatch Efficiency (last ${days} days)\n`,
191
+ `A higher Productive:Dispatch ratio indicates less time on triage/dispatch.\n`,
192
+ mdTable(['Member', 'Dispatch Hours', 'Productive Hours', 'Ratio (P:D)'], rows),
193
+ ].join('\n');
194
+ });
195
+ //# sourceMappingURL=analytics-msp-team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-msp-team.js","sourceRoot":"","sources":["../../src/operations/analytics-msp-team.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type MspHandler } from './analytics-msp-utils.js';
2
+ export declare const mspTicketHandlers: Record<string, MspHandler>;
3
+ //# sourceMappingURL=analytics-msp-tickets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-msp-tickets.d.ts","sourceRoot":"","sources":["../../src/operations/analytics-msp-tickets.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,UAAU,EAiBhB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAM,CAAC"}