@burdenoff/mcp-libs 2026.529.1 → 2026.626.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.
@@ -0,0 +1,1406 @@
1
+ import { mcpToolName, errorResult, jsonResult, mcpResourceUri, mcpPromptName } from '../../chunk-H2OYWLOA.js';
2
+ import { z } from 'zod';
3
+
4
+ // src/modules/kadaikodi/operations.ts
5
+ var PROVIDER_FIELDS = `
6
+ id name slug description category status offeringType serviceTypes
7
+ location businessHours rating totalRatings averageOrderValue
8
+ analyticsSnapshot ownerId workspaceId createdAt updatedAt
9
+ `;
10
+ var OFFERING_FIELDS = `
11
+ id name slug description category kind price originalPrice durationMinutes
12
+ stock isAvailable serviceType media metadata tags providerId workspaceId
13
+ createdAt updatedAt
14
+ `;
15
+ var ORDER_ITEM_FIELDS = `
16
+ id orderId offeringId name quantity unitPrice totalPrice customizations workspaceId
17
+ `;
18
+ var ORDER_FIELDS = `
19
+ id orderNumber customerId providerId assignedWorkerId status paymentStatus
20
+ paymentMethod fulfillmentType subtotal tax discount deliveryFee total
21
+ deliveryAddress notes timeline workspaceId createdAt updatedAt
22
+ items { ${ORDER_ITEM_FIELDS} }
23
+ `;
24
+ var REVIEW_FIELDS = `
25
+ id providerId customerId orderId rating review response workspaceId
26
+ createdAt updatedAt
27
+ `;
28
+ var WORKER_FIELDS = `
29
+ id providerId workerId name role status metadata workspaceId
30
+ tasks { id title type status priority orderId dueAt completedAt }
31
+ `;
32
+ var TASK_FIELDS = `
33
+ id workerRefId title description type status priority orderId location
34
+ dueAt completedAt workspaceId
35
+ `;
36
+ var OPPORTUNITY_FIELDS = `
37
+ id providerId title description targetAmount raisedAmount minimumInvestment
38
+ expectedReturnsPct lockInMonths riskLevel status businessMetrics terms
39
+ expiresAt workspaceId createdAt updatedAt
40
+ `;
41
+ var INVESTMENT_TXN_FIELDS = `
42
+ id investmentId type amount notes createdAt workspaceId
43
+ `;
44
+ var INVESTMENT_FIELDS = `
45
+ id opportunityId investorId amount currentValue realizedReturns
46
+ expectedReturnsPct status investedAt maturedAt workspaceId
47
+ transactions { ${INVESTMENT_TXN_FIELDS} }
48
+ `;
49
+ var GET_SERVICE_PROVIDER = `
50
+ query KadaikodiGetServiceProvider($id: ID!) {
51
+ getServiceProvider(id: $id) {
52
+ ${PROVIDER_FIELDS}
53
+ offerings { id name slug kind price isAvailable }
54
+ workers { id name role status }
55
+ investmentOpportunities { id title status targetAmount raisedAmount }
56
+ }
57
+ }
58
+ `;
59
+ var LIST_SERVICE_PROVIDERS = `
60
+ query KadaikodiListServiceProviders(
61
+ $filter: KadaikodiProviderFilterInput
62
+ $limit: Int
63
+ $offset: Int
64
+ ) {
65
+ listServiceProviders(filter: $filter, limit: $limit, offset: $offset) {
66
+ ${PROVIDER_FIELDS}
67
+ }
68
+ }
69
+ `;
70
+ var CREATE_SERVICE_PROVIDER = `
71
+ mutation KadaikodiCreateServiceProvider($input: KadaikodiCreateServiceProviderInput!) {
72
+ kadaikodiCreateServiceProvider(input: $input) {
73
+ ${PROVIDER_FIELDS}
74
+ }
75
+ }
76
+ `;
77
+ var UPDATE_SERVICE_PROVIDER = `
78
+ mutation KadaikodiUpdateServiceProvider(
79
+ $id: ID!
80
+ $input: KadaikodiUpdateServiceProviderInput!
81
+ ) {
82
+ kadaikodiUpdateServiceProvider(id: $id, input: $input) {
83
+ ${PROVIDER_FIELDS}
84
+ }
85
+ }
86
+ `;
87
+ var LIST_PROVIDER_WORKERS = `
88
+ query KadaikodiListProviderWorkers($providerId: String!, $limit: Int, $offset: Int) {
89
+ listProviderWorkers(providerId: $providerId, limit: $limit, offset: $offset) {
90
+ ${WORKER_FIELDS}
91
+ }
92
+ }
93
+ `;
94
+ var LIST_WORKER_TASKS = `
95
+ query KadaikodiListWorkerTasks(
96
+ $workerRefId: String!
97
+ $status: String
98
+ $limit: Int
99
+ $offset: Int
100
+ ) {
101
+ listWorkerTasks(workerRefId: $workerRefId, status: $status, limit: $limit, offset: $offset) {
102
+ ${TASK_FIELDS}
103
+ }
104
+ }
105
+ `;
106
+ var GET_OFFERING = `
107
+ query KadaikodiGetOffering($id: ID!) {
108
+ getOffering(id: $id) {
109
+ ${OFFERING_FIELDS}
110
+ }
111
+ }
112
+ `;
113
+ var LIST_OFFERINGS = `
114
+ query KadaikodiListOfferings(
115
+ $kind: KadaikodiOfferingKind
116
+ $providerId: String
117
+ $limit: Int
118
+ $offset: Int
119
+ ) {
120
+ listOfferings(kind: $kind, providerId: $providerId, limit: $limit, offset: $offset) {
121
+ ${OFFERING_FIELDS}
122
+ }
123
+ }
124
+ `;
125
+ var CREATE_OFFERING = `
126
+ mutation KadaikodiCreateOffering($input: KadaikodiCreateOfferingInput!) {
127
+ createOffering(input: $input) {
128
+ ${OFFERING_FIELDS}
129
+ }
130
+ }
131
+ `;
132
+ var UPDATE_OFFERING = `
133
+ mutation KadaikodiUpdateOffering($id: ID!, $input: KadaikodiUpdateOfferingInput!) {
134
+ updateOffering(id: $id, input: $input) {
135
+ ${OFFERING_FIELDS}
136
+ }
137
+ }
138
+ `;
139
+ var GET_ORDER = `
140
+ query KadaikodiGetOrder($id: ID!) {
141
+ getOrder(id: $id) {
142
+ ${ORDER_FIELDS}
143
+ }
144
+ }
145
+ `;
146
+ var LIST_ORDERS = `
147
+ query KadaikodiListOrders(
148
+ $customerId: String
149
+ $providerId: String
150
+ $status: KadaikodiOrderStatus
151
+ $limit: Int
152
+ $offset: Int
153
+ ) {
154
+ listOrders(
155
+ customerId: $customerId
156
+ providerId: $providerId
157
+ status: $status
158
+ limit: $limit
159
+ offset: $offset
160
+ ) {
161
+ ${ORDER_FIELDS}
162
+ }
163
+ }
164
+ `;
165
+ var PLACE_ORDER = `
166
+ mutation KadaikodiPlaceOrder($input: KadaikodiPlaceOrderInput!) {
167
+ placeOrder(input: $input) {
168
+ ${ORDER_FIELDS}
169
+ }
170
+ }
171
+ `;
172
+ var UPDATE_ORDER_STATUS = `
173
+ mutation KadaikodiUpdateOrderStatus($id: ID!, $status: KadaikodiOrderStatus!) {
174
+ updateOrderStatus(id: $id, status: $status) {
175
+ ${ORDER_FIELDS}
176
+ }
177
+ }
178
+ `;
179
+ var LIST_REVIEWS = `
180
+ query KadaikodiListReviews($providerId: String!, $limit: Int, $offset: Int) {
181
+ listReviews(providerId: $providerId, limit: $limit, offset: $offset) {
182
+ ${REVIEW_FIELDS}
183
+ }
184
+ }
185
+ `;
186
+ var CREATE_REVIEW = `
187
+ mutation KadaikodiCreateReview($input: KadaikodiCreateReviewInput!) {
188
+ createReview(input: $input) {
189
+ ${REVIEW_FIELDS}
190
+ }
191
+ }
192
+ `;
193
+ var RESPOND_TO_REVIEW = `
194
+ mutation KadaikodiRespondToReview($id: ID!, $response: String!) {
195
+ respondToReview(id: $id, response: $response) {
196
+ ${REVIEW_FIELDS}
197
+ }
198
+ }
199
+ `;
200
+ var GET_INVESTMENT_OPPORTUNITY = `
201
+ query KadaikodiGetInvestmentOpportunity($id: ID!) {
202
+ getInvestmentOpportunity(id: $id) {
203
+ ${OPPORTUNITY_FIELDS}
204
+ provider { id name slug category }
205
+ investments { id investorId amount status investedAt }
206
+ }
207
+ }
208
+ `;
209
+ var LIST_INVESTMENT_OPPORTUNITIES = `
210
+ query KadaikodiListInvestmentOpportunities(
211
+ $riskLevel: KadaikodiRiskLevel
212
+ $status: KadaikodiInvestmentStatus
213
+ $limit: Int
214
+ $offset: Int
215
+ ) {
216
+ listInvestmentOpportunities(
217
+ riskLevel: $riskLevel
218
+ status: $status
219
+ limit: $limit
220
+ offset: $offset
221
+ ) {
222
+ ${OPPORTUNITY_FIELDS}
223
+ }
224
+ }
225
+ `;
226
+ var LIST_INVESTMENTS = `
227
+ query KadaikodiListInvestments($investorId: String!, $limit: Int, $offset: Int) {
228
+ listInvestments(investorId: $investorId, limit: $limit, offset: $offset) {
229
+ ${INVESTMENT_FIELDS}
230
+ }
231
+ }
232
+ `;
233
+ var CREATE_INVESTMENT_OPPORTUNITY = `
234
+ mutation KadaikodiCreateInvestmentOpportunity(
235
+ $input: KadaikodiCreateInvestmentOpportunityInput!
236
+ ) {
237
+ createInvestmentOpportunity(input: $input) {
238
+ ${OPPORTUNITY_FIELDS}
239
+ }
240
+ }
241
+ `;
242
+ var INVEST = `
243
+ mutation KadaikodiInvest($input: KadaikodiInvestInput!) {
244
+ invest(input: $input) {
245
+ ${INVESTMENT_FIELDS}
246
+ opportunity { id title status raisedAmount targetAmount }
247
+ }
248
+ }
249
+ `;
250
+ var ADMIN_ANALYTICS = `
251
+ query KadaikodiAdminAnalytics {
252
+ kadaikodiAdminAnalytics {
253
+ categoryDistribution
254
+ customerGrowth
255
+ orderTrends
256
+ revenueByCategory
257
+ topProviders
258
+ }
259
+ }
260
+ `;
261
+ var DASHBOARD_STATS = `
262
+ query KadaikodiDashboardStats {
263
+ kadaikodiDashboardStats {
264
+ activeCustomers
265
+ activeProviders
266
+ avgRating
267
+ pendingOrders
268
+ totalOrders
269
+ totalRevenue
270
+ }
271
+ }
272
+ `;
273
+ var HEALTH = `
274
+ query KadaikodiHealth {
275
+ kadaikodiHealth
276
+ }
277
+ `;
278
+ var ServiceCategoryEnum = z.enum([
279
+ "CLOTHING_FASHION",
280
+ "EDUCATION_SKILLS",
281
+ "FOOD_BEVERAGE",
282
+ "GROCERY_ESSENTIALS",
283
+ "HEALTH_WELLNESS",
284
+ "HOME_SERVICES",
285
+ "PERSONAL_CARE_BEAUTY",
286
+ "REPAIR_MAINTENANCE",
287
+ "RETAIL_MERCHANDISE"
288
+ ]).describe("Top-level service/commerce category for a provider or offering");
289
+ var ProviderStatusEnum = z.enum(["ACTIVE", "ARCHIVED", "DRAFT", "PAUSED", "SUSPENDED", "VERIFIED"]).describe("Lifecycle/moderation status of a service provider");
290
+ var OfferingKindEnum = z.enum(["PRODUCT", "SERVICE"]).describe("Whether the offering is a physical PRODUCT (stocked) or a bookable SERVICE");
291
+ var OrderStatusEnum = z.enum([
292
+ "PENDING",
293
+ "PLACED",
294
+ "CONFIRMED",
295
+ "PREPARING",
296
+ "READY",
297
+ "OUT_FOR_DELIVERY",
298
+ "DELIVERED",
299
+ "COMPLETED",
300
+ "CANCELLED"
301
+ ]).describe("Fulfilment status of an order");
302
+ z.enum(["PENDING", "PROCESSING", "PAID", "FAILED", "REFUNDED"]).describe("Payment status of an order");
303
+ var InvestmentStatusEnum = z.enum(["DRAFT", "ACTIVE", "FUNDED", "CLOSED"]).describe("Lifecycle status of an investment opportunity");
304
+ var RiskLevelEnum = z.enum(["LOW", "MEDIUM", "HIGH"]).describe("Risk classification of an investment opportunity");
305
+ var JsonObject = z.record(z.string(), z.unknown());
306
+
307
+ // src/modules/kadaikodi/tools/providers.ts
308
+ function registerProviderTools(server, ctx, track) {
309
+ server.registerTool(
310
+ track(mcpToolName(ctx.productName, "providers_get")),
311
+ {
312
+ title: "Get Service Provider",
313
+ description: "Fetch a single Kadaikodi service provider by ID, including its offerings, workers, and investment opportunities.",
314
+ inputSchema: { id: z.string().describe("Service provider ID") }
315
+ },
316
+ async ({ id }) => {
317
+ try {
318
+ const data = await ctx.gql.workspace.request(GET_SERVICE_PROVIDER, { id });
319
+ if (!data.getServiceProvider) return errorResult(`Service provider ${id} not found`);
320
+ return jsonResult(data.getServiceProvider);
321
+ } catch (error) {
322
+ ctx.logger.error("kadaikodi providers_get failed", { error: String(error) });
323
+ return errorResult(
324
+ `Failed to get service provider: ${error instanceof Error ? error.message : String(error)}`
325
+ );
326
+ }
327
+ }
328
+ );
329
+ server.registerTool(
330
+ track(mcpToolName(ctx.productName, "providers_list")),
331
+ {
332
+ title: "List Service Providers",
333
+ description: "List service providers in the bound workspace with optional category/status/open-now/text filters and pagination.",
334
+ inputSchema: {
335
+ category: ServiceCategoryEnum.optional().describe("Filter by category"),
336
+ status: ProviderStatusEnum.optional().describe("Filter by lifecycle status"),
337
+ openOnly: z.boolean().optional().describe("Only providers currently open per businessHours"),
338
+ query: z.string().optional().describe("Free-text search across name/description"),
339
+ limit: z.number().int().optional().describe("Page size (default 50)"),
340
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
341
+ }
342
+ },
343
+ async ({ category, status, openOnly, query, limit, offset }) => {
344
+ try {
345
+ const filter = {};
346
+ if (category !== void 0) filter.category = category;
347
+ if (status !== void 0) filter.status = status;
348
+ if (openOnly !== void 0) filter.openOnly = openOnly;
349
+ if (query !== void 0) filter.query = query;
350
+ const data = await ctx.gql.workspace.request(LIST_SERVICE_PROVIDERS, {
351
+ filter: Object.keys(filter).length > 0 ? filter : void 0,
352
+ limit: limit ?? 50,
353
+ offset: offset ?? 0
354
+ });
355
+ return jsonResult(data.listServiceProviders);
356
+ } catch (error) {
357
+ ctx.logger.error("kadaikodi providers_list failed", { error: String(error) });
358
+ return errorResult(
359
+ `Failed to list service providers: ${error instanceof Error ? error.message : String(error)}`
360
+ );
361
+ }
362
+ }
363
+ );
364
+ server.registerTool(
365
+ track(mcpToolName(ctx.productName, "providers_create")),
366
+ {
367
+ title: "Create Service Provider",
368
+ description: "Onboard a new service provider (storefront/business). `slug` must be unique within the workspace; `location` is required JSON ({ address, latitude, longitude }).",
369
+ inputSchema: {
370
+ name: z.string().min(1).describe("Business / provider display name"),
371
+ slug: z.string().min(1).describe("URL slug, unique within the workspace"),
372
+ category: ServiceCategoryEnum.describe("Primary category"),
373
+ ownerId: z.string().min(1).describe("User ID of the provider owner"),
374
+ location: JsonObject.describe("Location JSON: { address, latitude, longitude }"),
375
+ description: z.string().optional().describe("Business description"),
376
+ offeringType: z.string().optional().describe('What the provider offers: "products", "services", or "both" (default "both")'),
377
+ serviceTypes: z.array(z.string()).optional().describe("Free-form service-type tags (default [])"),
378
+ businessHours: z.union([JsonObject, z.array(z.unknown())]).optional().describe("Business-hours JSON (per-day open/close windows)")
379
+ }
380
+ },
381
+ async ({
382
+ name,
383
+ slug,
384
+ category,
385
+ ownerId,
386
+ location,
387
+ description,
388
+ offeringType,
389
+ serviceTypes,
390
+ businessHours
391
+ }) => {
392
+ try {
393
+ const input = { name, slug, category, ownerId, location };
394
+ if (description !== void 0) input.description = description;
395
+ if (offeringType !== void 0) input.offeringType = offeringType;
396
+ if (serviceTypes !== void 0) input.serviceTypes = serviceTypes;
397
+ if (businessHours !== void 0) input.businessHours = businessHours;
398
+ const data = await ctx.gql.workspace.request(CREATE_SERVICE_PROVIDER, { input });
399
+ return jsonResult(data.kadaikodiCreateServiceProvider);
400
+ } catch (error) {
401
+ ctx.logger.error("kadaikodi providers_create failed", { error: String(error) });
402
+ return errorResult(
403
+ `Failed to create service provider: ${error instanceof Error ? error.message : String(error)}`
404
+ );
405
+ }
406
+ }
407
+ );
408
+ server.registerTool(
409
+ track(mcpToolName(ctx.productName, "providers_update")),
410
+ {
411
+ title: "Update Service Provider",
412
+ description: "Update a service provider. At least one mutable field must be provided. Use `status` to verify/pause/suspend/archive a provider.",
413
+ inputSchema: {
414
+ id: z.string().describe("Service provider ID"),
415
+ name: z.string().optional().describe("Updated display name"),
416
+ description: z.string().optional().describe("Updated description"),
417
+ status: ProviderStatusEnum.optional().describe("Updated lifecycle/moderation status"),
418
+ location: JsonObject.optional().describe("Updated location JSON"),
419
+ businessHours: z.union([JsonObject, z.array(z.unknown())]).optional().describe("Updated business-hours JSON"),
420
+ serviceTypes: z.array(z.string()).optional().describe("Updated service-type tags"),
421
+ analyticsSnapshot: JsonObject.optional().describe("Updated analytics snapshot JSON")
422
+ }
423
+ },
424
+ async ({
425
+ id,
426
+ name,
427
+ description,
428
+ status,
429
+ location,
430
+ businessHours,
431
+ serviceTypes,
432
+ analyticsSnapshot
433
+ }) => {
434
+ try {
435
+ const input = {};
436
+ if (name !== void 0) input.name = name;
437
+ if (description !== void 0) input.description = description;
438
+ if (status !== void 0) input.status = status;
439
+ if (location !== void 0) input.location = location;
440
+ if (businessHours !== void 0) input.businessHours = businessHours;
441
+ if (serviceTypes !== void 0) input.serviceTypes = serviceTypes;
442
+ if (analyticsSnapshot !== void 0) input.analyticsSnapshot = analyticsSnapshot;
443
+ if (Object.keys(input).length === 0) {
444
+ return errorResult(
445
+ "No updates specified \u2014 provide at least one of name/description/status/location/businessHours/serviceTypes/analyticsSnapshot"
446
+ );
447
+ }
448
+ const data = await ctx.gql.workspace.request(UPDATE_SERVICE_PROVIDER, { id, input });
449
+ return jsonResult(data.kadaikodiUpdateServiceProvider);
450
+ } catch (error) {
451
+ ctx.logger.error("kadaikodi providers_update failed", { error: String(error) });
452
+ return errorResult(
453
+ `Failed to update service provider: ${error instanceof Error ? error.message : String(error)}`
454
+ );
455
+ }
456
+ }
457
+ );
458
+ }
459
+ function registerWorkerTools(server, ctx, track) {
460
+ server.registerTool(
461
+ track(mcpToolName(ctx.productName, "workers_list")),
462
+ {
463
+ title: "List Provider Workers",
464
+ description: "List the workers (staff/agents) attached to a service provider, including each worker\u2019s assigned tasks.",
465
+ inputSchema: {
466
+ providerId: z.string().describe("Service provider ID"),
467
+ limit: z.number().int().optional().describe("Page size (default 50)"),
468
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
469
+ }
470
+ },
471
+ async ({ providerId, limit, offset }) => {
472
+ try {
473
+ const data = await ctx.gql.workspace.request(LIST_PROVIDER_WORKERS, {
474
+ providerId,
475
+ limit: limit ?? 50,
476
+ offset: offset ?? 0
477
+ });
478
+ return jsonResult(data.listProviderWorkers);
479
+ } catch (error) {
480
+ ctx.logger.error("kadaikodi workers_list failed", { error: String(error) });
481
+ return errorResult(
482
+ `Failed to list provider workers: ${error instanceof Error ? error.message : String(error)}`
483
+ );
484
+ }
485
+ }
486
+ );
487
+ }
488
+ function registerTaskTools(server, ctx, track) {
489
+ server.registerTool(
490
+ track(mcpToolName(ctx.productName, "tasks_list")),
491
+ {
492
+ title: "List Worker Tasks",
493
+ description: "List the tasks assigned to a provider worker (referenced by workerRefId), optionally filtered by free-form task status.",
494
+ inputSchema: {
495
+ workerRefId: z.string().describe("Worker reference ID (KadaikodiProviderWorker.workerId)"),
496
+ status: z.string().optional().describe('Filter by task status (free-form, e.g. "pending", "in_progress", "done")'),
497
+ limit: z.number().int().optional().describe("Page size (default 50)"),
498
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
499
+ }
500
+ },
501
+ async ({ workerRefId, status, limit, offset }) => {
502
+ try {
503
+ const data = await ctx.gql.workspace.request(LIST_WORKER_TASKS, {
504
+ workerRefId,
505
+ status,
506
+ limit: limit ?? 50,
507
+ offset: offset ?? 0
508
+ });
509
+ return jsonResult(data.listWorkerTasks);
510
+ } catch (error) {
511
+ ctx.logger.error("kadaikodi tasks_list failed", { error: String(error) });
512
+ return errorResult(
513
+ `Failed to list worker tasks: ${error instanceof Error ? error.message : String(error)}`
514
+ );
515
+ }
516
+ }
517
+ );
518
+ }
519
+ var MediaSchema = z.union([JsonObject, z.array(z.unknown())]).describe("Media JSON (image/video URLs or { images: [...] })");
520
+ function registerOfferingTools(server, ctx, track) {
521
+ server.registerTool(
522
+ track(mcpToolName(ctx.productName, "offerings_get")),
523
+ {
524
+ title: "Get Offering",
525
+ description: "Fetch a single catalog offering (product or service) by ID.",
526
+ inputSchema: { id: z.string().describe("Offering ID") }
527
+ },
528
+ async ({ id }) => {
529
+ try {
530
+ const data = await ctx.gql.workspace.request(GET_OFFERING, { id });
531
+ if (!data.getOffering) return errorResult(`Offering ${id} not found`);
532
+ return jsonResult(data.getOffering);
533
+ } catch (error) {
534
+ ctx.logger.error("kadaikodi offerings_get failed", { error: String(error) });
535
+ return errorResult(
536
+ `Failed to get offering: ${error instanceof Error ? error.message : String(error)}`
537
+ );
538
+ }
539
+ }
540
+ );
541
+ server.registerTool(
542
+ track(mcpToolName(ctx.productName, "offerings_list")),
543
+ {
544
+ title: "List Offerings",
545
+ description: "List catalog offerings, optionally filtered by kind (PRODUCT/SERVICE) and/or provider.",
546
+ inputSchema: {
547
+ kind: OfferingKindEnum.optional().describe("Filter by offering kind"),
548
+ providerId: z.string().optional().describe("Filter by provider ID"),
549
+ limit: z.number().int().optional().describe("Page size (default 100)"),
550
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
551
+ }
552
+ },
553
+ async ({ kind, providerId, limit, offset }) => {
554
+ try {
555
+ const data = await ctx.gql.workspace.request(LIST_OFFERINGS, {
556
+ kind,
557
+ providerId,
558
+ limit: limit ?? 100,
559
+ offset: offset ?? 0
560
+ });
561
+ return jsonResult(data.listOfferings);
562
+ } catch (error) {
563
+ ctx.logger.error("kadaikodi offerings_list failed", { error: String(error) });
564
+ return errorResult(
565
+ `Failed to list offerings: ${error instanceof Error ? error.message : String(error)}`
566
+ );
567
+ }
568
+ }
569
+ );
570
+ server.registerTool(
571
+ track(mcpToolName(ctx.productName, "offerings_create")),
572
+ {
573
+ title: "Create Offering",
574
+ description: "Create a catalog offering. For PRODUCT kind set `stock`; for SERVICE kind set `durationMinutes`. `slug` is unique per provider.",
575
+ inputSchema: {
576
+ providerId: z.string().min(1).describe("Owning provider ID"),
577
+ name: z.string().min(1).describe("Offering display name"),
578
+ slug: z.string().min(1).describe("URL slug, unique within the provider"),
579
+ category: ServiceCategoryEnum.describe("Offering category"),
580
+ kind: OfferingKindEnum.describe("PRODUCT or SERVICE"),
581
+ price: z.number().describe("Current selling price"),
582
+ originalPrice: z.number().optional().describe("Pre-discount/list price"),
583
+ description: z.string().optional().describe("Offering description"),
584
+ durationMinutes: z.number().int().optional().describe("Service duration in minutes (SERVICE kind)"),
585
+ stock: z.number().int().optional().describe("Available stock (PRODUCT kind)"),
586
+ serviceType: z.string().optional().describe("Free-form service-type tag"),
587
+ media: MediaSchema.optional(),
588
+ metadata: JsonObject.optional().describe("Arbitrary metadata JSON"),
589
+ tags: z.array(z.string()).optional().describe("Search/discovery tags (default [])")
590
+ }
591
+ },
592
+ async ({
593
+ providerId,
594
+ name,
595
+ slug,
596
+ category,
597
+ kind,
598
+ price,
599
+ originalPrice,
600
+ description,
601
+ durationMinutes,
602
+ stock,
603
+ serviceType,
604
+ media,
605
+ metadata,
606
+ tags
607
+ }) => {
608
+ try {
609
+ const input = { providerId, name, slug, category, kind, price };
610
+ if (originalPrice !== void 0) input.originalPrice = originalPrice;
611
+ if (description !== void 0) input.description = description;
612
+ if (durationMinutes !== void 0) input.durationMinutes = durationMinutes;
613
+ if (stock !== void 0) input.stock = stock;
614
+ if (serviceType !== void 0) input.serviceType = serviceType;
615
+ if (media !== void 0) input.media = media;
616
+ if (metadata !== void 0) input.metadata = metadata;
617
+ if (tags !== void 0) input.tags = tags;
618
+ const data = await ctx.gql.workspace.request(CREATE_OFFERING, { input });
619
+ return jsonResult(data.createOffering);
620
+ } catch (error) {
621
+ ctx.logger.error("kadaikodi offerings_create failed", { error: String(error) });
622
+ return errorResult(
623
+ `Failed to create offering: ${error instanceof Error ? error.message : String(error)}`
624
+ );
625
+ }
626
+ }
627
+ );
628
+ server.registerTool(
629
+ track(mcpToolName(ctx.productName, "offerings_update")),
630
+ {
631
+ title: "Update Offering",
632
+ description: "Update a catalog offering. At least one mutable field must be provided. Use `isAvailable` to toggle visibility.",
633
+ inputSchema: {
634
+ id: z.string().describe("Offering ID"),
635
+ name: z.string().optional().describe("Updated name"),
636
+ description: z.string().optional().describe("Updated description"),
637
+ price: z.number().optional().describe("Updated price"),
638
+ originalPrice: z.number().optional().describe("Updated list price"),
639
+ durationMinutes: z.number().int().optional().describe("Updated service duration (minutes)"),
640
+ stock: z.number().int().optional().describe("Updated stock"),
641
+ isAvailable: z.boolean().optional().describe("Toggle availability"),
642
+ serviceType: z.string().optional().describe("Updated service-type tag"),
643
+ media: MediaSchema.optional(),
644
+ metadata: JsonObject.optional().describe("Updated metadata JSON"),
645
+ tags: z.array(z.string()).optional().describe("Updated tags")
646
+ }
647
+ },
648
+ async ({
649
+ id,
650
+ name,
651
+ description,
652
+ price,
653
+ originalPrice,
654
+ durationMinutes,
655
+ stock,
656
+ isAvailable,
657
+ serviceType,
658
+ media,
659
+ metadata,
660
+ tags
661
+ }) => {
662
+ try {
663
+ const input = {};
664
+ if (name !== void 0) input.name = name;
665
+ if (description !== void 0) input.description = description;
666
+ if (price !== void 0) input.price = price;
667
+ if (originalPrice !== void 0) input.originalPrice = originalPrice;
668
+ if (durationMinutes !== void 0) input.durationMinutes = durationMinutes;
669
+ if (stock !== void 0) input.stock = stock;
670
+ if (isAvailable !== void 0) input.isAvailable = isAvailable;
671
+ if (serviceType !== void 0) input.serviceType = serviceType;
672
+ if (media !== void 0) input.media = media;
673
+ if (metadata !== void 0) input.metadata = metadata;
674
+ if (tags !== void 0) input.tags = tags;
675
+ if (Object.keys(input).length === 0) {
676
+ return errorResult("No updates specified \u2014 provide at least one mutable offering field");
677
+ }
678
+ const data = await ctx.gql.workspace.request(UPDATE_OFFERING, { id, input });
679
+ return jsonResult(data.updateOffering);
680
+ } catch (error) {
681
+ ctx.logger.error("kadaikodi offerings_update failed", { error: String(error) });
682
+ return errorResult(
683
+ `Failed to update offering: ${error instanceof Error ? error.message : String(error)}`
684
+ );
685
+ }
686
+ }
687
+ );
688
+ }
689
+ var OrderItemSchema = z.object({
690
+ name: z.string().describe("Line-item display name (snapshot)"),
691
+ quantity: z.number().int().describe("Quantity ordered"),
692
+ unitPrice: z.number().describe("Unit price at time of order"),
693
+ offeringId: z.string().optional().describe("Source offering ID (optional for ad-hoc items)"),
694
+ customizations: JsonObject.optional().describe("Per-item customization JSON")
695
+ }).describe("A single order line item");
696
+ function registerOrderTools(server, ctx, track) {
697
+ server.registerTool(
698
+ track(mcpToolName(ctx.productName, "orders_get")),
699
+ {
700
+ title: "Get Order",
701
+ description: "Fetch a single order by ID, including its line items.",
702
+ inputSchema: { id: z.string().describe("Order ID") }
703
+ },
704
+ async ({ id }) => {
705
+ try {
706
+ const data = await ctx.gql.workspace.request(GET_ORDER, { id });
707
+ if (!data.getOrder) return errorResult(`Order ${id} not found`);
708
+ return jsonResult(data.getOrder);
709
+ } catch (error) {
710
+ ctx.logger.error("kadaikodi orders_get failed", { error: String(error) });
711
+ return errorResult(
712
+ `Failed to get order: ${error instanceof Error ? error.message : String(error)}`
713
+ );
714
+ }
715
+ }
716
+ );
717
+ server.registerTool(
718
+ track(mcpToolName(ctx.productName, "orders_list")),
719
+ {
720
+ title: "List Orders",
721
+ description: "List orders, optionally filtered by customer, provider, and/or status. Useful for both buyer order-history and provider order-queue views.",
722
+ inputSchema: {
723
+ customerId: z.string().optional().describe("Filter by customer ID"),
724
+ providerId: z.string().optional().describe("Filter by provider ID"),
725
+ status: OrderStatusEnum.optional().describe("Filter by order status"),
726
+ limit: z.number().int().optional().describe("Page size (default 100)"),
727
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
728
+ }
729
+ },
730
+ async ({ customerId, providerId, status, limit, offset }) => {
731
+ try {
732
+ const data = await ctx.gql.workspace.request(LIST_ORDERS, {
733
+ customerId,
734
+ providerId,
735
+ status,
736
+ limit: limit ?? 100,
737
+ offset: offset ?? 0
738
+ });
739
+ return jsonResult(data.listOrders);
740
+ } catch (error) {
741
+ ctx.logger.error("kadaikodi orders_list failed", { error: String(error) });
742
+ return errorResult(
743
+ `Failed to list orders: ${error instanceof Error ? error.message : String(error)}`
744
+ );
745
+ }
746
+ }
747
+ );
748
+ server.registerTool(
749
+ track(mcpToolName(ctx.productName, "orders_place")),
750
+ {
751
+ title: "Place Order",
752
+ description: 'Place an order on behalf of a customer. Provide one or more line items; subtotal/total are computed server-side. `fulfillmentType` is e.g. "delivery" or "pickup".',
753
+ inputSchema: {
754
+ customerId: z.string().min(1).describe("Ordering customer ID"),
755
+ providerId: z.string().min(1).describe("Provider the order is placed with"),
756
+ fulfillmentType: z.string().min(1).describe('Fulfilment type, e.g. "delivery" or "pickup"'),
757
+ items: z.array(OrderItemSchema).min(1).describe("Order line items (at least one)"),
758
+ deliveryAddress: JsonObject.optional().describe("Delivery address JSON (delivery orders)"),
759
+ deliveryFee: z.number().optional().describe("Delivery fee (default 0)"),
760
+ discount: z.number().optional().describe("Order-level discount (default 0)"),
761
+ tax: z.number().optional().describe("Tax amount (default 0)"),
762
+ paymentMethod: z.string().optional().describe('Payment method, e.g. "cod", "card", "upi"'),
763
+ notes: z.string().optional().describe("Customer notes for the order")
764
+ }
765
+ },
766
+ async ({
767
+ customerId,
768
+ providerId,
769
+ fulfillmentType,
770
+ items,
771
+ deliveryAddress,
772
+ deliveryFee,
773
+ discount,
774
+ tax,
775
+ paymentMethod,
776
+ notes
777
+ }) => {
778
+ try {
779
+ const input = { customerId, providerId, fulfillmentType, items };
780
+ if (deliveryAddress !== void 0) input.deliveryAddress = deliveryAddress;
781
+ if (deliveryFee !== void 0) input.deliveryFee = deliveryFee;
782
+ if (discount !== void 0) input.discount = discount;
783
+ if (tax !== void 0) input.tax = tax;
784
+ if (paymentMethod !== void 0) input.paymentMethod = paymentMethod;
785
+ if (notes !== void 0) input.notes = notes;
786
+ const data = await ctx.gql.workspace.request(PLACE_ORDER, { input });
787
+ return jsonResult(data.placeOrder);
788
+ } catch (error) {
789
+ ctx.logger.error("kadaikodi orders_place failed", { error: String(error) });
790
+ return errorResult(
791
+ `Failed to place order: ${error instanceof Error ? error.message : String(error)}`
792
+ );
793
+ }
794
+ }
795
+ );
796
+ server.registerTool(
797
+ track(mcpToolName(ctx.productName, "orders_update_status")),
798
+ {
799
+ title: "Update Order Status",
800
+ description: "Advance an order through its fulfilment lifecycle (e.g. PLACED \u2192 CONFIRMED \u2192 PREPARING \u2192 READY \u2192 OUT_FOR_DELIVERY \u2192 DELIVERED \u2192 COMPLETED, or CANCELLED).",
801
+ inputSchema: {
802
+ id: z.string().describe("Order ID"),
803
+ status: OrderStatusEnum.describe("New order status")
804
+ }
805
+ },
806
+ async ({ id, status }) => {
807
+ try {
808
+ const data = await ctx.gql.workspace.request(UPDATE_ORDER_STATUS, { id, status });
809
+ return jsonResult(data.updateOrderStatus);
810
+ } catch (error) {
811
+ ctx.logger.error("kadaikodi orders_update_status failed", { error: String(error) });
812
+ return errorResult(
813
+ `Failed to update order status: ${error instanceof Error ? error.message : String(error)}`
814
+ );
815
+ }
816
+ }
817
+ );
818
+ }
819
+ function registerReviewTools(server, ctx, track) {
820
+ server.registerTool(
821
+ track(mcpToolName(ctx.productName, "reviews_list")),
822
+ {
823
+ title: "List Reviews",
824
+ description: "List customer reviews for a service provider.",
825
+ inputSchema: {
826
+ providerId: z.string().describe("Service provider ID"),
827
+ limit: z.number().int().optional().describe("Page size (default 100)"),
828
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
829
+ }
830
+ },
831
+ async ({ providerId, limit, offset }) => {
832
+ try {
833
+ const data = await ctx.gql.workspace.request(LIST_REVIEWS, {
834
+ providerId,
835
+ limit: limit ?? 100,
836
+ offset: offset ?? 0
837
+ });
838
+ return jsonResult(data.listReviews);
839
+ } catch (error) {
840
+ ctx.logger.error("kadaikodi reviews_list failed", { error: String(error) });
841
+ return errorResult(
842
+ `Failed to list reviews: ${error instanceof Error ? error.message : String(error)}`
843
+ );
844
+ }
845
+ }
846
+ );
847
+ server.registerTool(
848
+ track(mcpToolName(ctx.productName, "reviews_create")),
849
+ {
850
+ title: "Create Review",
851
+ description: "Create a customer review (rating 1\u20135, optional text) for a provider, optionally tied to a fulfilled order.",
852
+ inputSchema: {
853
+ providerId: z.string().min(1).describe("Provider being reviewed"),
854
+ customerId: z.string().min(1).describe("Reviewing customer ID"),
855
+ rating: z.number().int().min(1).max(5).describe("Star rating, 1\u20135"),
856
+ review: z.string().optional().describe("Free-text review body"),
857
+ orderId: z.string().optional().describe("Related order ID (for verified-purchase reviews)")
858
+ }
859
+ },
860
+ async ({ providerId, customerId, rating, review, orderId }) => {
861
+ try {
862
+ const input = { providerId, customerId, rating };
863
+ if (review !== void 0) input.review = review;
864
+ if (orderId !== void 0) input.orderId = orderId;
865
+ const data = await ctx.gql.workspace.request(CREATE_REVIEW, { input });
866
+ return jsonResult(data.createReview);
867
+ } catch (error) {
868
+ ctx.logger.error("kadaikodi reviews_create failed", { error: String(error) });
869
+ return errorResult(
870
+ `Failed to create review: ${error instanceof Error ? error.message : String(error)}`
871
+ );
872
+ }
873
+ }
874
+ );
875
+ server.registerTool(
876
+ track(mcpToolName(ctx.productName, "reviews_respond")),
877
+ {
878
+ title: "Respond to Review",
879
+ description: "Post a provider response to an existing review.",
880
+ inputSchema: {
881
+ id: z.string().describe("Review ID"),
882
+ response: z.string().min(1).describe("Provider response text")
883
+ }
884
+ },
885
+ async ({ id, response }) => {
886
+ try {
887
+ const data = await ctx.gql.workspace.request(RESPOND_TO_REVIEW, { id, response });
888
+ return jsonResult(data.respondToReview);
889
+ } catch (error) {
890
+ ctx.logger.error("kadaikodi reviews_respond failed", { error: String(error) });
891
+ return errorResult(
892
+ `Failed to respond to review: ${error instanceof Error ? error.message : String(error)}`
893
+ );
894
+ }
895
+ }
896
+ );
897
+ }
898
+ function registerInvestmentTools(server, ctx, track) {
899
+ server.registerTool(
900
+ track(mcpToolName(ctx.productName, "investments_opportunities_get")),
901
+ {
902
+ title: "Get Investment Opportunity",
903
+ description: "Fetch a single investment opportunity by ID, including its provider and current investments.",
904
+ inputSchema: { id: z.string().describe("Investment opportunity ID") }
905
+ },
906
+ async ({ id }) => {
907
+ try {
908
+ const data = await ctx.gql.workspace.request(GET_INVESTMENT_OPPORTUNITY, { id });
909
+ if (!data.getInvestmentOpportunity)
910
+ return errorResult(`Investment opportunity ${id} not found`);
911
+ return jsonResult(data.getInvestmentOpportunity);
912
+ } catch (error) {
913
+ ctx.logger.error("kadaikodi investments_opportunities_get failed", {
914
+ error: String(error)
915
+ });
916
+ return errorResult(
917
+ `Failed to get investment opportunity: ${error instanceof Error ? error.message : String(error)}`
918
+ );
919
+ }
920
+ }
921
+ );
922
+ server.registerTool(
923
+ track(mcpToolName(ctx.productName, "investments_opportunities_list")),
924
+ {
925
+ title: "List Investment Opportunities",
926
+ description: "List community-investment opportunities, optionally filtered by risk level and/or status.",
927
+ inputSchema: {
928
+ riskLevel: RiskLevelEnum.optional().describe("Filter by risk level"),
929
+ status: InvestmentStatusEnum.optional().describe("Filter by opportunity status"),
930
+ limit: z.number().int().optional().describe("Page size (default 100)"),
931
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
932
+ }
933
+ },
934
+ async ({ riskLevel, status, limit, offset }) => {
935
+ try {
936
+ const data = await ctx.gql.workspace.request(LIST_INVESTMENT_OPPORTUNITIES, {
937
+ riskLevel,
938
+ status,
939
+ limit: limit ?? 100,
940
+ offset: offset ?? 0
941
+ });
942
+ return jsonResult(data.listInvestmentOpportunities);
943
+ } catch (error) {
944
+ ctx.logger.error("kadaikodi investments_opportunities_list failed", {
945
+ error: String(error)
946
+ });
947
+ return errorResult(
948
+ `Failed to list investment opportunities: ${error instanceof Error ? error.message : String(error)}`
949
+ );
950
+ }
951
+ }
952
+ );
953
+ server.registerTool(
954
+ track(mcpToolName(ctx.productName, "investments_opportunities_create")),
955
+ {
956
+ title: "Create Investment Opportunity",
957
+ description: "Create a community-investment opportunity for a provider (fundraise target, minimum ticket, expected returns, lock-in, risk).",
958
+ inputSchema: {
959
+ providerId: z.string().min(1).describe("Provider raising the investment"),
960
+ title: z.string().min(1).describe("Opportunity title"),
961
+ targetAmount: z.number().describe("Fundraise target amount"),
962
+ minimumInvestment: z.number().describe("Minimum investment ticket size"),
963
+ expectedReturnsPct: z.number().describe("Expected returns as a percentage"),
964
+ lockInMonths: z.number().int().describe("Lock-in period in months"),
965
+ riskLevel: RiskLevelEnum.optional().describe("Risk level (default MEDIUM)"),
966
+ description: z.string().optional().describe("Opportunity description"),
967
+ businessMetrics: JsonObject.optional().describe("Supporting business-metrics JSON"),
968
+ terms: JsonObject.optional().describe("Investment terms JSON"),
969
+ expiresAt: z.string().optional().describe("Expiry timestamp (ISO-8601 DateTime)")
970
+ }
971
+ },
972
+ async ({
973
+ providerId,
974
+ title,
975
+ targetAmount,
976
+ minimumInvestment,
977
+ expectedReturnsPct,
978
+ lockInMonths,
979
+ riskLevel,
980
+ description,
981
+ businessMetrics,
982
+ terms,
983
+ expiresAt
984
+ }) => {
985
+ try {
986
+ const input = {
987
+ providerId,
988
+ title,
989
+ targetAmount,
990
+ minimumInvestment,
991
+ expectedReturnsPct,
992
+ lockInMonths
993
+ };
994
+ if (riskLevel !== void 0) input.riskLevel = riskLevel;
995
+ if (description !== void 0) input.description = description;
996
+ if (businessMetrics !== void 0) input.businessMetrics = businessMetrics;
997
+ if (terms !== void 0) input.terms = terms;
998
+ if (expiresAt !== void 0) input.expiresAt = expiresAt;
999
+ const data = await ctx.gql.workspace.request(CREATE_INVESTMENT_OPPORTUNITY, { input });
1000
+ return jsonResult(data.createInvestmentOpportunity);
1001
+ } catch (error) {
1002
+ ctx.logger.error("kadaikodi investments_opportunities_create failed", {
1003
+ error: String(error)
1004
+ });
1005
+ return errorResult(
1006
+ `Failed to create investment opportunity: ${error instanceof Error ? error.message : String(error)}`
1007
+ );
1008
+ }
1009
+ }
1010
+ );
1011
+ server.registerTool(
1012
+ track(mcpToolName(ctx.productName, "investments_list")),
1013
+ {
1014
+ title: "List Investments",
1015
+ description: "List the investments made by a given investor, including each investment\u2019s transactions.",
1016
+ inputSchema: {
1017
+ investorId: z.string().describe("Investor user ID"),
1018
+ limit: z.number().int().optional().describe("Page size (default 100)"),
1019
+ offset: z.number().int().optional().describe("Pagination offset (default 0)")
1020
+ }
1021
+ },
1022
+ async ({ investorId, limit, offset }) => {
1023
+ try {
1024
+ const data = await ctx.gql.workspace.request(LIST_INVESTMENTS, {
1025
+ investorId,
1026
+ limit: limit ?? 100,
1027
+ offset: offset ?? 0
1028
+ });
1029
+ return jsonResult(data.listInvestments);
1030
+ } catch (error) {
1031
+ ctx.logger.error("kadaikodi investments_list failed", { error: String(error) });
1032
+ return errorResult(
1033
+ `Failed to list investments: ${error instanceof Error ? error.message : String(error)}`
1034
+ );
1035
+ }
1036
+ }
1037
+ );
1038
+ server.registerTool(
1039
+ track(mcpToolName(ctx.productName, "investments_invest")),
1040
+ {
1041
+ title: "Invest in Opportunity",
1042
+ description: "Commit an investment amount to an opportunity on behalf of an investor. Returns the created investment plus the updated opportunity funding state.",
1043
+ inputSchema: {
1044
+ opportunityId: z.string().min(1).describe("Target investment opportunity ID"),
1045
+ investorId: z.string().min(1).describe("Investor user ID"),
1046
+ amount: z.number().describe("Investment amount (must meet the opportunity minimum)")
1047
+ }
1048
+ },
1049
+ async ({ opportunityId, investorId, amount }) => {
1050
+ try {
1051
+ const input = { opportunityId, investorId, amount };
1052
+ const data = await ctx.gql.workspace.request(INVEST, { input });
1053
+ return jsonResult(data.invest);
1054
+ } catch (error) {
1055
+ ctx.logger.error("kadaikodi investments_invest failed", { error: String(error) });
1056
+ return errorResult(
1057
+ `Failed to invest: ${error instanceof Error ? error.message : String(error)}`
1058
+ );
1059
+ }
1060
+ }
1061
+ );
1062
+ }
1063
+
1064
+ // src/modules/kadaikodi/tools/analytics.ts
1065
+ function registerAnalyticsTools(server, ctx, track) {
1066
+ server.registerTool(
1067
+ track(mcpToolName(ctx.productName, "analytics_admin")),
1068
+ {
1069
+ title: "Kadaikodi Admin Analytics",
1070
+ description: "Marketplace-wide admin analytics: category distribution, customer growth, order trends, revenue by category, and top providers.",
1071
+ inputSchema: {}
1072
+ },
1073
+ async () => {
1074
+ try {
1075
+ const data = await ctx.gql.workspace.request(ADMIN_ANALYTICS, {});
1076
+ return jsonResult(data.kadaikodiAdminAnalytics);
1077
+ } catch (error) {
1078
+ ctx.logger.error("kadaikodi analytics_admin failed", { error: String(error) });
1079
+ return errorResult(
1080
+ `Failed to get admin analytics: ${error instanceof Error ? error.message : String(error)}`
1081
+ );
1082
+ }
1083
+ }
1084
+ );
1085
+ server.registerTool(
1086
+ track(mcpToolName(ctx.productName, "analytics_dashboard")),
1087
+ {
1088
+ title: "Kadaikodi Dashboard Stats",
1089
+ description: "Headline marketplace KPIs: active providers, active customers, total + pending orders, total revenue, and average rating.",
1090
+ inputSchema: {}
1091
+ },
1092
+ async () => {
1093
+ try {
1094
+ const data = await ctx.gql.workspace.request(DASHBOARD_STATS, {});
1095
+ return jsonResult(data.kadaikodiDashboardStats);
1096
+ } catch (error) {
1097
+ ctx.logger.error("kadaikodi analytics_dashboard failed", { error: String(error) });
1098
+ return errorResult(
1099
+ `Failed to get dashboard stats: ${error instanceof Error ? error.message : String(error)}`
1100
+ );
1101
+ }
1102
+ }
1103
+ );
1104
+ server.registerTool(
1105
+ track(mcpToolName(ctx.productName, "health")),
1106
+ {
1107
+ title: "Kadaikodi Health Check",
1108
+ description: "Public health probe for the Kadaikodi subgraph (kadaikodiHealth). Requires no authentication.",
1109
+ inputSchema: {}
1110
+ },
1111
+ async () => {
1112
+ try {
1113
+ const data = await ctx.gql.workspace.request(HEALTH, {});
1114
+ return jsonResult({ ok: true, status: data.kadaikodiHealth });
1115
+ } catch (error) {
1116
+ ctx.logger.error("kadaikodi health failed", { error: String(error) });
1117
+ return errorResult(
1118
+ `Kadaikodi health check failed: ${error instanceof Error ? error.message : String(error)}`
1119
+ );
1120
+ }
1121
+ }
1122
+ );
1123
+ }
1124
+
1125
+ // src/modules/kadaikodi/resources.ts
1126
+ function registerKadaikodiResources(server, ctx, track) {
1127
+ const schemaUri = track(mcpResourceUri(ctx.productName, "schema"));
1128
+ const dashboardUri = track(mcpResourceUri(ctx.productName, "dashboard"));
1129
+ const analyticsUri = track(mcpResourceUri(ctx.productName, "analytics"));
1130
+ const providersUri = track(mcpResourceUri(ctx.productName, "providers"));
1131
+ server.registerResource(
1132
+ "kadaikodi-schema",
1133
+ schemaUri,
1134
+ {
1135
+ title: "Kadaikodi Domain Schema",
1136
+ description: "Overview of the Kadaikodi marketplace domain \u2014 entities, enums, and the per-entity tool surface.",
1137
+ mimeType: "text/plain"
1138
+ },
1139
+ async () => {
1140
+ ctx.logger.debug(`Resource ${schemaUri} requested`);
1141
+ const schema = `# Kadaikodi Domain (Overview)
1142
+
1143
+ Hyperlocal services + commerce + community-investment marketplace.
1144
+
1145
+ ## Entities
1146
+ - KadaikodiServiceProvider \u2014 a business/storefront (offerings, workers, investment opportunities)
1147
+ - KadaikodiProviderWorker \u2014 staff attached to a provider (has tasks)
1148
+ - KadaikodiWorkerTask \u2014 task assigned to a worker
1149
+ - KadaikodiOffering \u2014 catalog item (PRODUCT or SERVICE)
1150
+ - KadaikodiOrder (+KadaikodiOrderItem) \u2014 customer order + line items
1151
+ - KadaikodiReview \u2014 customer rating + provider response
1152
+ - KadaikodiInvestmentOpportunity \u2014 community fundraise for a provider
1153
+ - KadaikodiInvestment (+KadaikodiInvestmentTransaction) \u2014 an investor's stake + ledger
1154
+
1155
+ ## Enums
1156
+ - ServiceCategory: CLOTHING_FASHION, EDUCATION_SKILLS, FOOD_BEVERAGE, GROCERY_ESSENTIALS, HEALTH_WELLNESS, HOME_SERVICES, PERSONAL_CARE_BEAUTY, REPAIR_MAINTENANCE, RETAIL_MERCHANDISE
1157
+ - ProviderStatus: DRAFT, ACTIVE, VERIFIED, PAUSED, SUSPENDED, ARCHIVED
1158
+ - OfferingKind: PRODUCT, SERVICE
1159
+ - OrderStatus: PENDING, PLACED, CONFIRMED, PREPARING, READY, OUT_FOR_DELIVERY, DELIVERED, COMPLETED, CANCELLED
1160
+ - PaymentStatus: PENDING, PROCESSING, PAID, FAILED, REFUNDED
1161
+ - InvestmentStatus: DRAFT, ACTIVE, FUNDED, CLOSED
1162
+ - RiskLevel: LOW, MEDIUM, HIGH
1163
+
1164
+ ## Tool groups
1165
+ providers, workers, tasks, offerings, orders, reviews, investments, analytics.
1166
+ All run against the WORKSPACE gateway (workspace-scoped) except the public health probe.
1167
+ `;
1168
+ return {
1169
+ contents: [{ uri: schemaUri, text: schema, mimeType: "text/plain" }]
1170
+ };
1171
+ }
1172
+ );
1173
+ server.registerResource(
1174
+ "kadaikodi-dashboard",
1175
+ dashboardUri,
1176
+ {
1177
+ title: "Kadaikodi Dashboard Stats",
1178
+ description: "Live headline marketplace KPIs (providers, customers, orders, revenue, rating).",
1179
+ mimeType: "application/json"
1180
+ },
1181
+ async () => {
1182
+ ctx.logger.debug(`Resource ${dashboardUri} requested`);
1183
+ try {
1184
+ const data = await ctx.gql.workspace.request(
1185
+ DASHBOARD_STATS,
1186
+ {}
1187
+ );
1188
+ return {
1189
+ contents: [
1190
+ {
1191
+ uri: dashboardUri,
1192
+ text: JSON.stringify(data.kadaikodiDashboardStats, null, 2),
1193
+ mimeType: "application/json"
1194
+ }
1195
+ ]
1196
+ };
1197
+ } catch (error) {
1198
+ return {
1199
+ contents: [
1200
+ {
1201
+ uri: dashboardUri,
1202
+ text: JSON.stringify({
1203
+ error: error instanceof Error ? error.message : String(error)
1204
+ }),
1205
+ mimeType: "application/json"
1206
+ }
1207
+ ]
1208
+ };
1209
+ }
1210
+ }
1211
+ );
1212
+ server.registerResource(
1213
+ "kadaikodi-analytics",
1214
+ analyticsUri,
1215
+ {
1216
+ title: "Kadaikodi Admin Analytics",
1217
+ description: "Marketplace-wide analytics: category distribution, customer growth, order trends, revenue by category, top providers.",
1218
+ mimeType: "application/json"
1219
+ },
1220
+ async () => {
1221
+ ctx.logger.debug(`Resource ${analyticsUri} requested`);
1222
+ try {
1223
+ const data = await ctx.gql.workspace.request(
1224
+ ADMIN_ANALYTICS,
1225
+ {}
1226
+ );
1227
+ return {
1228
+ contents: [
1229
+ {
1230
+ uri: analyticsUri,
1231
+ text: JSON.stringify(data.kadaikodiAdminAnalytics, null, 2),
1232
+ mimeType: "application/json"
1233
+ }
1234
+ ]
1235
+ };
1236
+ } catch (error) {
1237
+ return {
1238
+ contents: [
1239
+ {
1240
+ uri: analyticsUri,
1241
+ text: JSON.stringify({
1242
+ error: error instanceof Error ? error.message : String(error)
1243
+ }),
1244
+ mimeType: "application/json"
1245
+ }
1246
+ ]
1247
+ };
1248
+ }
1249
+ }
1250
+ );
1251
+ server.registerResource(
1252
+ "kadaikodi-providers",
1253
+ providersUri,
1254
+ {
1255
+ title: "Kadaikodi Provider Directory",
1256
+ description: "The first 50 service providers in the bound workspace.",
1257
+ mimeType: "application/json"
1258
+ },
1259
+ async () => {
1260
+ ctx.logger.debug(`Resource ${providersUri} requested`);
1261
+ try {
1262
+ const data = await ctx.gql.workspace.request(
1263
+ LIST_SERVICE_PROVIDERS,
1264
+ { limit: 50, offset: 0 }
1265
+ );
1266
+ return {
1267
+ contents: [
1268
+ {
1269
+ uri: providersUri,
1270
+ text: JSON.stringify(data.listServiceProviders, null, 2),
1271
+ mimeType: "application/json"
1272
+ }
1273
+ ]
1274
+ };
1275
+ } catch (error) {
1276
+ return {
1277
+ contents: [
1278
+ {
1279
+ uri: providersUri,
1280
+ text: JSON.stringify({
1281
+ error: error instanceof Error ? error.message : String(error)
1282
+ }),
1283
+ mimeType: "application/json"
1284
+ }
1285
+ ]
1286
+ };
1287
+ }
1288
+ }
1289
+ );
1290
+ }
1291
+ function registerKadaikodiPrompts(server, ctx, track) {
1292
+ const p = ctx.productName;
1293
+ const onboardingName = track(mcpPromptName(p, "provider-onboarding"));
1294
+ const opsName = track(mcpPromptName(p, "marketplace-ops"));
1295
+ server.registerPrompt(
1296
+ onboardingName,
1297
+ {
1298
+ title: "Provider Onboarding",
1299
+ description: "Guide for onboarding a new Kadaikodi service provider end to end: create the provider, add catalog offerings, and optionally open an investment opportunity.",
1300
+ argsSchema: {
1301
+ name: z.string().optional().describe("Provider/business name"),
1302
+ category: z.string().optional().describe("Service category")
1303
+ }
1304
+ },
1305
+ ({ name, category }) => {
1306
+ ctx.logger.debug(`Prompt ${onboardingName} called`, { name, category });
1307
+ const nameNote = name ? `Use the business name "${name}".` : "Ask the user for the business name.";
1308
+ const categoryNote = category ? `Use category ${category}.` : "Help the user pick a ServiceCategory.";
1309
+ return {
1310
+ messages: [
1311
+ {
1312
+ role: "user",
1313
+ content: {
1314
+ type: "text",
1315
+ text: `Help me onboard a new Kadaikodi service provider.
1316
+
1317
+ 1. **Create Provider**: Use ${p}_providers_create. ${nameNote} ${categoryNote} Provide a unique slug, ownerId, and a location JSON ({ address, latitude, longitude }).
1318
+ 2. **Add Offerings**: Use ${p}_offerings_create for each catalog item \u2014 set kind=PRODUCT (with stock) or kind=SERVICE (with durationMinutes), a price, and a unique slug per provider.
1319
+ 3. **Verify Catalog**: Use ${p}_offerings_list filtered by the new providerId.
1320
+ 4. **(Optional) Open Investment**: Use ${p}_investments_opportunities_create to raise community capital (targetAmount, minimumInvestment, expectedReturnsPct, lockInMonths, riskLevel).
1321
+ 5. **Activate**: Use ${p}_providers_update with status=VERIFIED (or ACTIVE) when ready.
1322
+
1323
+ Show results at each step and confirm before activation.`
1324
+ }
1325
+ }
1326
+ ]
1327
+ };
1328
+ }
1329
+ );
1330
+ server.registerPrompt(
1331
+ opsName,
1332
+ {
1333
+ title: "Marketplace Operations",
1334
+ description: "Daily operations workflow for a provider: triage the order queue, advance fulfilment, respond to reviews, and review KPIs.",
1335
+ argsSchema: {
1336
+ providerId: z.string().optional().describe("Provider ID to operate")
1337
+ }
1338
+ },
1339
+ ({ providerId }) => {
1340
+ ctx.logger.debug(`Prompt ${opsName} called`, { providerId });
1341
+ const providerNote = providerId ? `Operate provider "${providerId}".` : `First list providers with ${p}_providers_list and pick one.`;
1342
+ return {
1343
+ messages: [
1344
+ {
1345
+ role: "user",
1346
+ content: {
1347
+ type: "text",
1348
+ text: `Run daily Kadaikodi marketplace operations. ${providerNote}
1349
+
1350
+ 1. **KPIs**: Use ${p}_analytics_dashboard for headline numbers and ${p}_analytics_admin for trends.
1351
+ 2. **Order Queue**: Use ${p}_orders_list filtered by providerId and status=PLACED (and PENDING) to find new orders.
1352
+ 3. **Advance Fulfilment**: For each order use ${p}_orders_update_status to move it through CONFIRMED \u2192 PREPARING \u2192 READY \u2192 OUT_FOR_DELIVERY \u2192 DELIVERED \u2192 COMPLETED.
1353
+ 4. **Reviews**: Use ${p}_reviews_list for the provider; reply to unanswered ones with ${p}_reviews_respond.
1354
+ 5. **Workforce**: Use ${p}_workers_list and ${p}_tasks_list to check worker task load.
1355
+ 6. **Investments**: If fundraising, use ${p}_investments_opportunities_list to track raised vs target.
1356
+
1357
+ Summarize what needs attention after each step.`
1358
+ }
1359
+ }
1360
+ ]
1361
+ };
1362
+ }
1363
+ );
1364
+ }
1365
+
1366
+ // src/modules/kadaikodi/index.ts
1367
+ var kadaikodiModule = {
1368
+ id: "kadaikodi",
1369
+ version: "0.0.1",
1370
+ displayName: "Kadaikodi",
1371
+ dependsOn: ["auth"],
1372
+ capabilities: { tools: {}, resources: {}, prompts: {} },
1373
+ register(server, ctx) {
1374
+ const tools = [];
1375
+ const resources = [];
1376
+ const prompts = [];
1377
+ const trackTool = (n) => {
1378
+ tools.push(n);
1379
+ return n;
1380
+ };
1381
+ const trackResource = (uri) => {
1382
+ resources.push(uri);
1383
+ return uri;
1384
+ };
1385
+ const trackPrompt = (n) => {
1386
+ prompts.push(n);
1387
+ return n;
1388
+ };
1389
+ registerProviderTools(server, ctx, trackTool);
1390
+ registerWorkerTools(server, ctx, trackTool);
1391
+ registerTaskTools(server, ctx, trackTool);
1392
+ registerOfferingTools(server, ctx, trackTool);
1393
+ registerOrderTools(server, ctx, trackTool);
1394
+ registerReviewTools(server, ctx, trackTool);
1395
+ registerInvestmentTools(server, ctx, trackTool);
1396
+ registerAnalyticsTools(server, ctx, trackTool);
1397
+ registerKadaikodiResources(server, ctx, trackResource);
1398
+ registerKadaikodiPrompts(server, ctx, trackPrompt);
1399
+ return { tools, resources, prompts };
1400
+ }
1401
+ };
1402
+ var kadaikodi_default = kadaikodiModule;
1403
+
1404
+ export { kadaikodi_default as default };
1405
+ //# sourceMappingURL=index.js.map
1406
+ //# sourceMappingURL=index.js.map