@burdenoff/mcp-libs 2026.529.1 → 2026.627.1

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 (33) hide show
  1. package/dist/{chunk-HRWIDQJE.js → chunk-XITZQYB2.js} +8 -3
  2. package/dist/{chunk-HRWIDQJE.js.map → chunk-XITZQYB2.js.map} +1 -1
  3. package/dist/modules/crewfoundry/index.cjs +1598 -0
  4. package/dist/modules/crewfoundry/index.cjs.map +1 -0
  5. package/dist/modules/crewfoundry/index.d.cts +8 -0
  6. package/dist/modules/crewfoundry/index.d.ts +8 -0
  7. package/dist/modules/crewfoundry/index.js +1537 -0
  8. package/dist/modules/crewfoundry/index.js.map +1 -0
  9. package/dist/modules/ggnomad/index.cjs +1068 -0
  10. package/dist/modules/ggnomad/index.cjs.map +1 -0
  11. package/dist/modules/ggnomad/index.d.cts +8 -0
  12. package/dist/modules/ggnomad/index.d.ts +8 -0
  13. package/dist/modules/ggnomad/index.js +1007 -0
  14. package/dist/modules/ggnomad/index.js.map +1 -0
  15. package/dist/modules/housingvista/index.cjs +1092 -0
  16. package/dist/modules/housingvista/index.cjs.map +1 -0
  17. package/dist/modules/housingvista/index.d.cts +8 -0
  18. package/dist/modules/housingvista/index.d.ts +8 -0
  19. package/dist/modules/housingvista/index.js +1031 -0
  20. package/dist/modules/housingvista/index.js.map +1 -0
  21. package/dist/modules/kadaikodi/index.cjs +1467 -0
  22. package/dist/modules/kadaikodi/index.cjs.map +1 -0
  23. package/dist/modules/kadaikodi/index.d.cts +8 -0
  24. package/dist/modules/kadaikodi/index.d.ts +8 -0
  25. package/dist/modules/kadaikodi/index.js +1406 -0
  26. package/dist/modules/kadaikodi/index.js.map +1 -0
  27. package/dist/modules/sandbox/index.cjs +26 -0
  28. package/dist/modules/sandbox/index.cjs.map +1 -1
  29. package/dist/modules/sandbox/index.js +22 -1
  30. package/dist/modules/sandbox/index.js.map +1 -1
  31. package/dist/modules/vibecontrols/index.cjs.map +1 -1
  32. package/dist/modules/vibecontrols/index.js +1 -1
  33. package/package.json +1 -1
