@open-loyalty/mcp-server 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/client/http.d.ts +5 -0
  2. package/dist/client/http.js +52 -3
  3. package/dist/config.d.ts +16 -2
  4. package/dist/config.js +28 -10
  5. package/dist/http.js +135 -62
  6. package/dist/server.js +8 -5
  7. package/dist/tools/achievement.d.ts +14 -0
  8. package/dist/tools/achievement.js +22 -15
  9. package/dist/tools/admin.d.ts +12 -0
  10. package/dist/tools/admin.js +12 -0
  11. package/dist/tools/analytics.d.ts +18 -0
  12. package/dist/tools/analytics.js +28 -19
  13. package/dist/tools/apikey.d.ts +7 -0
  14. package/dist/tools/apikey.js +7 -0
  15. package/dist/tools/audit.d.ts +4 -0
  16. package/dist/tools/audit.js +4 -0
  17. package/dist/tools/badge.d.ts +8 -0
  18. package/dist/tools/badge.js +13 -9
  19. package/dist/tools/campaign.d.ts +41 -16
  20. package/dist/tools/campaign.js +38 -25
  21. package/dist/tools/export.d.ts +8 -0
  22. package/dist/tools/export.js +13 -8
  23. package/dist/tools/import.d.ts +6 -0
  24. package/dist/tools/import.js +10 -6
  25. package/dist/tools/index.d.ts +3 -11
  26. package/dist/tools/index.js +4 -470
  27. package/dist/tools/member.d.ts +21 -0
  28. package/dist/tools/member.js +56 -62
  29. package/dist/tools/points.d.ts +12 -0
  30. package/dist/tools/points.js +30 -29
  31. package/dist/tools/reward.d.ts +18 -0
  32. package/dist/tools/reward.js +56 -66
  33. package/dist/tools/role.d.ts +20 -1
  34. package/dist/tools/role.js +13 -0
  35. package/dist/tools/segment.d.ts +19 -0
  36. package/dist/tools/segment.js +29 -19
  37. package/dist/tools/store.d.ts +8 -0
  38. package/dist/tools/store.js +8 -0
  39. package/dist/tools/tierset.d.ts +12 -0
  40. package/dist/tools/tierset.js +19 -13
  41. package/dist/tools/transaction.d.ts +12 -4
  42. package/dist/tools/transaction.js +13 -9
  43. package/dist/tools/wallet-type.d.ts +4 -0
  44. package/dist/tools/wallet-type.js +7 -5
  45. package/dist/tools/webhook.d.ts +17 -4
  46. package/dist/tools/webhook.js +58 -15
  47. package/dist/types/schemas/achievement.d.ts +0 -297
  48. package/dist/types/schemas/achievement.js +0 -13
  49. package/dist/types/schemas/admin.d.ts +10 -97
  50. package/dist/types/schemas/admin.js +0 -38
  51. package/dist/types/schemas/badge.d.ts +0 -37
  52. package/dist/types/schemas/badge.js +0 -11
  53. package/dist/types/schemas/campaign.d.ts +0 -648
  54. package/dist/types/schemas/campaign.js +0 -18
  55. package/dist/types/schemas/export.d.ts +0 -17
  56. package/dist/types/schemas/export.js +0 -7
  57. package/dist/types/schemas/member.d.ts +37 -176
  58. package/dist/types/schemas/member.js +0 -27
  59. package/dist/types/schemas/points.d.ts +0 -63
  60. package/dist/types/schemas/points.js +0 -22
  61. package/dist/types/schemas/reward.d.ts +0 -73
  62. package/dist/types/schemas/reward.js +0 -25
  63. package/dist/types/schemas/role.d.ts +0 -100
  64. package/dist/types/schemas/role.js +0 -29
  65. package/dist/types/schemas/segment.d.ts +0 -58
  66. package/dist/types/schemas/segment.js +0 -17
  67. package/dist/types/schemas/tierset.d.ts +0 -176
  68. package/dist/types/schemas/tierset.js +0 -27
  69. package/dist/types/schemas/transaction.d.ts +23 -254
  70. package/dist/types/schemas/transaction.js +0 -7
  71. package/dist/types/schemas/webhook.d.ts +0 -58
  72. package/dist/types/schemas/webhook.js +0 -12
  73. package/dist/utils/payload.d.ts +12 -0
  74. package/dist/utils/payload.js +14 -0
  75. package/package.json +3 -1
