@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.
- package/dist/{chunk-HRWIDQJE.js → chunk-XITZQYB2.js} +8 -3
- package/dist/{chunk-HRWIDQJE.js.map → chunk-XITZQYB2.js.map} +1 -1
- package/dist/modules/crewfoundry/index.cjs +1598 -0
- package/dist/modules/crewfoundry/index.cjs.map +1 -0
- package/dist/modules/crewfoundry/index.d.cts +8 -0
- package/dist/modules/crewfoundry/index.d.ts +8 -0
- package/dist/modules/crewfoundry/index.js +1537 -0
- package/dist/modules/crewfoundry/index.js.map +1 -0
- package/dist/modules/ggnomad/index.cjs +1068 -0
- package/dist/modules/ggnomad/index.cjs.map +1 -0
- package/dist/modules/ggnomad/index.d.cts +8 -0
- package/dist/modules/ggnomad/index.d.ts +8 -0
- package/dist/modules/ggnomad/index.js +1007 -0
- package/dist/modules/ggnomad/index.js.map +1 -0
- package/dist/modules/housingvista/index.cjs +1092 -0
- package/dist/modules/housingvista/index.cjs.map +1 -0
- package/dist/modules/housingvista/index.d.cts +8 -0
- package/dist/modules/housingvista/index.d.ts +8 -0
- package/dist/modules/housingvista/index.js +1031 -0
- package/dist/modules/housingvista/index.js.map +1 -0
- package/dist/modules/kadaikodi/index.cjs +1467 -0
- package/dist/modules/kadaikodi/index.cjs.map +1 -0
- package/dist/modules/kadaikodi/index.d.cts +8 -0
- package/dist/modules/kadaikodi/index.d.ts +8 -0
- package/dist/modules/kadaikodi/index.js +1406 -0
- package/dist/modules/kadaikodi/index.js.map +1 -0
- package/dist/modules/sandbox/index.cjs +26 -0
- package/dist/modules/sandbox/index.cjs.map +1 -1
- package/dist/modules/sandbox/index.js +22 -1
- package/dist/modules/sandbox/index.js.map +1 -1
- package/dist/modules/vibecontrols/index.cjs.map +1 -1
- package/dist/modules/vibecontrols/index.js +1 -1
- package/package.json +1 -1
|
@@ -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
|