@@ -0,0 +1,1537 @@
1
+ import { mcpToolName, jsonResult, errorResult, mcpResourceUri, mcpPromptName } from '../../chunk-H2OYWLOA.js';
2
+ import { z } from 'zod';
3
+
4
+ // src/modules/crewfoundry/operations.ts
5
+ var EMPLOYEE_FIELDS = `
6
+ id firstName lastName email phone position department location type status
7
+ salary performanceScore startDate managerId avatar workspaceId
8
+ `;
9
+ var DEPARTMENT_FIELDS = `
10
+ id name headId headName employeeCount budget location status workspaceId
11
+ `;
12
+ var TEAM_FIELDS = `
13
+ id name description department leadId leadName memberCount members
14
+ projectCount status createdAt workspaceId
15
+ `;
16
+ var CANDIDATE_FIELDS = `
17
+ id firstName lastName email phone position experience currentCompany source
18
+ status rating appliedDate resumeUrl skills notes workspaceId
19
+ `;
20
+ var JOB_POSTING_FIELDS = `
21
+ id title department location type experienceLevel description requirements
22
+ benefits salaryMin salaryMax status applicants postedDate deadline workspaceId
23
+ `;
24
+ var INTERVIEW_FIELDS = `
25
+ id candidateId candidateName position interviewerName type date time status
26
+ rating feedback workspaceId
27
+ `;
28
+ var LEAVE_REQUEST_FIELDS = `
29
+ id employeeId employeeName department type startDate endDate days reason
30
+ status approverName workspaceId
31
+ `;
32
+ var TIME_ENTRY_FIELDS = `
33
+ id employeeId employeeName date clockIn clockOut totalHours overtime project
34
+ status workspaceId
35
+ `;
36
+ var PAYROLL_FIELDS = `
37
+ id employeeId employeeName department period grossPay deductions netPay status
38
+ payDate paymentMethod workspaceId
39
+ `;
40
+ var CLIENT_FIELDS = `
41
+ id name industry contactPerson email phone status projects revenue since
42
+ workspaceId
43
+ `;
44
+ var INVOICE_FIELDS = `
45
+ id number clientName amount status issueDate dueDate items workspaceId
46
+ `;
47
+ var PROJECT_FIELDS = `
48
+ id name description status priority progress budget spent startDate endDate
49
+ managerId managerName teamId teamName tasks completedTasks workspaceId
50
+ `;
51
+ var VENDOR_FIELDS = `
52
+ id name category contactPerson email phone status rating contractValue
53
+ workspaceId
54
+ `;
55
+ var COURSE_FIELDS = `
56
+ id title description category level instructor duration modules enrolled
57
+ completed rating skills status thumbnail workspaceId
58
+ `;
59
+ var LEARNING_PATH_FIELDS = `
60
+ id title description level duration courses enrolled completionRate workspaceId
61
+ `;
62
+ var ANNOUNCEMENT_FIELDS = `
63
+ id title content author authorRole category priority isPinned tags viewCount
64
+ createdAt workspaceId
65
+ `;
66
+ var NOTIFICATION_FIELDS = `
67
+ id title message type category read actionUrl createdAt workspaceId
68
+ `;
69
+ var MARKETPLACE_SERVICE_FIELDS = `
70
+ id title description category provider price priceType rating reviews
71
+ deliveryTime skills status workspaceId
72
+ `;
73
+ var LIST_EMPLOYEES = `
74
+ query CrewfoundryListEmployees {
75
+ crewfoundryBootstrap { employees { ${EMPLOYEE_FIELDS} } }
76
+ }
77
+ `;
78
+ var LIST_DEPARTMENTS = `
79
+ query CrewfoundryListDepartments {
80
+ crewfoundryBootstrap { departments { ${DEPARTMENT_FIELDS} } }
81
+ }
82
+ `;
83
+ var LIST_TEAMS = `
84
+ query CrewfoundryListTeams {
85
+ crewfoundryBootstrap { teams { ${TEAM_FIELDS} } }
86
+ }
87
+ `;
88
+ var LIST_CANDIDATES = `
89
+ query CrewfoundryListCandidates {
90
+ crewfoundryBootstrap { candidates { ${CANDIDATE_FIELDS} } }
91
+ }
92
+ `;
93
+ var LIST_JOB_POSTINGS = `
94
+ query CrewfoundryListJobPostings {
95
+ crewfoundryBootstrap { jobPostings { ${JOB_POSTING_FIELDS} } }
96
+ }
97
+ `;
98
+ var LIST_INTERVIEWS = `
99
+ query CrewfoundryListInterviews {
100
+ crewfoundryBootstrap { interviews { ${INTERVIEW_FIELDS} } }
101
+ }
102
+ `;
103
+ var LIST_LEAVE_REQUESTS = `
104
+ query CrewfoundryListLeaveRequests {
105
+ crewfoundryBootstrap { leaveRequests { ${LEAVE_REQUEST_FIELDS} } }
106
+ }
107
+ `;
108
+ var LIST_TIME_ENTRIES = `
109
+ query CrewfoundryListTimeEntries {
110
+ crewfoundryBootstrap { timeEntries { ${TIME_ENTRY_FIELDS} } }
111
+ }
112
+ `;
113
+ var LIST_PAYROLL_RECORDS = `
114
+ query CrewfoundryListPayrollRecords {
115
+ crewfoundryBootstrap { payrollRecords { ${PAYROLL_FIELDS} } }
116
+ }
117
+ `;
118
+ var LIST_CLIENTS = `
119
+ query CrewfoundryListClients {
120
+ crewfoundryBootstrap { clients { ${CLIENT_FIELDS} } }
121
+ }
122
+ `;
123
+ var LIST_INVOICES = `
124
+ query CrewfoundryListInvoices {
125
+ crewfoundryBootstrap { invoices { ${INVOICE_FIELDS} } }
126
+ }
127
+ `;
128
+ var LIST_PROJECTS = `
129
+ query CrewfoundryListProjects {
130
+ crewfoundryBootstrap { projects { ${PROJECT_FIELDS} } }
131
+ }
132
+ `;
133
+ var LIST_VENDORS = `
134
+ query CrewfoundryListVendors {
135
+ crewfoundryBootstrap { vendors { ${VENDOR_FIELDS} } }
136
+ }
137
+ `;
138
+ var LIST_COURSES = `
139
+ query CrewfoundryListCourses {
140
+ crewfoundryBootstrap { courses { ${COURSE_FIELDS} } }
141
+ }
142
+ `;
143
+ var LIST_LEARNING_PATHS = `
144
+ query CrewfoundryListLearningPaths {
145
+ crewfoundryBootstrap { learningPaths { ${LEARNING_PATH_FIELDS} } }
146
+ }
147
+ `;
148
+ var LIST_ANNOUNCEMENTS = `
149
+ query CrewfoundryListAnnouncements {
150
+ crewfoundryBootstrap { announcements { ${ANNOUNCEMENT_FIELDS} } }
151
+ }
152
+ `;
153
+ var LIST_NOTIFICATIONS = `
154
+ query CrewfoundryListNotifications {
155
+ crewfoundryBootstrap { notifications { ${NOTIFICATION_FIELDS} } }
156
+ }
157
+ `;
158
+ var LIST_MARKETPLACE_SERVICES = `
159
+ query CrewfoundryListMarketplaceServices {
160
+ crewfoundryBootstrap { marketplaceServices { ${MARKETPLACE_SERVICE_FIELDS} } }
161
+ }
162
+ `;
163
+ var BOOTSTRAP_OVERVIEW = `
164
+ query CrewfoundryOverview {
165
+ crewfoundryBootstrap {
166
+ employees { ${EMPLOYEE_FIELDS} }
167
+ departments { ${DEPARTMENT_FIELDS} }
168
+ teams { ${TEAM_FIELDS} }
169
+ candidates { ${CANDIDATE_FIELDS} }
170
+ jobPostings { ${JOB_POSTING_FIELDS} }
171
+ interviews { ${INTERVIEW_FIELDS} }
172
+ leaveRequests { ${LEAVE_REQUEST_FIELDS} }
173
+ timeEntries { ${TIME_ENTRY_FIELDS} }
174
+ payrollRecords { ${PAYROLL_FIELDS} }
175
+ clients { ${CLIENT_FIELDS} }
176
+ invoices { ${INVOICE_FIELDS} }
177
+ projects { ${PROJECT_FIELDS} }
178
+ vendors { ${VENDOR_FIELDS} }
179
+ courses { ${COURSE_FIELDS} }
180
+ learningPaths { ${LEARNING_PATH_FIELDS} }
181
+ announcements { ${ANNOUNCEMENT_FIELDS} }
182
+ notifications { ${NOTIFICATION_FIELDS} }
183
+ marketplaceServices { ${MARKETPLACE_SERVICE_FIELDS} }
184
+ }
185
+ }
186
+ `;
187
+ var CREATE_EMPLOYEE = `
188
+ mutation CrewfoundryCreateEmployee($input: CreateCrewEmployeeInput!) {
189
+ createCrewEmployee(input: $input) { ${EMPLOYEE_FIELDS} }
190
+ }
191
+ `;
192
+ var UPDATE_EMPLOYEE = `
193
+ mutation CrewfoundryUpdateEmployee($id: ID!, $input: UpdateCrewEmployeeInput!) {
194
+ updateCrewEmployee(id: $id, input: $input) { ${EMPLOYEE_FIELDS} }
195
+ }
196
+ `;
197
+ var REMOVE_EMPLOYEE = `
198
+ mutation CrewfoundryRemoveEmployee($id: ID!) {
199
+ removeCrewEmployee(id: $id)
200
+ }
201
+ `;
202
+ var CREATE_CANDIDATE = `
203
+ mutation CrewfoundryCreateCandidate($input: CreateCrewCandidateInput!) {
204
+ createCrewCandidate(input: $input) { ${CANDIDATE_FIELDS} }
205
+ }
206
+ `;
207
+ var UPDATE_CANDIDATE = `
208
+ mutation CrewfoundryUpdateCandidate($id: ID!, $input: UpdateCrewCandidateInput!) {
209
+ updateCrewCandidate(id: $id, input: $input) { ${CANDIDATE_FIELDS} }
210
+ }
211
+ `;
212
+ var CREATE_JOB_POSTING = `
213
+ mutation CrewfoundryCreateJobPosting($input: CreateCrewJobPostingInput!) {
214
+ createCrewJobPosting(input: $input) { ${JOB_POSTING_FIELDS} }
215
+ }
216
+ `;
217
+ var UPDATE_JOB_POSTING = `
218
+ mutation CrewfoundryUpdateJobPosting($id: ID!, $input: UpdateCrewJobPostingInput!) {
219
+ updateCrewJobPosting(id: $id, input: $input) { ${JOB_POSTING_FIELDS} }
220
+ }
221
+ `;
222
+ var CREATE_LEAVE_REQUEST = `
223
+ mutation CrewfoundryCreateLeaveRequest($input: CreateCrewLeaveRequestInput!) {
224
+ createCrewLeaveRequest(input: $input) { ${LEAVE_REQUEST_FIELDS} }
225
+ }
226
+ `;
227
+ var UPDATE_LEAVE_REQUEST = `
228
+ mutation CrewfoundryUpdateLeaveRequest($id: ID!, $input: UpdateCrewLeaveRequestInput!) {
229
+ updateCrewLeaveRequest(id: $id, input: $input) { ${LEAVE_REQUEST_FIELDS} }
230
+ }
231
+ `;
232
+ var CREATE_ANNOUNCEMENT = `
233
+ mutation CrewfoundryCreateAnnouncement($input: CreateCrewAnnouncementInput!) {
234
+ createCrewAnnouncement(input: $input) { ${ANNOUNCEMENT_FIELDS} }
235
+ }
236
+ `;
237
+ var MARK_NOTIFICATION_READ = `
238
+ mutation CrewfoundryMarkNotificationRead($id: ID!) {
239
+ markCrewNotificationRead(id: $id)
240
+ }
241
+ `;
242
+ var MARK_ALL_NOTIFICATIONS_READ = `
243
+ mutation CrewfoundryMarkAllNotificationsRead {
244
+ markAllCrewNotificationsRead
245
+ }
246
+ `;
247
+ var IsoDateTime = z.string().describe('ISO-8601 datetime, e.g. "2026-06-26T09:00:00.000Z"');
248
+
249
+ // src/modules/crewfoundry/tools/people.ts
250
+ function registerPeopleTools(server, ctx, track) {
251
+ server.registerTool(
252
+ track(mcpToolName(ctx.productName, "employees_list")),
253
+ {
254
+ title: "List Employees",
255
+ description: "List all employees in the bound workspace (from the crewfoundry bootstrap).",
256
+ inputSchema: {}
257
+ },
258
+ async () => {
259
+ try {
260
+ const data = await ctx.gql.workspace.request(LIST_EMPLOYEES, {});
261
+ return jsonResult(data.crewfoundryBootstrap.employees);
262
+ } catch (error) {
263
+ ctx.logger.error("crewfoundry employees_list failed", { error: String(error) });
264
+ return errorResult(
265
+ `Failed to list employees: ${error instanceof Error ? error.message : String(error)}`
266
+ );
267
+ }
268
+ }
269
+ );
270
+ server.registerTool(
271
+ track(mcpToolName(ctx.productName, "employees_create")),
272
+ {
273
+ title: "Create Employee",
274
+ description: "Add a new employee to the workspace directory.",
275
+ inputSchema: {
276
+ firstName: z.string().min(1).describe("First name"),
277
+ lastName: z.string().min(1).describe("Last name"),
278
+ email: z.string().min(1).describe("Work email"),
279
+ phone: z.string().min(1).describe("Contact phone"),
280
+ position: z.string().min(1).describe("Job title / position"),
281
+ department: z.string().min(1).describe("Department name"),
282
+ location: z.string().min(1).describe("Work location"),
283
+ type: z.string().min(1).describe('Employment type, e.g. "full-time" / "contract"'),
284
+ status: z.string().min(1).describe('Employment status, e.g. "active" / "on-leave"'),
285
+ salary: z.number().describe("Annual/period salary"),
286
+ performanceScore: z.number().describe("Performance score (e.g. 0\u20135 or 0\u2013100)"),
287
+ startDate: IsoDateTime.describe("Start date (ISO-8601)"),
288
+ managerId: z.string().optional().describe("Manager employee ID"),
289
+ avatar: z.string().optional().describe("Avatar image URL")
290
+ }
291
+ },
292
+ async ({
293
+ firstName,
294
+ lastName,
295
+ email,
296
+ phone,
297
+ position,
298
+ department,
299
+ location,
300
+ type,
301
+ status,
302
+ salary,
303
+ performanceScore,
304
+ startDate,
305
+ managerId,
306
+ avatar
307
+ }) => {
308
+ try {
309
+ const input = {
310
+ firstName,
311
+ lastName,
312
+ email,
313
+ phone,
314
+ position,
315
+ department,
316
+ location,
317
+ type,
318
+ status,
319
+ salary,
320
+ performanceScore,
321
+ startDate
322
+ };
323
+ if (managerId !== void 0) input.managerId = managerId;
324
+ if (avatar !== void 0) input.avatar = avatar;
325
+ const data = await ctx.gql.workspace.request(CREATE_EMPLOYEE, { input });
326
+ return jsonResult(data.createCrewEmployee);
327
+ } catch (error) {
328
+ ctx.logger.error("crewfoundry employees_create failed", { error: String(error) });
329
+ return errorResult(
330
+ `Failed to create employee: ${error instanceof Error ? error.message : String(error)}`
331
+ );
332
+ }
333
+ }
334
+ );
335
+ server.registerTool(
336
+ track(mcpToolName(ctx.productName, "employees_update")),
337
+ {
338
+ title: "Update Employee",
339
+ description: "Update an employee. At least one mutable field must be provided.",
340
+ inputSchema: {
341
+ id: z.string().describe("Employee ID"),
342
+ firstName: z.string().optional().describe("Updated first name"),
343
+ lastName: z.string().optional().describe("Updated last name"),
344
+ email: z.string().optional().describe("Updated email"),
345
+ phone: z.string().optional().describe("Updated phone"),
346
+ position: z.string().optional().describe("Updated position"),
347
+ department: z.string().optional().describe("Updated department"),
348
+ location: z.string().optional().describe("Updated location"),
349
+ type: z.string().optional().describe("Updated employment type"),
350
+ status: z.string().optional().describe("Updated employment status"),
351
+ salary: z.number().optional().describe("Updated salary"),
352
+ performanceScore: z.number().optional().describe("Updated performance score"),
353
+ startDate: IsoDateTime.optional().describe("Updated start date (ISO-8601)"),
354
+ managerId: z.string().optional().describe("Updated manager employee ID"),
355
+ avatar: z.string().optional().describe("Updated avatar URL")
356
+ }
357
+ },
358
+ async ({
359
+ id,
360
+ firstName,
361
+ lastName,
362
+ email,
363
+ phone,
364
+ position,
365
+ department,
366
+ location,
367
+ type,
368
+ status,
369
+ salary,
370
+ performanceScore,
371
+ startDate,
372
+ managerId,
373
+ avatar
374
+ }) => {
375
+ try {
376
+ const input = {};
377
+ if (firstName !== void 0) input.firstName = firstName;
378
+ if (lastName !== void 0) input.lastName = lastName;
379
+ if (email !== void 0) input.email = email;
380
+ if (phone !== void 0) input.phone = phone;
381
+ if (position !== void 0) input.position = position;
382
+ if (department !== void 0) input.department = department;
383
+ if (location !== void 0) input.location = location;
384
+ if (type !== void 0) input.type = type;
385
+ if (status !== void 0) input.status = status;
386
+ if (salary !== void 0) input.salary = salary;
387
+ if (performanceScore !== void 0) input.performanceScore = performanceScore;
388
+ if (startDate !== void 0) input.startDate = startDate;
389
+ if (managerId !== void 0) input.managerId = managerId;
390
+ if (avatar !== void 0) input.avatar = avatar;
391
+ if (Object.keys(input).length === 0) {
392
+ return errorResult("No updates specified \u2014 provide at least one mutable field");
393
+ }
394
+ const data = await ctx.gql.workspace.request(UPDATE_EMPLOYEE, { id, input });
395
+ return jsonResult(data.updateCrewEmployee);
396
+ } catch (error) {
397
+ ctx.logger.error("crewfoundry employees_update failed", { error: String(error) });
398
+ return errorResult(
399
+ `Failed to update employee: ${error instanceof Error ? error.message : String(error)}`
400
+ );
401
+ }
402
+ }
403
+ );
404
+ server.registerTool(
405
+ track(mcpToolName(ctx.productName, "employees_remove")),
406
+ {
407
+ title: "Remove Employee",
408
+ description: "Remove (offboard) an employee from the workspace directory.",
409
+ inputSchema: { id: z.string().describe("Employee ID") }
410
+ },
411
+ async ({ id }) => {
412
+ try {
413
+ const data = await ctx.gql.workspace.request(
414
+ REMOVE_EMPLOYEE,
415
+ { id }
416
+ );
417
+ return jsonResult({ ok: data.removeCrewEmployee, id });
418
+ } catch (error) {
419
+ ctx.logger.error("crewfoundry employees_remove failed", { error: String(error) });
420
+ return errorResult(
421
+ `Failed to remove employee: ${error instanceof Error ? error.message : String(error)}`
422
+ );
423
+ }
424
+ }
425
+ );
426
+ server.registerTool(
427
+ track(mcpToolName(ctx.productName, "departments_list")),
428
+ {
429
+ title: "List Departments",
430
+ description: "List all departments in the bound workspace.",
431
+ inputSchema: {}
432
+ },
433
+ async () => {
434
+ try {
435
+ const data = await ctx.gql.workspace.request(LIST_DEPARTMENTS, {});
436
+ return jsonResult(data.crewfoundryBootstrap.departments);
437
+ } catch (error) {
438
+ ctx.logger.error("crewfoundry departments_list failed", { error: String(error) });
439
+ return errorResult(
440
+ `Failed to list departments: ${error instanceof Error ? error.message : String(error)}`
441
+ );
442
+ }
443
+ }
444
+ );
445
+ server.registerTool(
446
+ track(mcpToolName(ctx.productName, "teams_list")),
447
+ {
448
+ title: "List Teams",
449
+ description: "List all teams in the bound workspace.",
450
+ inputSchema: {}
451
+ },
452
+ async () => {
453
+ try {
454
+ const data = await ctx.gql.workspace.request(LIST_TEAMS, {});
455
+ return jsonResult(data.crewfoundryBootstrap.teams);
456
+ } catch (error) {
457
+ ctx.logger.error("crewfoundry teams_list failed", { error: String(error) });
458
+ return errorResult(
459
+ `Failed to list teams: ${error instanceof Error ? error.message : String(error)}`
460
+ );
461
+ }
462
+ }
463
+ );
464
+ }
465
+ function registerRecruitmentTools(server, ctx, track) {
466
+ server.registerTool(
467
+ track(mcpToolName(ctx.productName, "candidates_list")),
468
+ {
469
+ title: "List Candidates",
470
+ description: "List all recruitment candidates in the bound workspace.",
471
+ inputSchema: {}
472
+ },
473
+ async () => {
474
+ try {
475
+ const data = await ctx.gql.workspace.request(LIST_CANDIDATES, {});
476
+ return jsonResult(data.crewfoundryBootstrap.candidates);
477
+ } catch (error) {
478
+ ctx.logger.error("crewfoundry candidates_list failed", { error: String(error) });
479
+ return errorResult(
480
+ `Failed to list candidates: ${error instanceof Error ? error.message : String(error)}`
481
+ );
482
+ }
483
+ }
484
+ );
485
+ server.registerTool(
486
+ track(mcpToolName(ctx.productName, "candidates_create")),
487
+ {
488
+ title: "Create Candidate",
489
+ description: "Add a new recruitment candidate to the pipeline.",
490
+ inputSchema: {
491
+ firstName: z.string().min(1).describe("First name"),
492
+ lastName: z.string().min(1).describe("Last name"),
493
+ email: z.string().min(1).describe("Candidate email"),
494
+ phone: z.string().min(1).describe("Candidate phone"),
495
+ position: z.string().min(1).describe("Position applied for"),
496
+ experience: z.number().int().describe("Years of experience"),
497
+ rating: z.number().describe("Recruiter rating (e.g. 0\u20135)"),
498
+ source: z.string().min(1).describe('Sourcing channel, e.g. "referral" / "linkedin"'),
499
+ status: z.string().min(1).describe('Pipeline status, e.g. "applied" / "screening"'),
500
+ skills: z.array(z.string()).describe("Skill tags"),
501
+ appliedDate: IsoDateTime.describe("Applied date (ISO-8601)"),
502
+ currentCompany: z.string().optional().describe("Current employer"),
503
+ resumeUrl: z.string().optional().describe("Resume URL"),
504
+ notes: z.string().optional().describe("Recruiter notes")
505
+ }
506
+ },
507
+ async ({
508
+ firstName,
509
+ lastName,
510
+ email,
511
+ phone,
512
+ position,
513
+ experience,
514
+ rating,
515
+ source,
516
+ status,
517
+ skills,
518
+ appliedDate,
519
+ currentCompany,
520
+ resumeUrl,
521
+ notes
522
+ }) => {
523
+ try {
524
+ const input = {
525
+ firstName,
526
+ lastName,
527
+ email,
528
+ phone,
529
+ position,
530
+ experience,
531
+ rating,
532
+ source,
533
+ status,
534
+ skills,
535
+ appliedDate
536
+ };
537
+ if (currentCompany !== void 0) input.currentCompany = currentCompany;
538
+ if (resumeUrl !== void 0) input.resumeUrl = resumeUrl;
539
+ if (notes !== void 0) input.notes = notes;
540
+ const data = await ctx.gql.workspace.request(CREATE_CANDIDATE, { input });
541
+ return jsonResult(data.createCrewCandidate);
542
+ } catch (error) {
543
+ ctx.logger.error("crewfoundry candidates_create failed", { error: String(error) });
544
+ return errorResult(
545
+ `Failed to create candidate: ${error instanceof Error ? error.message : String(error)}`
546
+ );
547
+ }
548
+ }
549
+ );
550
+ server.registerTool(
551
+ track(mcpToolName(ctx.productName, "candidates_update")),
552
+ {
553
+ title: "Update Candidate",
554
+ description: "Update a candidate. At least one mutable field must be provided.",
555
+ inputSchema: {
556
+ id: z.string().describe("Candidate ID"),
557
+ firstName: z.string().optional().describe("Updated first name"),
558
+ lastName: z.string().optional().describe("Updated last name"),
559
+ email: z.string().optional().describe("Updated email"),
560
+ phone: z.string().optional().describe("Updated phone"),
561
+ position: z.string().optional().describe("Updated position"),
562
+ experience: z.number().int().optional().describe("Updated years of experience"),
563
+ rating: z.number().optional().describe("Updated rating"),
564
+ source: z.string().optional().describe("Updated sourcing channel"),
565
+ status: z.string().optional().describe("Updated pipeline status"),
566
+ skills: z.array(z.string()).optional().describe("Updated skill tags"),
567
+ appliedDate: IsoDateTime.optional().describe("Updated applied date (ISO-8601)"),
568
+ currentCompany: z.string().optional().describe("Updated current employer"),
569
+ resumeUrl: z.string().optional().describe("Updated resume URL"),
570
+ notes: z.string().optional().describe("Updated recruiter notes")
571
+ }
572
+ },
573
+ async ({
574
+ id,
575
+ firstName,
576
+ lastName,
577
+ email,
578
+ phone,
579
+ position,
580
+ experience,
581
+ rating,
582
+ source,
583
+ status,
584
+ skills,
585
+ appliedDate,
586
+ currentCompany,
587
+ resumeUrl,
588
+ notes
589
+ }) => {
590
+ try {
591
+ const input = {};
592
+ if (firstName !== void 0) input.firstName = firstName;
593
+ if (lastName !== void 0) input.lastName = lastName;
594
+ if (email !== void 0) input.email = email;
595
+ if (phone !== void 0) input.phone = phone;
596
+ if (position !== void 0) input.position = position;
597
+ if (experience !== void 0) input.experience = experience;
598
+ if (rating !== void 0) input.rating = rating;
599
+ if (source !== void 0) input.source = source;
600
+ if (status !== void 0) input.status = status;
601
+ if (skills !== void 0) input.skills = skills;
602
+ if (appliedDate !== void 0) input.appliedDate = appliedDate;
603
+ if (currentCompany !== void 0) input.currentCompany = currentCompany;
604
+ if (resumeUrl !== void 0) input.resumeUrl = resumeUrl;
605
+ if (notes !== void 0) input.notes = notes;
606
+ if (Object.keys(input).length === 0) {
607
+ return errorResult("No updates specified \u2014 provide at least one mutable field");
608
+ }
609
+ const data = await ctx.gql.workspace.request(UPDATE_CANDIDATE, { id, input });
610
+ return jsonResult(data.updateCrewCandidate);
611
+ } catch (error) {
612
+ ctx.logger.error("crewfoundry candidates_update failed", { error: String(error) });
613
+ return errorResult(
614
+ `Failed to update candidate: ${error instanceof Error ? error.message : String(error)}`
615
+ );
616
+ }
617
+ }
618
+ );
619
+ server.registerTool(
620
+ track(mcpToolName(ctx.productName, "job_postings_list")),
621
+ {
622
+ title: "List Job Postings",
623
+ description: "List all job postings in the bound workspace.",
624
+ inputSchema: {}
625
+ },
626
+ async () => {
627
+ try {
628
+ const data = await ctx.gql.workspace.request(LIST_JOB_POSTINGS, {});
629
+ return jsonResult(data.crewfoundryBootstrap.jobPostings);
630
+ } catch (error) {
631
+ ctx.logger.error("crewfoundry job_postings_list failed", { error: String(error) });
632
+ return errorResult(
633
+ `Failed to list job postings: ${error instanceof Error ? error.message : String(error)}`
634
+ );
635
+ }
636
+ }
637
+ );
638
+ server.registerTool(
639
+ track(mcpToolName(ctx.productName, "job_postings_create")),
640
+ {
641
+ title: "Create Job Posting",
642
+ description: "Open a new job posting / requisition.",
643
+ inputSchema: {
644
+ title: z.string().min(1).describe("Job title"),
645
+ department: z.string().min(1).describe("Department"),
646
+ location: z.string().min(1).describe("Work location"),
647
+ type: z.string().min(1).describe('Employment type, e.g. "full-time"'),
648
+ experienceLevel: z.string().min(1).describe('Experience level, e.g. "senior"'),
649
+ description: z.string().min(1).describe("Role description"),
650
+ requirements: z.array(z.string()).describe("Requirement bullet points"),
651
+ benefits: z.array(z.string()).describe("Benefit bullet points"),
652
+ salaryMin: z.number().describe("Minimum salary"),
653
+ salaryMax: z.number().describe("Maximum salary"),
654
+ status: z.string().min(1).describe('Posting status, e.g. "open" / "closed"'),
655
+ applicants: z.number().int().describe("Current applicant count"),
656
+ postedDate: IsoDateTime.describe("Posted date (ISO-8601)"),
657
+ deadline: IsoDateTime.optional().describe("Application deadline (ISO-8601)")
658
+ }
659
+ },
660
+ async ({
661
+ title,
662
+ department,
663
+ location,
664
+ type,
665
+ experienceLevel,
666
+ description,
667
+ requirements,
668
+ benefits,
669
+ salaryMin,
670
+ salaryMax,
671
+ status,
672
+ applicants,
673
+ postedDate,
674
+ deadline
675
+ }) => {
676
+ try {
677
+ const input = {
678
+ title,
679
+ department,
680
+ location,
681
+ type,
682
+ experienceLevel,
683
+ description,
684
+ requirements,
685
+ benefits,
686
+ salaryMin,
687
+ salaryMax,
688
+ status,
689
+ applicants,
690
+ postedDate
691
+ };
692
+ if (deadline !== void 0) input.deadline = deadline;
693
+ const data = await ctx.gql.workspace.request(CREATE_JOB_POSTING, { input });
694
+ return jsonResult(data.createCrewJobPosting);
695
+ } catch (error) {
696
+ ctx.logger.error("crewfoundry job_postings_create failed", { error: String(error) });
697
+ return errorResult(
698
+ `Failed to create job posting: ${error instanceof Error ? error.message : String(error)}`
699
+ );
700
+ }
701
+ }
702
+ );
703
+ server.registerTool(
704
+ track(mcpToolName(ctx.productName, "job_postings_update")),
705
+ {
706
+ title: "Update Job Posting",
707
+ description: "Update a job posting. At least one mutable field must be provided.",
708
+ inputSchema: {
709
+ id: z.string().describe("Job posting ID"),
710
+ title: z.string().optional().describe("Updated title"),
711
+ department: z.string().optional().describe("Updated department"),
712
+ location: z.string().optional().describe("Updated location"),
713
+ type: z.string().optional().describe("Updated employment type"),
714
+ experienceLevel: z.string().optional().describe("Updated experience level"),
715
+ description: z.string().optional().describe("Updated description"),
716
+ requirements: z.array(z.string()).optional().describe("Updated requirements"),
717
+ benefits: z.array(z.string()).optional().describe("Updated benefits"),
718
+ salaryMin: z.number().optional().describe("Updated minimum salary"),
719
+ salaryMax: z.number().optional().describe("Updated maximum salary"),
720
+ status: z.string().optional().describe("Updated status"),
721
+ applicants: z.number().int().optional().describe("Updated applicant count"),
722
+ postedDate: IsoDateTime.optional().describe("Updated posted date (ISO-8601)"),
723
+ deadline: IsoDateTime.optional().describe("Updated deadline (ISO-8601)")
724
+ }
725
+ },
726
+ async ({
727
+ id,
728
+ title,
729
+ department,
730
+ location,
731
+ type,
732
+ experienceLevel,
733
+ description,
734
+ requirements,
735
+ benefits,
736
+ salaryMin,
737
+ salaryMax,
738
+ status,
739
+ applicants,
740
+ postedDate,
741
+ deadline
742
+ }) => {
743
+ try {
744
+ const input = {};
745
+ if (title !== void 0) input.title = title;
746
+ if (department !== void 0) input.department = department;
747
+ if (location !== void 0) input.location = location;
748
+ if (type !== void 0) input.type = type;
749
+ if (experienceLevel !== void 0) input.experienceLevel = experienceLevel;
750
+ if (description !== void 0) input.description = description;
751
+ if (requirements !== void 0) input.requirements = requirements;
752
+ if (benefits !== void 0) input.benefits = benefits;
753
+ if (salaryMin !== void 0) input.salaryMin = salaryMin;
754
+ if (salaryMax !== void 0) input.salaryMax = salaryMax;
755
+ if (status !== void 0) input.status = status;
756
+ if (applicants !== void 0) input.applicants = applicants;
757
+ if (postedDate !== void 0) input.postedDate = postedDate;
758
+ if (deadline !== void 0) input.deadline = deadline;
759
+ if (Object.keys(input).length === 0) {
760
+ return errorResult("No updates specified \u2014 provide at least one mutable field");
761
+ }
762
+ const data = await ctx.gql.workspace.request(UPDATE_JOB_POSTING, { id, input });
763
+ return jsonResult(data.updateCrewJobPosting);
764
+ } catch (error) {
765
+ ctx.logger.error("crewfoundry job_postings_update failed", { error: String(error) });
766
+ return errorResult(
767
+ `Failed to update job posting: ${error instanceof Error ? error.message : String(error)}`
768
+ );
769
+ }
770
+ }
771
+ );
772
+ server.registerTool(
773
+ track(mcpToolName(ctx.productName, "interviews_list")),
774
+ {
775
+ title: "List Interviews",
776
+ description: "List all scheduled interviews in the bound workspace.",
777
+ inputSchema: {}
778
+ },
779
+ async () => {
780
+ try {
781
+ const data = await ctx.gql.workspace.request(LIST_INTERVIEWS, {});
782
+ return jsonResult(data.crewfoundryBootstrap.interviews);
783
+ } catch (error) {
784
+ ctx.logger.error("crewfoundry interviews_list failed", { error: String(error) });
785
+ return errorResult(
786
+ `Failed to list interviews: ${error instanceof Error ? error.message : String(error)}`
787
+ );
788
+ }
789
+ }
790
+ );
791
+ }
792
+ function registerAttendanceTools(server, ctx, track) {
793
+ server.registerTool(
794
+ track(mcpToolName(ctx.productName, "leave_requests_list")),
795
+ {
796
+ title: "List Leave Requests",
797
+ description: "List all leave requests in the bound workspace.",
798
+ inputSchema: {}
799
+ },
800
+ async () => {
801
+ try {
802
+ const data = await ctx.gql.workspace.request(LIST_LEAVE_REQUESTS, {});
803
+ return jsonResult(data.crewfoundryBootstrap.leaveRequests);
804
+ } catch (error) {
805
+ ctx.logger.error("crewfoundry leave_requests_list failed", { error: String(error) });
806
+ return errorResult(
807
+ `Failed to list leave requests: ${error instanceof Error ? error.message : String(error)}`
808
+ );
809
+ }
810
+ }
811
+ );
812
+ server.registerTool(
813
+ track(mcpToolName(ctx.productName, "leave_requests_create")),
814
+ {
815
+ title: "Create Leave Request",
816
+ description: "File a new leave request for an employee.",
817
+ inputSchema: {
818
+ employeeId: z.string().min(1).describe("Employee ID"),
819
+ employeeName: z.string().min(1).describe("Employee display name"),
820
+ department: z.string().min(1).describe("Department"),
821
+ type: z.string().min(1).describe('Leave type, e.g. "annual" / "sick"'),
822
+ startDate: IsoDateTime.describe("Leave start date (ISO-8601)"),
823
+ endDate: IsoDateTime.describe("Leave end date (ISO-8601)"),
824
+ days: z.number().int().describe("Number of leave days"),
825
+ reason: z.string().min(1).describe("Reason for leave"),
826
+ status: z.string().min(1).describe('Status, e.g. "pending" / "approved"'),
827
+ approverName: z.string().optional().describe("Approver display name")
828
+ }
829
+ },
830
+ async ({
831
+ employeeId,
832
+ employeeName,
833
+ department,
834
+ type,
835
+ startDate,
836
+ endDate,
837
+ days,
838
+ reason,
839
+ status,
840
+ approverName
841
+ }) => {
842
+ try {
843
+ const input = {
844
+ employeeId,
845
+ employeeName,
846
+ department,
847
+ type,
848
+ startDate,
849
+ endDate,
850
+ days,
851
+ reason,
852
+ status
853
+ };
854
+ if (approverName !== void 0) input.approverName = approverName;
855
+ const data = await ctx.gql.workspace.request(CREATE_LEAVE_REQUEST, { input });
856
+ return jsonResult(data.createCrewLeaveRequest);
857
+ } catch (error) {
858
+ ctx.logger.error("crewfoundry leave_requests_create failed", { error: String(error) });
859
+ return errorResult(
860
+ `Failed to create leave request: ${error instanceof Error ? error.message : String(error)}`
861
+ );
862
+ }
863
+ }
864
+ );
865
+ server.registerTool(
866
+ track(mcpToolName(ctx.productName, "leave_requests_update")),
867
+ {
868
+ title: "Update Leave Request",
869
+ description: "Update a leave request (e.g. approve/reject by setting status + approverName). At least one mutable field must be provided.",
870
+ inputSchema: {
871
+ id: z.string().describe("Leave request ID"),
872
+ employeeId: z.string().optional().describe("Updated employee ID"),
873
+ employeeName: z.string().optional().describe("Updated employee name"),
874
+ department: z.string().optional().describe("Updated department"),
875
+ type: z.string().optional().describe("Updated leave type"),
876
+ startDate: IsoDateTime.optional().describe("Updated start date (ISO-8601)"),
877
+ endDate: IsoDateTime.optional().describe("Updated end date (ISO-8601)"),
878
+ days: z.number().int().optional().describe("Updated number of days"),
879
+ reason: z.string().optional().describe("Updated reason"),
880
+ status: z.string().optional().describe('Updated status, e.g. "approved" / "rejected"'),
881
+ approverName: z.string().optional().describe("Updated approver name")
882
+ }
883
+ },
884
+ async ({
885
+ id,
886
+ employeeId,
887
+ employeeName,
888
+ department,
889
+ type,
890
+ startDate,
891
+ endDate,
892
+ days,
893
+ reason,
894
+ status,
895
+ approverName
896
+ }) => {
897
+ try {
898
+ const input = {};
899
+ if (employeeId !== void 0) input.employeeId = employeeId;
900
+ if (employeeName !== void 0) input.employeeName = employeeName;
901
+ if (department !== void 0) input.department = department;
902
+ if (type !== void 0) input.type = type;
903
+ if (startDate !== void 0) input.startDate = startDate;
904
+ if (endDate !== void 0) input.endDate = endDate;
905
+ if (days !== void 0) input.days = days;
906
+ if (reason !== void 0) input.reason = reason;
907
+ if (status !== void 0) input.status = status;
908
+ if (approverName !== void 0) input.approverName = approverName;
909
+ if (Object.keys(input).length === 0) {
910
+ return errorResult("No updates specified \u2014 provide at least one mutable field");
911
+ }
912
+ const data = await ctx.gql.workspace.request(UPDATE_LEAVE_REQUEST, { id, input });
913
+ return jsonResult(data.updateCrewLeaveRequest);
914
+ } catch (error) {
915
+ ctx.logger.error("crewfoundry leave_requests_update failed", { error: String(error) });
916
+ return errorResult(
917
+ `Failed to update leave request: ${error instanceof Error ? error.message : String(error)}`
918
+ );
919
+ }
920
+ }
921
+ );
922
+ server.registerTool(
923
+ track(mcpToolName(ctx.productName, "time_entries_list")),
924
+ {
925
+ title: "List Time Entries",
926
+ description: "List all clock-in/clock-out time entries in the bound workspace.",
927
+ inputSchema: {}
928
+ },
929
+ async () => {
930
+ try {
931
+ const data = await ctx.gql.workspace.request(LIST_TIME_ENTRIES, {});
932
+ return jsonResult(data.crewfoundryBootstrap.timeEntries);
933
+ } catch (error) {
934
+ ctx.logger.error("crewfoundry time_entries_list failed", { error: String(error) });
935
+ return errorResult(
936
+ `Failed to list time entries: ${error instanceof Error ? error.message : String(error)}`
937
+ );
938
+ }
939
+ }
940
+ );
941
+ server.registerTool(
942
+ track(mcpToolName(ctx.productName, "payroll_list")),
943
+ {
944
+ title: "List Payroll Records",
945
+ description: "List all payroll records in the bound workspace.",
946
+ inputSchema: {}
947
+ },
948
+ async () => {
949
+ try {
950
+ const data = await ctx.gql.workspace.request(LIST_PAYROLL_RECORDS, {});
951
+ return jsonResult(data.crewfoundryBootstrap.payrollRecords);
952
+ } catch (error) {
953
+ ctx.logger.error("crewfoundry payroll_list failed", { error: String(error) });
954
+ return errorResult(
955
+ `Failed to list payroll records: ${error instanceof Error ? error.message : String(error)}`
956
+ );
957
+ }
958
+ }
959
+ );
960
+ }
961
+
962
+ // src/modules/crewfoundry/tools/clients.ts
963
+ function registerClientTools(server, ctx, track) {
964
+ server.registerTool(
965
+ track(mcpToolName(ctx.productName, "clients_list")),
966
+ {
967
+ title: "List Clients",
968
+ description: "List all clients in the bound workspace.",
969
+ inputSchema: {}
970
+ },
971
+ async () => {
972
+ try {
973
+ const data = await ctx.gql.workspace.request(LIST_CLIENTS, {});
974
+ return jsonResult(data.crewfoundryBootstrap.clients);
975
+ } catch (error) {
976
+ ctx.logger.error("crewfoundry clients_list failed", { error: String(error) });
977
+ return errorResult(
978
+ `Failed to list clients: ${error instanceof Error ? error.message : String(error)}`
979
+ );
980
+ }
981
+ }
982
+ );
983
+ server.registerTool(
984
+ track(mcpToolName(ctx.productName, "invoices_list")),
985
+ {
986
+ title: "List Invoices",
987
+ description: "List all invoices in the bound workspace.",
988
+ inputSchema: {}
989
+ },
990
+ async () => {
991
+ try {
992
+ const data = await ctx.gql.workspace.request(LIST_INVOICES, {});
993
+ return jsonResult(data.crewfoundryBootstrap.invoices);
994
+ } catch (error) {
995
+ ctx.logger.error("crewfoundry invoices_list failed", { error: String(error) });
996
+ return errorResult(
997
+ `Failed to list invoices: ${error instanceof Error ? error.message : String(error)}`
998
+ );
999
+ }
1000
+ }
1001
+ );
1002
+ server.registerTool(
1003
+ track(mcpToolName(ctx.productName, "projects_list")),
1004
+ {
1005
+ title: "List Projects",
1006
+ description: "List all projects in the bound workspace.",
1007
+ inputSchema: {}
1008
+ },
1009
+ async () => {
1010
+ try {
1011
+ const data = await ctx.gql.workspace.request(LIST_PROJECTS, {});
1012
+ return jsonResult(data.crewfoundryBootstrap.projects);
1013
+ } catch (error) {
1014
+ ctx.logger.error("crewfoundry projects_list failed", { error: String(error) });
1015
+ return errorResult(
1016
+ `Failed to list projects: ${error instanceof Error ? error.message : String(error)}`
1017
+ );
1018
+ }
1019
+ }
1020
+ );
1021
+ server.registerTool(
1022
+ track(mcpToolName(ctx.productName, "vendors_list")),
1023
+ {
1024
+ title: "List Vendors",
1025
+ description: "List all vendors in the bound workspace.",
1026
+ inputSchema: {}
1027
+ },
1028
+ async () => {
1029
+ try {
1030
+ const data = await ctx.gql.workspace.request(LIST_VENDORS, {});
1031
+ return jsonResult(data.crewfoundryBootstrap.vendors);
1032
+ } catch (error) {
1033
+ ctx.logger.error("crewfoundry vendors_list failed", { error: String(error) });
1034
+ return errorResult(
1035
+ `Failed to list vendors: ${error instanceof Error ? error.message : String(error)}`
1036
+ );
1037
+ }
1038
+ }
1039
+ );
1040
+ server.registerTool(
1041
+ track(mcpToolName(ctx.productName, "marketplace_services_list")),
1042
+ {
1043
+ title: "List Marketplace Services",
1044
+ description: "List all marketplace services offered in the bound workspace.",
1045
+ inputSchema: {}
1046
+ },
1047
+ async () => {
1048
+ try {
1049
+ const data = await ctx.gql.workspace.request(LIST_MARKETPLACE_SERVICES, {});
1050
+ return jsonResult(data.crewfoundryBootstrap.marketplaceServices);
1051
+ } catch (error) {
1052
+ ctx.logger.error("crewfoundry marketplace_services_list failed", { error: String(error) });
1053
+ return errorResult(
1054
+ `Failed to list marketplace services: ${error instanceof Error ? error.message : String(error)}`
1055
+ );
1056
+ }
1057
+ }
1058
+ );
1059
+ }
1060
+
1061
+ // src/modules/crewfoundry/tools/learning.ts
1062
+ function registerLearningTools(server, ctx, track) {
1063
+ server.registerTool(
1064
+ track(mcpToolName(ctx.productName, "courses_list")),
1065
+ {
1066
+ title: "List Courses",
1067
+ description: "List all learning courses in the bound workspace.",
1068
+ inputSchema: {}
1069
+ },
1070
+ async () => {
1071
+ try {
1072
+ const data = await ctx.gql.workspace.request(LIST_COURSES, {});
1073
+ return jsonResult(data.crewfoundryBootstrap.courses);
1074
+ } catch (error) {
1075
+ ctx.logger.error("crewfoundry courses_list failed", { error: String(error) });
1076
+ return errorResult(
1077
+ `Failed to list courses: ${error instanceof Error ? error.message : String(error)}`
1078
+ );
1079
+ }
1080
+ }
1081
+ );
1082
+ server.registerTool(
1083
+ track(mcpToolName(ctx.productName, "learning_paths_list")),
1084
+ {
1085
+ title: "List Learning Paths",
1086
+ description: "List all learning paths in the bound workspace.",
1087
+ inputSchema: {}
1088
+ },
1089
+ async () => {
1090
+ try {
1091
+ const data = await ctx.gql.workspace.request(LIST_LEARNING_PATHS, {});
1092
+ return jsonResult(data.crewfoundryBootstrap.learningPaths);
1093
+ } catch (error) {
1094
+ ctx.logger.error("crewfoundry learning_paths_list failed", { error: String(error) });
1095
+ return errorResult(
1096
+ `Failed to list learning paths: ${error instanceof Error ? error.message : String(error)}`
1097
+ );
1098
+ }
1099
+ }
1100
+ );
1101
+ }
1102
+ function registerEngagementTools(server, ctx, track) {
1103
+ server.registerTool(
1104
+ track(mcpToolName(ctx.productName, "announcements_list")),
1105
+ {
1106
+ title: "List Announcements",
1107
+ description: "List all crew announcements in the bound workspace.",
1108
+ inputSchema: {}
1109
+ },
1110
+ async () => {
1111
+ try {
1112
+ const data = await ctx.gql.workspace.request(LIST_ANNOUNCEMENTS, {});
1113
+ return jsonResult(data.crewfoundryBootstrap.announcements);
1114
+ } catch (error) {
1115
+ ctx.logger.error("crewfoundry announcements_list failed", { error: String(error) });
1116
+ return errorResult(
1117
+ `Failed to list announcements: ${error instanceof Error ? error.message : String(error)}`
1118
+ );
1119
+ }
1120
+ }
1121
+ );
1122
+ server.registerTool(
1123
+ track(mcpToolName(ctx.productName, "announcements_create")),
1124
+ {
1125
+ title: "Create Announcement",
1126
+ description: "Publish a new crew announcement.",
1127
+ inputSchema: {
1128
+ title: z.string().min(1).describe("Announcement title"),
1129
+ content: z.string().min(1).describe("Announcement body"),
1130
+ author: z.string().min(1).describe("Author display name"),
1131
+ authorRole: z.string().min(1).describe("Author role / title"),
1132
+ category: z.string().min(1).describe('Category, e.g. "policy" / "event"'),
1133
+ priority: z.string().min(1).describe('Priority, e.g. "low" / "high"'),
1134
+ isPinned: z.boolean().describe("Whether the announcement is pinned"),
1135
+ tags: z.array(z.string()).describe("Tag labels"),
1136
+ viewCount: z.number().int().describe("Initial view count (typically 0)"),
1137
+ createdAt: IsoDateTime.describe("Creation timestamp (ISO-8601)")
1138
+ }
1139
+ },
1140
+ async ({
1141
+ title,
1142
+ content,
1143
+ author,
1144
+ authorRole,
1145
+ category,
1146
+ priority,
1147
+ isPinned,
1148
+ tags,
1149
+ viewCount,
1150
+ createdAt
1151
+ }) => {
1152
+ try {
1153
+ const input = {
1154
+ title,
1155
+ content,
1156
+ author,
1157
+ authorRole,
1158
+ category,
1159
+ priority,
1160
+ isPinned,
1161
+ tags,
1162
+ viewCount,
1163
+ createdAt
1164
+ };
1165
+ const data = await ctx.gql.workspace.request(CREATE_ANNOUNCEMENT, { input });
1166
+ return jsonResult(data.createCrewAnnouncement);
1167
+ } catch (error) {
1168
+ ctx.logger.error("crewfoundry announcements_create failed", { error: String(error) });
1169
+ return errorResult(
1170
+ `Failed to create announcement: ${error instanceof Error ? error.message : String(error)}`
1171
+ );
1172
+ }
1173
+ }
1174
+ );
1175
+ server.registerTool(
1176
+ track(mcpToolName(ctx.productName, "notifications_list")),
1177
+ {
1178
+ title: "List Notifications",
1179
+ description: "List all notifications in the bound workspace.",
1180
+ inputSchema: {}
1181
+ },
1182
+ async () => {
1183
+ try {
1184
+ const data = await ctx.gql.workspace.request(LIST_NOTIFICATIONS, {});
1185
+ return jsonResult(data.crewfoundryBootstrap.notifications);
1186
+ } catch (error) {
1187
+ ctx.logger.error("crewfoundry notifications_list failed", { error: String(error) });
1188
+ return errorResult(
1189
+ `Failed to list notifications: ${error instanceof Error ? error.message : String(error)}`
1190
+ );
1191
+ }
1192
+ }
1193
+ );
1194
+ server.registerTool(
1195
+ track(mcpToolName(ctx.productName, "notifications_mark_read")),
1196
+ {
1197
+ title: "Mark Notification Read",
1198
+ description: "Mark a single notification as read.",
1199
+ inputSchema: { id: z.string().describe("Notification ID") }
1200
+ },
1201
+ async ({ id }) => {
1202
+ try {
1203
+ const data = await ctx.gql.workspace.request(
1204
+ MARK_NOTIFICATION_READ,
1205
+ { id }
1206
+ );
1207
+ return jsonResult({ ok: data.markCrewNotificationRead, id });
1208
+ } catch (error) {
1209
+ ctx.logger.error("crewfoundry notifications_mark_read failed", { error: String(error) });
1210
+ return errorResult(
1211
+ `Failed to mark notification read: ${error instanceof Error ? error.message : String(error)}`
1212
+ );
1213
+ }
1214
+ }
1215
+ );
1216
+ server.registerTool(
1217
+ track(mcpToolName(ctx.productName, "notifications_mark_all_read")),
1218
+ {
1219
+ title: "Mark All Notifications Read",
1220
+ description: "Mark every notification in the bound workspace as read.",
1221
+ inputSchema: {}
1222
+ },
1223
+ async () => {
1224
+ try {
1225
+ const data = await ctx.gql.workspace.request(
1226
+ MARK_ALL_NOTIFICATIONS_READ,
1227
+ {}
1228
+ );
1229
+ return jsonResult({ ok: data.markAllCrewNotificationsRead });
1230
+ } catch (error) {
1231
+ ctx.logger.error("crewfoundry notifications_mark_all_read failed", {
1232
+ error: String(error)
1233
+ });
1234
+ return errorResult(
1235
+ `Failed to mark all notifications read: ${error instanceof Error ? error.message : String(error)}`
1236
+ );
1237
+ }
1238
+ }
1239
+ );
1240
+ }
1241
+
1242
+ // src/modules/crewfoundry/tools/overview.ts
1243
+ function registerOverviewTools(server, ctx, track) {
1244
+ server.registerTool(
1245
+ track(mcpToolName(ctx.productName, "overview")),
1246
+ {
1247
+ title: "Crewfoundry Overview",
1248
+ description: "Single-call snapshot of the bound workspace \u2014 every crewfoundry collection (people, recruitment, attendance, clients/delivery, learning, engagement) in one response.",
1249
+ inputSchema: {}
1250
+ },
1251
+ async () => {
1252
+ try {
1253
+ const data = await ctx.gql.workspace.request(BOOTSTRAP_OVERVIEW, {});
1254
+ return jsonResult(data.crewfoundryBootstrap);
1255
+ } catch (error) {
1256
+ ctx.logger.error("crewfoundry overview failed", { error: String(error) });
1257
+ return errorResult(
1258
+ `Failed to get crewfoundry overview: ${error instanceof Error ? error.message : String(error)}`
1259
+ );
1260
+ }
1261
+ }
1262
+ );
1263
+ }
1264
+
1265
+ // src/modules/crewfoundry/resources.ts
1266
+ function registerCrewfoundryResources(server, ctx, track) {
1267
+ const schemaUri = track(mcpResourceUri(ctx.productName, "schema"));
1268
+ const overviewUri = track(mcpResourceUri(ctx.productName, "overview"));
1269
+ const employeesUri = track(mcpResourceUri(ctx.productName, "employees"));
1270
+ const announcementsUri = track(mcpResourceUri(ctx.productName, "announcements"));
1271
+ server.registerResource(
1272
+ "crewfoundry-schema",
1273
+ schemaUri,
1274
+ {
1275
+ title: "Crewfoundry Domain Schema",
1276
+ description: "Overview of the Crewfoundry workforce/HR domain \u2014 entities and the per-entity tool surface.",
1277
+ mimeType: "text/plain"
1278
+ },
1279
+ async () => {
1280
+ ctx.logger.debug(`Resource ${schemaUri} requested`);
1281
+ const schema = `# Crewfoundry Domain (Overview)
1282
+
1283
+ Workforce / HR / crew-operations platform.
1284
+
1285
+ ## Read model
1286
+ All collections are served by a single \`crewfoundryBootstrap\` query; each list
1287
+ tool selects only the collection it needs from it. The \`overview\` tool returns
1288
+ the whole bootstrap in one call.
1289
+
1290
+ ## Entities
1291
+ - CrewEmployee \u2014 workforce directory (create/update/remove)
1292
+ - CrewDepartment, CrewTeam \u2014 org structure (read-only)
1293
+ - CrewCandidate \u2014 recruitment pipeline (create/update)
1294
+ - CrewJobPosting \u2014 open requisitions (create/update)
1295
+ - CrewInterview \u2014 scheduled interviews (read-only)
1296
+ - CrewLeaveRequest \u2014 time-off requests (create/update)
1297
+ - CrewTimeEntry \u2014 clock-in/out entries (read-only)
1298
+ - CrewPayrollRecord \u2014 payroll runs (read-only)
1299
+ - CrewClient, CrewInvoice, CrewProject, CrewVendor, CrewMarketplaceService \u2014 delivery side (read-only)
1300
+ - CrewCourse, CrewLearningPath \u2014 learning & development (read-only)
1301
+ - CrewAnnouncement \u2014 internal announcements (create)
1302
+ - CrewNotification \u2014 user notifications (mark read / mark all read)
1303
+
1304
+ ## Tool groups
1305
+ people, recruitment, attendance, clients, learning, engagement, overview.
1306
+ All run against the WORKSPACE gateway (workspace-scoped).
1307
+ `;
1308
+ return {
1309
+ contents: [{ uri: schemaUri, text: schema, mimeType: "text/plain" }]
1310
+ };
1311
+ }
1312
+ );
1313
+ server.registerResource(
1314
+ "crewfoundry-overview",
1315
+ overviewUri,
1316
+ {
1317
+ title: "Crewfoundry Workspace Snapshot",
1318
+ description: "Live single-call snapshot of every crewfoundry collection in the bound workspace.",
1319
+ mimeType: "application/json"
1320
+ },
1321
+ async () => {
1322
+ ctx.logger.debug(`Resource ${overviewUri} requested`);
1323
+ try {
1324
+ const data = await ctx.gql.workspace.request(
1325
+ BOOTSTRAP_OVERVIEW,
1326
+ {}
1327
+ );
1328
+ return {
1329
+ contents: [
1330
+ {
1331
+ uri: overviewUri,
1332
+ text: JSON.stringify(data.crewfoundryBootstrap, null, 2),
1333
+ mimeType: "application/json"
1334
+ }
1335
+ ]
1336
+ };
1337
+ } catch (error) {
1338
+ return {
1339
+ contents: [
1340
+ {
1341
+ uri: overviewUri,
1342
+ text: JSON.stringify({
1343
+ error: error instanceof Error ? error.message : String(error)
1344
+ }),
1345
+ mimeType: "application/json"
1346
+ }
1347
+ ]
1348
+ };
1349
+ }
1350
+ }
1351
+ );
1352
+ server.registerResource(
1353
+ "crewfoundry-employees",
1354
+ employeesUri,
1355
+ {
1356
+ title: "Crewfoundry Employee Directory",
1357
+ description: "The employee directory in the bound workspace.",
1358
+ mimeType: "application/json"
1359
+ },
1360
+ async () => {
1361
+ ctx.logger.debug(`Resource ${employeesUri} requested`);
1362
+ try {
1363
+ const data = await ctx.gql.workspace.request(LIST_EMPLOYEES, {});
1364
+ return {
1365
+ contents: [
1366
+ {
1367
+ uri: employeesUri,
1368
+ text: JSON.stringify(data.crewfoundryBootstrap.employees, null, 2),
1369
+ mimeType: "application/json"
1370
+ }
1371
+ ]
1372
+ };
1373
+ } catch (error) {
1374
+ return {
1375
+ contents: [
1376
+ {
1377
+ uri: employeesUri,
1378
+ text: JSON.stringify({
1379
+ error: error instanceof Error ? error.message : String(error)
1380
+ }),
1381
+ mimeType: "application/json"
1382
+ }
1383
+ ]
1384
+ };
1385
+ }
1386
+ }
1387
+ );
1388
+ server.registerResource(
1389
+ "crewfoundry-announcements",
1390
+ announcementsUri,
1391
+ {
1392
+ title: "Crewfoundry Announcements",
1393
+ description: "The crew announcements feed in the bound workspace.",
1394
+ mimeType: "application/json"
1395
+ },
1396
+ async () => {
1397
+ ctx.logger.debug(`Resource ${announcementsUri} requested`);
1398
+ try {
1399
+ const data = await ctx.gql.workspace.request(LIST_ANNOUNCEMENTS, {});
1400
+ return {
1401
+ contents: [
1402
+ {
1403
+ uri: announcementsUri,
1404
+ text: JSON.stringify(data.crewfoundryBootstrap.announcements, null, 2),
1405
+ mimeType: "application/json"
1406
+ }
1407
+ ]
1408
+ };
1409
+ } catch (error) {
1410
+ return {
1411
+ contents: [
1412
+ {
1413
+ uri: announcementsUri,
1414
+ text: JSON.stringify({
1415
+ error: error instanceof Error ? error.message : String(error)
1416
+ }),
1417
+ mimeType: "application/json"
1418
+ }
1419
+ ]
1420
+ };
1421
+ }
1422
+ }
1423
+ );
1424
+ }
1425
+ function registerCrewfoundryPrompts(server, ctx, track) {
1426
+ const p = ctx.productName;
1427
+ const onboardingName = track(mcpPromptName(p, "employee-onboarding"));
1428
+ const opsName = track(mcpPromptName(p, "hr-ops"));
1429
+ server.registerPrompt(
1430
+ onboardingName,
1431
+ {
1432
+ title: "Employee Onboarding",
1433
+ description: "Guide for onboarding a new Crewfoundry employee end to end: confirm the department/team, create the employee record, and announce the hire.",
1434
+ argsSchema: {
1435
+ name: z.string().optional().describe("New hire full name"),
1436
+ department: z.string().optional().describe("Target department")
1437
+ }
1438
+ },
1439
+ ({ name, department }) => {
1440
+ ctx.logger.debug(`Prompt ${onboardingName} called`, { name, department });
1441
+ const nameNote = name ? `Use the name "${name}".` : "Ask the user for the new hire name.";
1442
+ const deptNote = department ? `Place them in the "${department}" department.` : `First list departments with ${p}_departments_list and pick one.`;
1443
+ return {
1444
+ messages: [
1445
+ {
1446
+ role: "user",
1447
+ content: {
1448
+ type: "text",
1449
+ text: `Help me onboard a new Crewfoundry employee.
1450
+
1451
+ 1. **Confirm Org**: ${deptNote} Optionally check teams with ${p}_teams_list.
1452
+ 2. **Create Employee**: Use ${p}_employees_create. ${nameNote} Set position, location, type (e.g. full-time), status=active, salary, performanceScore, and startDate (ISO-8601). Set managerId if known.
1453
+ 3. **Verify**: Use ${p}_employees_list to confirm the new record.
1454
+ 4. **(Optional) Announce**: Use ${p}_announcements_create to welcome the hire (category="people", priority="normal").
1455
+
1456
+ Show results at each step and confirm before announcing.`
1457
+ }
1458
+ }
1459
+ ]
1460
+ };
1461
+ }
1462
+ );
1463
+ server.registerPrompt(
1464
+ opsName,
1465
+ {
1466
+ title: "HR Operations",
1467
+ description: "Daily HR operations workflow: triage leave requests, review the hiring pipeline, check payroll/time, and clear notifications.",
1468
+ argsSchema: {
1469
+ department: z.string().optional().describe("Department to focus on")
1470
+ }
1471
+ },
1472
+ ({ department }) => {
1473
+ ctx.logger.debug(`Prompt ${opsName} called`, { department });
1474
+ const deptNote = department ? `Focus on the "${department}" department.` : "Cover the whole workspace.";
1475
+ return {
1476
+ messages: [
1477
+ {
1478
+ role: "user",
1479
+ content: {
1480
+ type: "text",
1481
+ text: `Run daily Crewfoundry HR operations. ${deptNote}
1482
+
1483
+ 1. **Snapshot**: Use ${p}_overview for a one-call read of the workspace.
1484
+ 2. **Leave Queue**: Use ${p}_leave_requests_list to find pending requests; approve/reject with ${p}_leave_requests_update (set status + approverName).
1485
+ 3. **Hiring Pipeline**: Use ${p}_candidates_list and ${p}_job_postings_list; check upcoming ${p}_interviews_list. Advance candidates with ${p}_candidates_update.
1486
+ 4. **Time & Payroll**: Use ${p}_time_entries_list and ${p}_payroll_list to spot anomalies.
1487
+ 5. **Notifications**: Use ${p}_notifications_list; clear them with ${p}_notifications_mark_read or ${p}_notifications_mark_all_read.
1488
+
1489
+ Summarize what needs attention after each step.`
1490
+ }
1491
+ }
1492
+ ]
1493
+ };
1494
+ }
1495
+ );
1496
+ }
1497
+
1498
+ // src/modules/crewfoundry/index.ts
1499
+ var crewfoundryModule = {
1500
+ id: "crewfoundry",
1501
+ version: "0.0.1",
1502
+ displayName: "Crewfoundry",
1503
+ dependsOn: ["auth"],
1504
+ capabilities: { tools: {}, resources: {}, prompts: {} },
1505
+ register(server, ctx) {
1506
+ const tools = [];
1507
+ const resources = [];
1508
+ const prompts = [];
1509
+ const trackTool = (n) => {
1510
+ tools.push(n);
1511
+ return n;
1512
+ };
1513
+ const trackResource = (uri) => {
1514
+ resources.push(uri);
1515
+ return uri;
1516
+ };
1517
+ const trackPrompt = (n) => {
1518
+ prompts.push(n);
1519
+ return n;
1520
+ };
1521
+ registerPeopleTools(server, ctx, trackTool);
1522
+ registerRecruitmentTools(server, ctx, trackTool);
1523
+ registerAttendanceTools(server, ctx, trackTool);
1524
+ registerClientTools(server, ctx, trackTool);
1525
+ registerLearningTools(server, ctx, trackTool);
1526
+ registerEngagementTools(server, ctx, trackTool);
1527
+ registerOverviewTools(server, ctx, trackTool);
1528
+ registerCrewfoundryResources(server, ctx, trackResource);
1529
+ registerCrewfoundryPrompts(server, ctx, trackPrompt);
1530
+ return { tools, resources, prompts };
1531
+ }
1532
+ };
1533
+ var crewfoundry_default = crewfoundryModule;
1534
+
1535
+ export { crewfoundry_default as default };
1536
+ //# sourceMappingURL=index.js.map
1537
+ //# sourceMappingURL=index.js.map