@@ -2,7 +2,8 @@ import { z } from "zod";
2
2
  import { apiGet, apiPost, apiPut } from "../client/http.js";
3
3
  import { RewardSchema, } from "../types/schemas/reward.js";
4
4
  import { formatApiError, OpenLoyaltyError } from "../utils/errors.js";
5
- import { getConfig } from "../config.js";
5
+ import { getStoreCode } from "../config.js";
6
+ import { omitUndefined } from "../utils/payload.js";
6
7
  // Input Schemas
7
8
  export const RewardListInputSchema = {
8
9
  storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
@@ -69,8 +70,7 @@ export const RewardCategoryListInputSchema = {
69
70
  };
70
71
  // Handler functions
71
72
  export async function rewardList(input) {
72
- const config = getConfig();
73
- const storeCode = input.storeCode || config.defaultStoreCode;
73
+ const storeCode = getStoreCode(input.storeCode);
74
74
  const params = new URLSearchParams();
75
75
  if (input.page)
76
76
  params.append("_page", String(input.page));
@@ -111,34 +111,22 @@ export async function rewardList(input) {
111
111
  }
112
112
  }
113
113
  export async function rewardCreate(input) {
114
- const config = getConfig();
115
- const storeCode = input.storeCode || config.defaultStoreCode;
116
- const payload = {
114
+ const storeCode = getStoreCode(input.storeCode);
115
+ const payload = omitUndefined({
117
116
  name: input.name,
118
117
  type: input.type,
119
- };
120
- if (input.costInPoints !== undefined)
121
- payload.costInPoints = input.costInPoints;
122
- if (input.description)
123
- payload.description = input.description;
124
- if (input.usageInstruction)
125
- payload.usageInstruction = input.usageInstruction;
126
- if (input.active !== undefined)
127
- payload.active = input.active;
128
- if (input.categories)
129
- payload.categories = input.categories;
130
- if (input.levels)
131
- payload.levels = input.levels;
132
- if (input.segments)
133
- payload.segments = input.segments;
134
- if (input.target !== undefined)
135
- payload.target = input.target;
136
- if (input.couponValue !== undefined)
137
- payload.couponValue = input.couponValue;
138
- if (input.couponValueType)
139
- payload.couponValueType = input.couponValueType;
140
- if (input.daysValid !== undefined)
141
- payload.daysValid = input.daysValid;
118
+ costInPoints: input.costInPoints,
119
+ description: input.description,
120
+ usageInstruction: input.usageInstruction,
121
+ active: input.active,
122
+ categories: input.categories,
123
+ levels: input.levels,
124
+ segments: input.segments,
125
+ target: input.target,
126
+ couponValue: input.couponValue,
127
+ couponValueType: input.couponValueType,
128
+ daysValid: input.daysValid,
129
+ });
142
130
  try {
143
131
  const response = await apiPost(`/${storeCode}/reward`, { reward: payload });
144
132
  return {
@@ -152,8 +140,7 @@ export async function rewardCreate(input) {
152
140
  }
153
141
  }
154
142
  export async function rewardGet(input) {
155
- const config = getConfig();
156
- const storeCode = input.storeCode || config.defaultStoreCode;
143
+ const storeCode = getStoreCode(input.storeCode);
157
144
  try {
158
145
  const response = await apiGet(`/${storeCode}/reward/${input.rewardId}`);
159
146
  return RewardSchema.parse(response);
@@ -163,23 +150,16 @@ export async function rewardGet(input) {
163
150
  }
164
151
  }
165
152
  export async function rewardUpdate(input) {
166
- const config = getConfig();
167
- const storeCode = input.storeCode || config.defaultStoreCode;
168
- const payload = {};
169
- if (input.name)
170
- payload.name = input.name;
171
- if (input.costInPoints !== undefined)
172
- payload.costInPoints = input.costInPoints;
173
- if (input.description)
174
- payload.description = input.description;
175
- if (input.active !== undefined)
176
- payload.active = input.active;
177
- if (input.categories)
178
- payload.categories = input.categories;
179
- if (input.levels)
180
- payload.levels = input.levels;
181
- if (input.segments)
182
- payload.segments = input.segments;
153
+ const storeCode = getStoreCode(input.storeCode);
154
+ const payload = omitUndefined({
155
+ name: input.name,
156
+ costInPoints: input.costInPoints,
157
+ description: input.description,
158
+ active: input.active,
159
+ categories: input.categories,
160
+ levels: input.levels,
161
+ segments: input.segments,
162
+ });
183
163
  try {
184
164
  await apiPut(`/${storeCode}/reward/${input.rewardId}`, { reward: payload });
185
165
  }
@@ -188,8 +168,7 @@ export async function rewardUpdate(input) {
188
168
  }
189
169
  }
190
170
  export async function rewardActivate(input) {
191
- const config = getConfig();
192
- const storeCode = input.storeCode || config.defaultStoreCode;
171
+ const storeCode = getStoreCode(input.storeCode);
193
172
  try {
194
173
  await apiPost(`/${storeCode}/reward/${input.rewardId}/activate`);
195
174
  }
@@ -198,8 +177,7 @@ export async function rewardActivate(input) {
198
177
  }
199
178
  }
200
179
  export async function rewardDeactivate(input) {
201
- const config = getConfig();
202
- const storeCode = input.storeCode || config.defaultStoreCode;
180
+ const storeCode = getStoreCode(input.storeCode);
203
181
  try {
204
182
  await apiPost(`/${storeCode}/reward/${input.rewardId}/deactivate`);
205
183
  }
@@ -208,17 +186,13 @@ export async function rewardDeactivate(input) {
208
186
  }
209
187
  }
210
188
  export async function rewardBuy(input) {
211
- const config = getConfig();
212
- const storeCode = input.storeCode || config.defaultStoreCode;
213
- const payload = {
189
+ const storeCode = getStoreCode(input.storeCode);
190
+ const payload = omitUndefined({
214
191
  customerId: input.memberId,
215
- };
216
- if (input.quantity)
217
- payload.quantity = input.quantity;
218
- if (input.couponValue !== undefined)
219
- payload.couponValue = input.couponValue;
220
- if (input.withoutPoints !== undefined)
221
- payload.withoutPoints = input.withoutPoints;
192
+ quantity: input.quantity,
193
+ couponValue: input.couponValue,
194
+ withoutPoints: input.withoutPoints,
195
+ });
222
196
  try {
223
197
  const response = await apiPost(`/${storeCode}/reward/${input.rewardId}/buy`, payload);
224
198
  // API returns array of issued rewards
@@ -242,8 +216,7 @@ export async function rewardBuy(input) {
242
216
  }
243
217
  }
244
218
  export async function rewardRedeem(input) {
245
- const config = getConfig();
246
- const storeCode = input.storeCode || config.defaultStoreCode;
219
+ const storeCode = getStoreCode(input.storeCode);
247
220
  try {
248
221
  const response = await apiPost(`/${storeCode}/member/${input.memberId}/reward/redeem`, { couponCode: input.couponCode });
249
222
  return { code: response.code || input.couponCode, used: true };
@@ -278,8 +251,7 @@ export async function rewardRedeem(input) {
278
251
  }
279
252
  }
280
253
  export async function rewardCategoryList(input) {
281
- const config = getConfig();
282
- const storeCode = input.storeCode || config.defaultStoreCode;
254
+ const storeCode = getStoreCode(input.storeCode);
283
255
  const params = new URLSearchParams();
284
256
  if (input.page)
285
257
  params.append("_page", String(input.page));
@@ -310,61 +282,79 @@ export async function rewardCategoryList(input) {
310
282
  export const rewardToolDefinitions = [
311
283
  {
312
284
  name: "openloyalty_reward_list",
285
+ title: "Browse Rewards",
313
286
  description: "List available rewards. Use reward_get for full details or reward_buy to redeem. " +
314
287
  "Filter by type, active status, or category.",
288
+ readOnly: true,
315
289
  inputSchema: RewardListInputSchema,
316
290
  handler: rewardList,
317
291
  },
318
292
  {
319
293
  name: "openloyalty_reward_create",
294
+ title: "Create New Reward",
320
295
  description: "Create a new reward that members can redeem with points. " +
321
296
  "Types: static_coupon (fixed discount), dynamic_coupon (variable value set at purchase), " +
322
297
  "material (physical goods), conversion_coupon (converts points), fortune_wheel (gamified). " +
323
298
  "Returns rewardId.",
299
+ readOnly: false,
324
300
  inputSchema: RewardCreateInputSchema,
325
301
  handler: rewardCreate,
326
302
  },
327
303
  {
328
304
  name: "openloyalty_reward_get",
305
+ title: "Get Reward Details",
329
306
  description: "Get full reward details including configuration, targeting, and coupon settings.",
307
+ readOnly: true,
330
308
  inputSchema: RewardGetInputSchema,
331
309
  handler: rewardGet,
332
310
  },
333
311
  {
334
312
  name: "openloyalty_reward_update",
313
+ title: "Update Reward",
335
314
  description: "Update reward configuration. Cannot change reward type after creation.",
315
+ readOnly: false,
336
316
  inputSchema: RewardUpdateInputSchema,
337
317
  handler: rewardUpdate,
338
318
  },
339
319
  {
340
320
  name: "openloyalty_reward_activate",
321
+ title: "Activate Reward",
341
322
  description: "Activate a reward, making it available for members to redeem.",
323
+ readOnly: false,
342
324
  inputSchema: RewardIdInputSchema,
343
325
  handler: rewardActivate,
344
326
  },
345
327
  {
346
328
  name: "openloyalty_reward_deactivate",
329
+ title: "Deactivate Reward",
347
330
  description: "Deactivate a reward, hiding it from members. Already purchased rewards remain valid.",
331
+ readOnly: false,
348
332
  inputSchema: RewardIdInputSchema,
349
333
  handler: rewardDeactivate,
350
334
  },
351
335
  {
352
336
  name: "openloyalty_reward_buy",
337
+ title: "Redeem Reward for Member",
353
338
  description: "Purchase reward for member, deducting points. Returns issuedRewardId and couponCode if applicable. " +
354
339
  "Use reward_redeem to mark the coupon as used.",
340
+ readOnly: false,
355
341
  inputSchema: RewardBuyInputSchema,
356
342
  handler: rewardBuy,
357
343
  },
358
344
  {
359
345
  name: "openloyalty_reward_redeem",
346
+ title: "Use Coupon Code",
360
347
  description: "Mark coupon as used. Validates coupon exists, belongs to member, and is active. " +
361
348
  "Fails if coupon is expired, already used, or doesn't exist.",
349
+ readOnly: false,
362
350
  inputSchema: RewardRedeemInputSchema,
363
351
  handler: rewardRedeem,
364
352
  },
365
353
  {
366
354
  name: "openloyalty_reward_category_list",
355
+ title: "List Reward Categories",
367
356
  description: "List reward categories. Use categoryId when creating or filtering rewards.",
357
+ readOnly: true,
368
358
  inputSchema: RewardCategoryListInputSchema,
369
359
  handler: rewardCategoryList,
370
360
  },
@@ -1,5 +1,10 @@
1
1
  import { z } from "zod";
2
- import { Role, RoleListItem, ACLResource, RolePermissionInput } from "../types/schemas/role.js";
2
+ import { Role, RoleListItem, ACLResource } from "../types/schemas/role.js";
3
+ interface RolePermissionInput {
4
+ resource: string;
5
+ access: string;
6
+ filterQuery?: string;
7
+ }
3
8
  export declare const RoleListInputSchema: {
4
9
  page: z.ZodOptional<z.ZodNumber>;
5
10
  perPage: z.ZodOptional<z.ZodNumber>;
@@ -85,7 +90,9 @@ export declare function aclGetResources(): Promise<{
85
90
  }>;
86
91
  export declare const roleToolDefinitions: readonly [{
87
92
  readonly name: "openloyalty_role_list";
93
+ readonly title: "List Roles";
88
94
  readonly description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.";
95
+ readonly readOnly: true;
89
96
  readonly inputSchema: {
90
97
  page: z.ZodOptional<z.ZodNumber>;
91
98
  perPage: z.ZodOptional<z.ZodNumber>;
@@ -96,7 +103,9 @@ export declare const roleToolDefinitions: readonly [{
96
103
  readonly handler: typeof roleList;
97
104
  }, {
98
105
  readonly name: "openloyalty_role_create";
106
+ readonly title: "Create Role";
99
107
  readonly description: "Create a new role with permissions. Requires name. Optionally specify permissions (array of {resource, access, filterQuery}) and stores. Returns void on success (201 Created).";
108
+ readonly readOnly: false;
100
109
  readonly inputSchema: {
101
110
  name: z.ZodString;
102
111
  permissions: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -118,14 +127,18 @@ export declare const roleToolDefinitions: readonly [{
118
127
  readonly handler: typeof roleCreate;
119
128
  }, {
120
129
  readonly name: "openloyalty_role_get";
130
+ readonly title: "Get Role Details";
121
131
  readonly description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.";
132
+ readonly readOnly: true;
122
133
  readonly inputSchema: {
123
134
  roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
124
135
  };
125
136
  readonly handler: typeof roleGet;
126
137
  }, {
127
138
  readonly name: "openloyalty_role_update";
139
+ readonly title: "Update Role";
128
140
  readonly description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).";
141
+ readonly readOnly: false;
129
142
  readonly inputSchema: {
130
143
  roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
131
144
  name: z.ZodOptional<z.ZodString>;
@@ -148,14 +161,20 @@ export declare const roleToolDefinitions: readonly [{
148
161
  readonly handler: typeof roleUpdate;
149
162
  }, {
150
163
  readonly name: "openloyalty_role_delete";
164
+ readonly title: "Delete Role (Permanent)";
151
165
  readonly description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.";
166
+ readonly readOnly: false;
167
+ readonly destructive: true;
152
168
  readonly inputSchema: {
153
169
  roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
154
170
  };
155
171
  readonly handler: typeof roleDelete;
156
172
  }, {
157
173
  readonly name: "openloyalty_acl_get_resources";
174
+ readonly title: "Get ACL Resources";
158
175
  readonly description: "Get list of available ACL resources. Returns items with code and name for each resource type. Use this to discover available permissions before creating roles.";
176
+ readonly readOnly: true;
159
177
  readonly inputSchema: {};
160
178
  readonly handler: typeof aclGetResources;
161
179
  }];
180
+ export {};
@@ -123,37 +123,50 @@ export async function aclGetResources() {
123
123
  export const roleToolDefinitions = [
124
124
  {
125
125
  name: "openloyalty_role_list",
126
+ title: "List Roles",
126
127
  description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.",
128
+ readOnly: true,
127
129
  inputSchema: RoleListInputSchema,
128
130
  handler: roleList,
129
131
  },
130
132
  {
131
133
  name: "openloyalty_role_create",
134
+ title: "Create Role",
132
135
  description: "Create a new role with permissions. Requires name. Optionally specify permissions (array of {resource, access, filterQuery}) and stores. Returns void on success (201 Created).",
136
+ readOnly: false,
133
137
  inputSchema: RoleCreateInputSchema,
134
138
  handler: roleCreate,
135
139
  },
136
140
  {
137
141
  name: "openloyalty_role_get",
142
+ title: "Get Role Details",
138
143
  description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.",
144
+ readOnly: true,
139
145
  inputSchema: RoleGetInputSchema,
140
146
  handler: roleGet,
141
147
  },
142
148
  {
143
149
  name: "openloyalty_role_update",
150
+ title: "Update Role",
144
151
  description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).",
152
+ readOnly: false,
145
153
  inputSchema: RoleUpdateInputSchema,
146
154
  handler: roleUpdate,
147
155
  },
148
156
  {
149
157
  name: "openloyalty_role_delete",
158
+ title: "Delete Role (Permanent)",
150
159
  description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.",
160
+ readOnly: false,
161
+ destructive: true,
151
162
  inputSchema: RoleDeleteInputSchema,
152
163
  handler: roleDelete,
153
164
  },
154
165
  {
155
166
  name: "openloyalty_acl_get_resources",
167
+ title: "Get ACL Resources",
156
168
  description: "Get list of available ACL resources. Returns items with code and name for each resource type. Use this to discover available permissions before creating roles.",
169
+ readOnly: true,
157
170
  inputSchema: {},
158
171
  handler: aclGetResources,
159
172
  },
@@ -423,7 +423,9 @@ export declare function segmentGetResources(input: {
423
423
  }>;
424
424
  export declare const segmentToolDefinitions: readonly [{
425
425
  readonly name: "openloyalty_segment_list";
426
+ readonly title: "List Segments";
426
427
  readonly description: "List customer segments. Segments group members by criteria (purchase behavior, tier, location, etc). Use for campaign targeting and analytics.";
428
+ readonly readOnly: true;
427
429
  readonly inputSchema: {
428
430
  storeCode: z.ZodOptional<z.ZodString>;
429
431
  page: z.ZodOptional<z.ZodNumber>;
@@ -434,7 +436,9 @@ export declare const segmentToolDefinitions: readonly [{
434
436
  readonly handler: typeof segmentList;
435
437
  }, {
436
438
  readonly name: "openloyalty_segment_create";
439
+ readonly title: "Create Segment";
437
440
  readonly description: "Create segment to group members. Parts use OR logic (member matches if ANY part matches). Criteria within parts use AND logic (must match ALL criteria in that part). Common criteria: tier, transaction_count, points_balance, country. Example - VIP segment: parts: [{ criteria: [{ type: 'tier', tierIds: ['gold-level-id'] }] }]";
441
+ readonly readOnly: false;
438
442
  readonly inputSchema: {
439
443
  storeCode: z.ZodOptional<z.ZodString>;
440
444
  name: z.ZodString;
@@ -589,7 +593,9 @@ export declare const segmentToolDefinitions: readonly [{
589
593
  readonly handler: typeof segmentCreate;
590
594
  }, {
591
595
  readonly name: "openloyalty_segment_get";
596
+ readonly title: "Get Segment Details";
592
597
  readonly description: "Get full segment details including all parts and criteria configurations.";
598
+ readonly readOnly: true;
593
599
  readonly inputSchema: {
594
600
  storeCode: z.ZodOptional<z.ZodString>;
595
601
  segmentId: z.ZodString;
@@ -597,7 +603,9 @@ export declare const segmentToolDefinitions: readonly [{
597
603
  readonly handler: typeof segmentGet;
598
604
  }, {
599
605
  readonly name: "openloyalty_segment_update";
606
+ readonly title: "Update Segment";
600
607
  readonly description: "Update segment configuration. Requires full segment definition (name, parts with criteria). Use segment_get first to retrieve current configuration.";
608
+ readonly readOnly: false;
601
609
  readonly inputSchema: {
602
610
  storeCode: z.ZodOptional<z.ZodString>;
603
611
  segmentId: z.ZodString;
@@ -753,7 +761,10 @@ export declare const segmentToolDefinitions: readonly [{
753
761
  readonly handler: typeof segmentUpdate;
754
762
  }, {
755
763
  readonly name: "openloyalty_segment_delete";
764
+ readonly title: "Delete Segment (Permanent)";
756
765
  readonly description: "Permanently delete a segment. Cannot be undone. Check segment_get_resources first to see what uses this segment.";
766
+ readonly readOnly: false;
767
+ readonly destructive: true;
757
768
  readonly inputSchema: {
758
769
  storeCode: z.ZodOptional<z.ZodString>;
759
770
  segmentId: z.ZodString;
@@ -761,7 +772,9 @@ export declare const segmentToolDefinitions: readonly [{
761
772
  readonly handler: typeof segmentDelete;
762
773
  }, {
763
774
  readonly name: "openloyalty_segment_get_members";
775
+ readonly title: "Get Segment Members";
764
776
  readonly description: "Get members belonging to a segment. Returns paginated list of member details. Use for verifying segment criteria or exporting member lists.";
777
+ readonly readOnly: true;
765
778
  readonly inputSchema: {
766
779
  storeCode: z.ZodOptional<z.ZodString>;
767
780
  segmentId: z.ZodString;
@@ -771,7 +784,9 @@ export declare const segmentToolDefinitions: readonly [{
771
784
  readonly handler: typeof segmentGetMembers;
772
785
  }, {
773
786
  readonly name: "openloyalty_segment_activate";
787
+ readonly title: "Activate Segment";
774
788
  readonly description: "Activate a segment. Active segments are used for campaign targeting and can be queried for members.";
789
+ readonly readOnly: false;
775
790
  readonly inputSchema: {
776
791
  storeCode: z.ZodOptional<z.ZodString>;
777
792
  segmentId: z.ZodString;
@@ -779,7 +794,9 @@ export declare const segmentToolDefinitions: readonly [{
779
794
  readonly handler: typeof segmentActivate;
780
795
  }, {
781
796
  readonly name: "openloyalty_segment_deactivate";
797
+ readonly title: "Deactivate Segment";
782
798
  readonly description: "Deactivate a segment. Deactivated segments are not used for campaign targeting but retain their configuration.";
799
+ readonly readOnly: false;
783
800
  readonly inputSchema: {
784
801
  storeCode: z.ZodOptional<z.ZodString>;
785
802
  segmentId: z.ZodString;
@@ -787,7 +804,9 @@ export declare const segmentToolDefinitions: readonly [{
787
804
  readonly handler: typeof segmentDeactivate;
788
805
  }, {
789
806
  readonly name: "openloyalty_segment_get_resources";
807
+ readonly title: "Get Segment Resources";
790
808
  readonly description: "Get resources (campaigns, rewards, etc.) that use this segment for targeting. Check before deleting a segment.";
809
+ readonly readOnly: true;
791
810
  readonly inputSchema: {
792
811
  storeCode: z.ZodOptional<z.ZodString>;
793
812
  segmentId: z.ZodString;
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { apiGet, apiPost, apiPut, apiDelete } from "../client/http.js";
3
3
  import { formatApiError } from "../utils/errors.js";
4
- import { getConfig } from "../config.js";
4
+ import { getStoreCode } from "../config.js";
5
5
  // Input Schemas
6
6
  export const SegmentListInputSchema = {
7
7
  storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
@@ -79,8 +79,7 @@ export const SegmentGetResourcesInputSchema = {
79
79
  };
80
80
  // Handler functions
81
81
  export async function segmentList(input) {
82
- const config = getConfig();
83
- const storeCode = input.storeCode || config.defaultStoreCode;
82
+ const storeCode = getStoreCode(input.storeCode);
84
83
  const params = new URLSearchParams();
85
84
  if (input.page)
86
85
  params.append("_page", String(input.page));
@@ -116,8 +115,7 @@ export async function segmentList(input) {
116
115
  }
117
116
  }
118
117
  export async function segmentCreate(input) {
119
- const config = getConfig();
120
- const storeCode = input.storeCode || config.defaultStoreCode;
118
+ const storeCode = getStoreCode(input.storeCode);
121
119
  const segmentPayload = {
122
120
  name: input.name,
123
121
  parts: input.parts,
@@ -136,8 +134,7 @@ export async function segmentCreate(input) {
136
134
  }
137
135
  }
138
136
  export async function segmentGet(input) {
139
- const config = getConfig();
140
- const storeCode = input.storeCode || config.defaultStoreCode;
137
+ const storeCode = getStoreCode(input.storeCode);
141
138
  try {
142
139
  const response = await apiGet(`/${storeCode}/segment/${input.segmentId}`);
143
140
  return response;
@@ -147,8 +144,7 @@ export async function segmentGet(input) {
147
144
  }
148
145
  }
149
146
  export async function segmentUpdate(input) {
150
- const config = getConfig();
151
- const storeCode = input.storeCode || config.defaultStoreCode;
147
+ const storeCode = getStoreCode(input.storeCode);
152
148
  const segmentPayload = {
153
149
  name: input.name,
154
150
  parts: input.parts,
@@ -166,8 +162,7 @@ export async function segmentUpdate(input) {
166
162
  }
167
163
  }
168
164
  export async function segmentDelete(input) {
169
- const config = getConfig();
170
- const storeCode = input.storeCode || config.defaultStoreCode;
165
+ const storeCode = getStoreCode(input.storeCode);
171
166
  try {
172
167
  await apiDelete(`/${storeCode}/segment/${input.segmentId}`);
173
168
  }
@@ -176,8 +171,7 @@ export async function segmentDelete(input) {
176
171
  }
177
172
  }
178
173
  export async function segmentGetMembers(input) {
179
- const config = getConfig();
180
- const storeCode = input.storeCode || config.defaultStoreCode;
174
+ const storeCode = getStoreCode(input.storeCode);
181
175
  const params = new URLSearchParams();
182
176
  if (input.page)
183
177
  params.append("_page", String(input.page));
@@ -209,8 +203,7 @@ export async function segmentGetMembers(input) {
209
203
  }
210
204
  }
211
205
  export async function segmentActivate(input) {
212
- const config = getConfig();
213
- const storeCode = input.storeCode || config.defaultStoreCode;
206
+ const storeCode = getStoreCode(input.storeCode);
214
207
  try {
215
208
  await apiPost(`/${storeCode}/segment/${input.segmentId}/activate`, {});
216
209
  }
@@ -219,8 +212,7 @@ export async function segmentActivate(input) {
219
212
  }
220
213
  }
221
214
  export async function segmentDeactivate(input) {
222
- const config = getConfig();
223
- const storeCode = input.storeCode || config.defaultStoreCode;
215
+ const storeCode = getStoreCode(input.storeCode);
224
216
  try {
225
217
  await apiPost(`/${storeCode}/segment/${input.segmentId}/deactivate`, {});
226
218
  }
@@ -229,8 +221,7 @@ export async function segmentDeactivate(input) {
229
221
  }
230
222
  }
231
223
  export async function segmentGetResources(input) {
232
- const config = getConfig();
233
- const storeCode = input.storeCode || config.defaultStoreCode;
224
+ const storeCode = getStoreCode(input.storeCode);
234
225
  try {
235
226
  const response = await apiGet(`/${storeCode}/segment/${input.segmentId}/resources`);
236
227
  const resources = response.items || response.resources || [];
@@ -244,55 +235,74 @@ export async function segmentGetResources(input) {
244
235
  export const segmentToolDefinitions = [
245
236
  {
246
237
  name: "openloyalty_segment_list",
238
+ title: "List Segments",
247
239
  description: "List customer segments. Segments group members by criteria (purchase behavior, tier, location, etc). Use for campaign targeting and analytics.",
240
+ readOnly: true,
248
241
  inputSchema: SegmentListInputSchema,
249
242
  handler: segmentList,
250
243
  },
251
244
  {
252
245
  name: "openloyalty_segment_create",
246
+ title: "Create Segment",
253
247
  description: "Create segment to group members. Parts use OR logic (member matches if ANY part matches). Criteria within parts use AND logic (must match ALL criteria in that part). Common criteria: tier, transaction_count, points_balance, country. Example - VIP segment: parts: [{ criteria: [{ type: 'tier', tierIds: ['gold-level-id'] }] }]",
248
+ readOnly: false,
254
249
  inputSchema: SegmentCreateInputSchema,
255
250
  handler: segmentCreate,
256
251
  },
257
252
  {
258
253
  name: "openloyalty_segment_get",
254
+ title: "Get Segment Details",
259
255
  description: "Get full segment details including all parts and criteria configurations.",
256
+ readOnly: true,
260
257
  inputSchema: SegmentGetInputSchema,
261
258
  handler: segmentGet,
262
259
  },
263
260
  {
264
261
  name: "openloyalty_segment_update",
262
+ title: "Update Segment",
265
263
  description: "Update segment configuration. Requires full segment definition (name, parts with criteria). Use segment_get first to retrieve current configuration.",
264
+ readOnly: false,
266
265
  inputSchema: SegmentUpdateInputSchema,
267
266
  handler: segmentUpdate,
268
267
  },
269
268
  {
270
269
  name: "openloyalty_segment_delete",
270
+ title: "Delete Segment (Permanent)",
271
271
  description: "Permanently delete a segment. Cannot be undone. Check segment_get_resources first to see what uses this segment.",
272
+ readOnly: false,
273
+ destructive: true,
272
274
  inputSchema: SegmentDeleteInputSchema,
273
275
  handler: segmentDelete,
274
276
  },
275
277
  {
276
278
  name: "openloyalty_segment_get_members",
279
+ title: "Get Segment Members",
277
280
  description: "Get members belonging to a segment. Returns paginated list of member details. Use for verifying segment criteria or exporting member lists.",
281
+ readOnly: true,
278
282
  inputSchema: SegmentGetMembersInputSchema,
279
283
  handler: segmentGetMembers,
280
284
  },
281
285
  {
282
286
  name: "openloyalty_segment_activate",
287
+ title: "Activate Segment",
283
288
  description: "Activate a segment. Active segments are used for campaign targeting and can be queried for members.",
289
+ readOnly: false,
284
290
  inputSchema: SegmentActivateInputSchema,
285
291
  handler: segmentActivate,
286
292
  },
287
293
  {
288
294
  name: "openloyalty_segment_deactivate",
295
+ title: "Deactivate Segment",
289
296
  description: "Deactivate a segment. Deactivated segments are not used for campaign targeting but retain their configuration.",
297
+ readOnly: false,
290
298
  inputSchema: SegmentDeactivateInputSchema,
291
299
  handler: segmentDeactivate,
292
300
  },
293
301
  {
294
302
  name: "openloyalty_segment_get_resources",
303
+ title: "Get Segment Resources",
295
304
  description: "Get resources (campaigns, rewards, etc.) that use this segment for targeting. Check before deleting a segment.",
305
+ readOnly: true,
296
306
  inputSchema: SegmentGetResourcesInputSchema,
297
307
  handler: segmentGetResources,
298
308
  },