@open-loyalty/mcp-server 1.5.3 → 1.7.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.
- package/dist/config.d.ts +4 -0
- package/dist/config.js +11 -0
- package/dist/index.js +0 -8
- package/dist/server.js +13 -0
- package/dist/tools/achievement/handlers.js +47 -0
- package/dist/tools/achievement/index.d.ts +11 -4
- package/dist/tools/achievement/index.js +12 -1
- package/dist/tools/achievement/schemas.d.ts +4 -4
- package/dist/tools/achievement/schemas.js +13 -12
- package/dist/tools/admin/handlers.d.ts +48 -0
- package/dist/tools/admin/handlers.js +159 -0
- package/dist/tools/admin/index.d.ts +86 -0
- package/dist/tools/admin/index.js +64 -0
- package/dist/tools/admin/schemas.d.ts +40 -0
- package/dist/tools/admin/schemas.js +40 -0
- package/dist/tools/analytics/handlers.d.ts +42 -0
- package/dist/tools/analytics/handlers.js +282 -0
- package/dist/tools/analytics/index.d.ts +108 -0
- package/dist/tools/analytics/index.js +91 -0
- package/dist/tools/analytics/schemas.d.ts +42 -0
- package/dist/tools/analytics/schemas.js +47 -0
- package/dist/tools/apikey/handlers.d.ts +15 -0
- package/dist/tools/apikey/handlers.js +53 -0
- package/dist/tools/apikey/index.d.ts +41 -0
- package/dist/tools/apikey/index.js +38 -0
- package/dist/tools/apikey/schemas.d.ts +31 -0
- package/dist/tools/apikey/schemas.js +15 -0
- package/dist/tools/audit/handlers.d.ts +20 -0
- package/dist/tools/audit/handlers.js +82 -0
- package/dist/tools/audit/index.d.ts +36 -0
- package/dist/tools/audit/index.js +28 -0
- package/dist/tools/audit/schemas.d.ts +62 -0
- package/dist/tools/audit/schemas.js +18 -0
- package/dist/tools/badge/handlers.d.ts +45 -0
- package/dist/tools/badge/handlers.js +135 -0
- package/dist/tools/badge/index.d.ts +68 -0
- package/dist/tools/badge/index.js +47 -0
- package/dist/tools/badge/schemas.d.ts +37 -0
- package/dist/tools/badge/schemas.js +31 -0
- package/dist/tools/campaign/handlers.js +61 -0
- package/dist/tools/campaign/index.d.ts +12 -0
- package/dist/tools/campaign/index.js +20 -1
- package/dist/tools/campaign/member-handlers.js +37 -1
- package/dist/tools/campaign/schemas.js +16 -14
- package/dist/tools/custom-event/handlers.d.ts +98 -0
- package/dist/tools/custom-event/handlers.js +238 -0
- package/dist/tools/custom-event/index.d.ts +139 -0
- package/dist/tools/custom-event/index.js +78 -0
- package/dist/tools/custom-event/schemas.d.ts +87 -0
- package/dist/tools/custom-event/schemas.js +59 -0
- package/dist/tools/export/handlers.d.ts +29 -0
- package/dist/tools/export/handlers.js +128 -0
- package/dist/tools/export/index.d.ts +56 -0
- package/dist/tools/export/index.js +46 -0
- package/dist/tools/export/schemas.d.ts +42 -0
- package/dist/tools/export/schemas.js +41 -0
- package/dist/tools/import/handlers.d.ts +22 -0
- package/dist/tools/import/handlers.js +123 -0
- package/dist/tools/import/index.d.ts +45 -0
- package/dist/tools/import/index.js +41 -0
- package/dist/tools/import/schemas.d.ts +57 -0
- package/dist/tools/import/schemas.js +39 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +11 -11
- package/dist/tools/member/handlers.js +30 -0
- package/dist/tools/member/index.d.ts +10 -0
- package/dist/tools/member/index.js +10 -0
- package/dist/tools/member/schemas.js +13 -13
- package/dist/tools/points/handlers.js +73 -0
- package/dist/tools/points/index.d.ts +6 -0
- package/dist/tools/points/index.js +6 -0
- package/dist/tools/points/schemas.js +1 -1
- package/dist/tools/referral/index.d.ts +3 -0
- package/dist/tools/referral/index.js +3 -0
- package/dist/tools/reward/handlers.js +21 -13
- package/dist/tools/reward/index.d.ts +9 -0
- package/dist/tools/reward/index.js +12 -1
- package/dist/tools/reward/schemas.js +2 -2
- package/dist/tools/role/handlers.d.ts +35 -0
- package/dist/tools/role/handlers.js +127 -0
- package/dist/tools/role/index.d.ts +99 -0
- package/dist/tools/role/index.js +65 -0
- package/dist/tools/role/schemas.d.ts +56 -0
- package/dist/tools/role/schemas.js +35 -0
- package/dist/tools/segment/handlers.js +68 -1
- package/dist/tools/segment/index.d.ts +9 -0
- package/dist/tools/segment/index.js +13 -0
- package/dist/tools/segment/schemas.js +8 -5
- package/dist/tools/store/handlers.d.ts +25 -0
- package/dist/tools/store/handlers.js +89 -0
- package/dist/tools/store/index.d.ts +55 -0
- package/dist/tools/store/index.js +46 -0
- package/dist/tools/store/schemas.d.ts +38 -0
- package/dist/tools/store/schemas.js +23 -0
- package/dist/tools/tierset/handlers.js +92 -1
- package/dist/tools/tierset/index.d.ts +6 -0
- package/dist/tools/tierset/index.js +8 -1
- package/dist/tools/transaction/handlers.js +40 -0
- package/dist/tools/transaction/index.d.ts +4 -0
- package/dist/tools/transaction/index.js +4 -0
- package/dist/tools/transaction/schemas.js +3 -3
- package/dist/tools/wallet-type/index.d.ts +4 -0
- package/dist/tools/wallet-type/index.js +5 -1
- package/dist/tools/webhook/handlers.d.ts +34 -0
- package/dist/tools/webhook/handlers.js +147 -0
- package/dist/tools/webhook/index.d.ts +97 -0
- package/dist/tools/webhook/index.js +65 -0
- package/dist/tools/webhook/schemas.d.ts +72 -0
- package/dist/tools/{webhook.js → webhook/schemas.js} +0 -140
- package/dist/types/schemas/tierset.js +3 -1
- package/package.json +1 -1
- package/dist/tools/admin.d.ts +0 -165
- package/dist/tools/admin.js +0 -205
- package/dist/tools/analytics.d.ts +0 -180
- package/dist/tools/analytics.js +0 -255
- package/dist/tools/apikey.d.ts +0 -79
- package/dist/tools/apikey.js +0 -85
- package/dist/tools/audit.d.ts +0 -111
- package/dist/tools/audit.js +0 -94
- package/dist/tools/badge.d.ts +0 -143
- package/dist/tools/badge.js +0 -174
- package/dist/tools/custom-event.d.ts +0 -315
- package/dist/tools/custom-event.js +0 -271
- package/dist/tools/export.d.ts +0 -118
- package/dist/tools/export.js +0 -152
- package/dist/tools/import.d.ts +0 -116
- package/dist/tools/import.js +0 -143
- package/dist/tools/role.d.ts +0 -180
- package/dist/tools/role.js +0 -173
- package/dist/tools/store.d.ts +0 -109
- package/dist/tools/store.js +0 -125
- package/dist/tools/webhook.d.ts +0 -192
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export { RoleListInputSchema, RoleCreateInputSchema, RoleGetInputSchema, RoleUpdateInputSchema, RoleDeleteInputSchema, } from "./schemas.js";
|
|
2
|
+
export type { RolePermissionInput } from "./schemas.js";
|
|
3
|
+
export { roleList, roleCreate, roleGet, roleUpdate, roleDelete, aclGetResources, } from "./handlers.js";
|
|
4
|
+
import { roleList, roleCreate, roleGet, roleUpdate, roleDelete, aclGetResources } from "./handlers.js";
|
|
5
|
+
export declare const roleToolDefinitions: readonly [{
|
|
6
|
+
readonly name: "ol_role_list";
|
|
7
|
+
readonly title: "List Roles";
|
|
8
|
+
readonly description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.";
|
|
9
|
+
readonly readOnly: true;
|
|
10
|
+
readonly idempotent: true;
|
|
11
|
+
readonly inputSchema: {
|
|
12
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
13
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
14
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
15
|
+
master: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
16
|
+
default: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
17
|
+
};
|
|
18
|
+
readonly handler: typeof roleList;
|
|
19
|
+
}, {
|
|
20
|
+
readonly name: "ol_role_create";
|
|
21
|
+
readonly title: "Create Role";
|
|
22
|
+
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).";
|
|
23
|
+
readonly readOnly: false;
|
|
24
|
+
readonly idempotent: false;
|
|
25
|
+
readonly inputSchema: {
|
|
26
|
+
name: import("zod").ZodString;
|
|
27
|
+
permissions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
28
|
+
resource: import("zod").ZodString;
|
|
29
|
+
access: import("zod").ZodString;
|
|
30
|
+
filterQuery: import("zod").ZodOptional<import("zod").ZodString>;
|
|
31
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
32
|
+
resource: string;
|
|
33
|
+
access: string;
|
|
34
|
+
filterQuery?: string | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
resource: string;
|
|
37
|
+
access: string;
|
|
38
|
+
filterQuery?: string | undefined;
|
|
39
|
+
}>, "many">>;
|
|
40
|
+
stores: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
41
|
+
default: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
42
|
+
};
|
|
43
|
+
readonly handler: typeof roleCreate;
|
|
44
|
+
}, {
|
|
45
|
+
readonly name: "ol_role_get";
|
|
46
|
+
readonly title: "Get Role Details";
|
|
47
|
+
readonly description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.";
|
|
48
|
+
readonly readOnly: true;
|
|
49
|
+
readonly idempotent: true;
|
|
50
|
+
readonly inputSchema: {
|
|
51
|
+
roleId: import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>;
|
|
52
|
+
};
|
|
53
|
+
readonly handler: typeof roleGet;
|
|
54
|
+
}, {
|
|
55
|
+
readonly name: "ol_role_update";
|
|
56
|
+
readonly title: "Update Role";
|
|
57
|
+
readonly description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).";
|
|
58
|
+
readonly readOnly: false;
|
|
59
|
+
readonly idempotent: true;
|
|
60
|
+
readonly inputSchema: {
|
|
61
|
+
roleId: import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>;
|
|
62
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
63
|
+
permissions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
64
|
+
resource: import("zod").ZodString;
|
|
65
|
+
access: import("zod").ZodString;
|
|
66
|
+
filterQuery: import("zod").ZodOptional<import("zod").ZodString>;
|
|
67
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
68
|
+
resource: string;
|
|
69
|
+
access: string;
|
|
70
|
+
filterQuery?: string | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
resource: string;
|
|
73
|
+
access: string;
|
|
74
|
+
filterQuery?: string | undefined;
|
|
75
|
+
}>, "many">>;
|
|
76
|
+
stores: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
77
|
+
default: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
78
|
+
};
|
|
79
|
+
readonly handler: typeof roleUpdate;
|
|
80
|
+
}, {
|
|
81
|
+
readonly name: "ol_role_delete";
|
|
82
|
+
readonly title: "Delete Role (Permanent)";
|
|
83
|
+
readonly description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.";
|
|
84
|
+
readonly readOnly: false;
|
|
85
|
+
readonly destructive: true;
|
|
86
|
+
readonly idempotent: true;
|
|
87
|
+
readonly inputSchema: {
|
|
88
|
+
roleId: import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>;
|
|
89
|
+
};
|
|
90
|
+
readonly handler: typeof roleDelete;
|
|
91
|
+
}, {
|
|
92
|
+
readonly name: "ol_acl_get_resources";
|
|
93
|
+
readonly title: "Get ACL Resources";
|
|
94
|
+
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.";
|
|
95
|
+
readonly readOnly: true;
|
|
96
|
+
readonly idempotent: true;
|
|
97
|
+
readonly inputSchema: {};
|
|
98
|
+
readonly handler: typeof aclGetResources;
|
|
99
|
+
}];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Re-export schemas and types
|
|
2
|
+
export { RoleListInputSchema, RoleCreateInputSchema, RoleGetInputSchema, RoleUpdateInputSchema, RoleDeleteInputSchema, } from "./schemas.js";
|
|
3
|
+
// Re-export handlers
|
|
4
|
+
export { roleList, roleCreate, roleGet, roleUpdate, roleDelete, aclGetResources, } from "./handlers.js";
|
|
5
|
+
// Imports for tool definitions
|
|
6
|
+
import { RoleListInputSchema, RoleCreateInputSchema, RoleGetInputSchema, RoleUpdateInputSchema, RoleDeleteInputSchema, } from "./schemas.js";
|
|
7
|
+
import { roleList, roleCreate, roleGet, roleUpdate, roleDelete, aclGetResources, } from "./handlers.js";
|
|
8
|
+
// Tool definitions
|
|
9
|
+
export const roleToolDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: "ol_role_list",
|
|
12
|
+
title: "List Roles",
|
|
13
|
+
description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.",
|
|
14
|
+
readOnly: true,
|
|
15
|
+
idempotent: true,
|
|
16
|
+
inputSchema: RoleListInputSchema,
|
|
17
|
+
handler: roleList,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "ol_role_create",
|
|
21
|
+
title: "Create Role",
|
|
22
|
+
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).",
|
|
23
|
+
readOnly: false,
|
|
24
|
+
idempotent: false,
|
|
25
|
+
inputSchema: RoleCreateInputSchema,
|
|
26
|
+
handler: roleCreate,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "ol_role_get",
|
|
30
|
+
title: "Get Role Details",
|
|
31
|
+
description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.",
|
|
32
|
+
readOnly: true,
|
|
33
|
+
idempotent: true,
|
|
34
|
+
inputSchema: RoleGetInputSchema,
|
|
35
|
+
handler: roleGet,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "ol_role_update",
|
|
39
|
+
title: "Update Role",
|
|
40
|
+
description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).",
|
|
41
|
+
readOnly: false,
|
|
42
|
+
idempotent: true,
|
|
43
|
+
inputSchema: RoleUpdateInputSchema,
|
|
44
|
+
handler: roleUpdate,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "ol_role_delete",
|
|
48
|
+
title: "Delete Role (Permanent)",
|
|
49
|
+
description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.",
|
|
50
|
+
readOnly: false,
|
|
51
|
+
destructive: true,
|
|
52
|
+
idempotent: true,
|
|
53
|
+
inputSchema: RoleDeleteInputSchema,
|
|
54
|
+
handler: roleDelete,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "ol_acl_get_resources",
|
|
58
|
+
title: "Get ACL Resources",
|
|
59
|
+
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.",
|
|
60
|
+
readOnly: true,
|
|
61
|
+
idempotent: true,
|
|
62
|
+
inputSchema: {},
|
|
63
|
+
handler: aclGetResources,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export interface RolePermissionInput {
|
|
3
|
+
resource: string;
|
|
4
|
+
access: string;
|
|
5
|
+
filterQuery?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const RoleListInputSchema: {
|
|
8
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
name: z.ZodOptional<z.ZodString>;
|
|
11
|
+
master: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
};
|
|
14
|
+
export declare const RoleCreateInputSchema: {
|
|
15
|
+
name: z.ZodString;
|
|
16
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
17
|
+
resource: z.ZodString;
|
|
18
|
+
access: z.ZodString;
|
|
19
|
+
filterQuery: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
resource: string;
|
|
22
|
+
access: string;
|
|
23
|
+
filterQuery?: string | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
resource: string;
|
|
26
|
+
access: string;
|
|
27
|
+
filterQuery?: string | undefined;
|
|
28
|
+
}>, "many">>;
|
|
29
|
+
stores: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
30
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
};
|
|
32
|
+
export declare const RoleGetInputSchema: {
|
|
33
|
+
roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
34
|
+
};
|
|
35
|
+
export declare const RoleUpdateInputSchema: {
|
|
36
|
+
roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
37
|
+
name: z.ZodOptional<z.ZodString>;
|
|
38
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
39
|
+
resource: z.ZodString;
|
|
40
|
+
access: z.ZodString;
|
|
41
|
+
filterQuery: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, "strip", z.ZodTypeAny, {
|
|
43
|
+
resource: string;
|
|
44
|
+
access: string;
|
|
45
|
+
filterQuery?: string | undefined;
|
|
46
|
+
}, {
|
|
47
|
+
resource: string;
|
|
48
|
+
access: string;
|
|
49
|
+
filterQuery?: string | undefined;
|
|
50
|
+
}>, "many">>;
|
|
51
|
+
stores: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
52
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
53
|
+
};
|
|
54
|
+
export declare const RoleDeleteInputSchema: {
|
|
55
|
+
roleId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
56
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const RoleListInputSchema = {
|
|
3
|
+
page: z.number().optional().describe("Page number (default: 1)."),
|
|
4
|
+
perPage: z.number().optional().describe("Items per page (default: 25)."),
|
|
5
|
+
name: z.string().optional().describe("Filter by role name."),
|
|
6
|
+
master: z.boolean().optional().describe("Filter by master role status."),
|
|
7
|
+
default: z.boolean().optional().describe("Filter by default role status."),
|
|
8
|
+
};
|
|
9
|
+
export const RoleCreateInputSchema = {
|
|
10
|
+
name: z.string().describe("Role name (required)."),
|
|
11
|
+
permissions: z.array(z.object({
|
|
12
|
+
resource: z.string().describe("Resource name (e.g., ANALYTICS, EVENTS). Use ol_acl_get_resources to discover all available resource codes."),
|
|
13
|
+
access: z.string().describe("Access level: VIEW (read-only) or MODIFY (read-write)."),
|
|
14
|
+
filterQuery: z.string().optional().describe("Optional filter query."),
|
|
15
|
+
})).optional().describe("Array of permission definitions."),
|
|
16
|
+
stores: z.array(z.string()).optional().describe("Store codes to assign access (e.g., ['DEFAULT'])."),
|
|
17
|
+
default: z.boolean().optional().describe("Whether this is a default role for new admins."),
|
|
18
|
+
};
|
|
19
|
+
export const RoleGetInputSchema = {
|
|
20
|
+
roleId: z.union([z.string(), z.number()]).describe("The role ID to retrieve."),
|
|
21
|
+
};
|
|
22
|
+
export const RoleUpdateInputSchema = {
|
|
23
|
+
roleId: z.union([z.string(), z.number()]).describe("The role ID to update."),
|
|
24
|
+
name: z.string().optional().describe("Role name."),
|
|
25
|
+
permissions: z.array(z.object({
|
|
26
|
+
resource: z.string().describe("Resource name. Use ol_acl_get_resources to discover all available resource codes."),
|
|
27
|
+
access: z.string().describe("Access level: VIEW (read-only) or MODIFY (read-write)."),
|
|
28
|
+
filterQuery: z.string().optional().describe("Optional filter query."),
|
|
29
|
+
})).optional().describe("Array of permission definitions."),
|
|
30
|
+
stores: z.array(z.string()).optional().describe("Store codes to assign access."),
|
|
31
|
+
default: z.boolean().optional().describe("Whether this is a default role."),
|
|
32
|
+
};
|
|
33
|
+
export const RoleDeleteInputSchema = {
|
|
34
|
+
roleId: z.union([z.string(), z.number()]).describe("The role ID to delete."),
|
|
35
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { apiGet, apiPost, apiPut, apiDelete } from "../../client/http.js";
|
|
2
|
-
import { formatApiError } from "../../utils/errors.js";
|
|
2
|
+
import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
|
|
3
3
|
import { getStoreCode } from "../../config.js";
|
|
4
4
|
const DEFAULT_TRANSACTION_COUNT_MAX = 999999;
|
|
5
5
|
function normalizeSegmentParts(parts) {
|
|
@@ -71,6 +71,25 @@ export async function segmentCreate(input) {
|
|
|
71
71
|
return { segmentId: response.segmentId };
|
|
72
72
|
}
|
|
73
73
|
catch (error) {
|
|
74
|
+
const axiosError = error;
|
|
75
|
+
const apiErrors = axiosError.response?.data?.errors || [];
|
|
76
|
+
const allMessages = [
|
|
77
|
+
axiosError.response?.data?.message || "",
|
|
78
|
+
...apiErrors.map(e => `${e.path || ""}: ${e.message}`)
|
|
79
|
+
].join(" ").toLowerCase();
|
|
80
|
+
if (allMessages.includes("type") && (allMessages.includes("choice is invalid") || allMessages.includes("not valid") || allMessages.includes("invalid"))) {
|
|
81
|
+
throw new OpenLoyaltyError({
|
|
82
|
+
code: "INVALID_CRITERION_TYPE",
|
|
83
|
+
message: "Invalid criterion type in segment definition",
|
|
84
|
+
hint: "Valid criterion types: 'transaction_count' (purchase frequency), 'average_transaction_value', " +
|
|
85
|
+
"'transaction_amount' (total spend), 'transaction_percent_in_period', 'purchase_in_period', " +
|
|
86
|
+
"'bought_skus' (specific products), 'bought_labels' (product categories/tags), " +
|
|
87
|
+
"'bought_makers' (brands), 'customer_list' (manual list), 'anniversary', 'last_purchase_n_days_before', " +
|
|
88
|
+
"'customer_has_labels', 'customer_with_labels_values'. " +
|
|
89
|
+
"NOTE: 'tier' and 'points_balance' are REJECTED by the API despite being documented.",
|
|
90
|
+
relatedTool: "ol_segment_create",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
74
93
|
throw formatApiError(error, "ol_segment_create");
|
|
75
94
|
}
|
|
76
95
|
}
|
|
@@ -81,6 +100,15 @@ export async function segmentGet(input) {
|
|
|
81
100
|
return response;
|
|
82
101
|
}
|
|
83
102
|
catch (error) {
|
|
103
|
+
const axiosError = error;
|
|
104
|
+
if (axiosError.response?.status === 404) {
|
|
105
|
+
throw new OpenLoyaltyError({
|
|
106
|
+
code: "NOT_FOUND",
|
|
107
|
+
message: `Segment '${input.segmentId}' not found`,
|
|
108
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.",
|
|
109
|
+
relatedTool: "ol_segment_get",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
84
112
|
throw formatApiError(error, "ol_segment_get");
|
|
85
113
|
}
|
|
86
114
|
}
|
|
@@ -99,6 +127,20 @@ export async function segmentUpdate(input) {
|
|
|
99
127
|
await apiPut(`/${storeCode}/segment/${input.segmentId}`, { segment: segmentPayload });
|
|
100
128
|
}
|
|
101
129
|
catch (error) {
|
|
130
|
+
const axiosError = error;
|
|
131
|
+
if (axiosError.response?.status === 404) {
|
|
132
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
133
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_update" });
|
|
134
|
+
}
|
|
135
|
+
const apiErrors = axiosError.response?.data?.errors || [];
|
|
136
|
+
const allMessages = [axiosError.response?.data?.message || "", ...apiErrors.map(e => `${e.path || ""}: ${e.message}`)].join(" ").toLowerCase();
|
|
137
|
+
if (allMessages.includes("type") && (allMessages.includes("choice is invalid") || allMessages.includes("not valid") || allMessages.includes("invalid"))) {
|
|
138
|
+
throw new OpenLoyaltyError({ code: "INVALID_CRITERION_TYPE", message: "Invalid criterion type in segment definition",
|
|
139
|
+
hint: "Valid criterion types: 'transaction_count', 'average_transaction_value', 'transaction_amount', " +
|
|
140
|
+
"'purchase_in_period', 'bought_skus', 'bought_labels', 'bought_makers', 'customer_list', 'anniversary', " +
|
|
141
|
+
"'last_purchase_n_days_before', 'customer_has_labels', 'customer_with_labels_values'.",
|
|
142
|
+
relatedTool: "ol_segment_update" });
|
|
143
|
+
}
|
|
102
144
|
throw formatApiError(error, "ol_segment_update");
|
|
103
145
|
}
|
|
104
146
|
}
|
|
@@ -108,6 +150,11 @@ export async function segmentDelete(input) {
|
|
|
108
150
|
await apiDelete(`/${storeCode}/segment/${input.segmentId}`);
|
|
109
151
|
}
|
|
110
152
|
catch (error) {
|
|
153
|
+
const axiosError = error;
|
|
154
|
+
if (axiosError.response?.status === 404) {
|
|
155
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
156
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_delete" });
|
|
157
|
+
}
|
|
111
158
|
throw formatApiError(error, "ol_segment_delete");
|
|
112
159
|
}
|
|
113
160
|
}
|
|
@@ -140,6 +187,11 @@ export async function segmentGetMembers(input) {
|
|
|
140
187
|
};
|
|
141
188
|
}
|
|
142
189
|
catch (error) {
|
|
190
|
+
const axiosError = error;
|
|
191
|
+
if (axiosError.response?.status === 404) {
|
|
192
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
193
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_get_members" });
|
|
194
|
+
}
|
|
143
195
|
throw formatApiError(error, "ol_segment_get_members");
|
|
144
196
|
}
|
|
145
197
|
}
|
|
@@ -149,6 +201,11 @@ export async function segmentActivate(input) {
|
|
|
149
201
|
await apiPost(`/${storeCode}/segment/${input.segmentId}/activate`, {});
|
|
150
202
|
}
|
|
151
203
|
catch (error) {
|
|
204
|
+
const axiosError = error;
|
|
205
|
+
if (axiosError.response?.status === 404) {
|
|
206
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
207
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_activate" });
|
|
208
|
+
}
|
|
152
209
|
throw formatApiError(error, "ol_segment_activate");
|
|
153
210
|
}
|
|
154
211
|
}
|
|
@@ -158,6 +215,11 @@ export async function segmentDeactivate(input) {
|
|
|
158
215
|
await apiPost(`/${storeCode}/segment/${input.segmentId}/deactivate`, {});
|
|
159
216
|
}
|
|
160
217
|
catch (error) {
|
|
218
|
+
const axiosError = error;
|
|
219
|
+
if (axiosError.response?.status === 404) {
|
|
220
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
221
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_deactivate" });
|
|
222
|
+
}
|
|
161
223
|
throw formatApiError(error, "ol_segment_deactivate");
|
|
162
224
|
}
|
|
163
225
|
}
|
|
@@ -169,6 +231,11 @@ export async function segmentGetResources(input) {
|
|
|
169
231
|
return { resources };
|
|
170
232
|
}
|
|
171
233
|
catch (error) {
|
|
234
|
+
const axiosError = error;
|
|
235
|
+
if (axiosError.response?.status === 404) {
|
|
236
|
+
throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Segment '${input.segmentId}' not found`,
|
|
237
|
+
hint: "Use ol_segment_list() to find existing segments and their IDs.", relatedTool: "ol_segment_get_resources" });
|
|
238
|
+
}
|
|
172
239
|
throw formatApiError(error, "ol_segment_get_resources");
|
|
173
240
|
}
|
|
174
241
|
}
|
|
@@ -6,6 +6,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
6
6
|
readonly title: "List Segments";
|
|
7
7
|
readonly description: "List customer segments. Segments group members by criteria (purchase behavior, tier, location, etc). Use for campaign targeting and analytics.";
|
|
8
8
|
readonly readOnly: true;
|
|
9
|
+
readonly idempotent: true;
|
|
9
10
|
readonly inputSchema: {
|
|
10
11
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
11
12
|
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
@@ -19,6 +20,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
19
20
|
readonly title: "Create Segment";
|
|
20
21
|
readonly description: string;
|
|
21
22
|
readonly readOnly: false;
|
|
23
|
+
readonly idempotent: false;
|
|
22
24
|
readonly inputSchema: {
|
|
23
25
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
24
26
|
name: import("zod").ZodString;
|
|
@@ -176,6 +178,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
176
178
|
readonly title: "Get Segment Details";
|
|
177
179
|
readonly description: "Get full segment details including all parts and criteria configurations.";
|
|
178
180
|
readonly readOnly: true;
|
|
181
|
+
readonly idempotent: true;
|
|
179
182
|
readonly inputSchema: {
|
|
180
183
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
181
184
|
segmentId: import("zod").ZodString;
|
|
@@ -186,6 +189,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
186
189
|
readonly title: "Update Segment";
|
|
187
190
|
readonly description: "Update segment configuration. Requires full segment definition (name, parts with criteria). Use segment_get first to retrieve current configuration.";
|
|
188
191
|
readonly readOnly: false;
|
|
192
|
+
readonly idempotent: true;
|
|
189
193
|
readonly inputSchema: {
|
|
190
194
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
191
195
|
segmentId: import("zod").ZodString;
|
|
@@ -345,6 +349,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
345
349
|
readonly description: "Permanently delete a segment. Cannot be undone. Check segment_get_resources first to see what uses this segment.";
|
|
346
350
|
readonly readOnly: false;
|
|
347
351
|
readonly destructive: true;
|
|
352
|
+
readonly idempotent: true;
|
|
348
353
|
readonly inputSchema: {
|
|
349
354
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
350
355
|
segmentId: import("zod").ZodString;
|
|
@@ -355,6 +360,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
355
360
|
readonly title: "Get Segment Members";
|
|
356
361
|
readonly description: "Get members belonging to a segment. Returns paginated list of member details. Use for verifying segment criteria or exporting member lists.";
|
|
357
362
|
readonly readOnly: true;
|
|
363
|
+
readonly idempotent: true;
|
|
358
364
|
readonly inputSchema: {
|
|
359
365
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
360
366
|
segmentId: import("zod").ZodString;
|
|
@@ -367,6 +373,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
367
373
|
readonly title: "Activate Segment";
|
|
368
374
|
readonly description: "Activate a segment. Active segments are used for campaign targeting and can be queried for members.";
|
|
369
375
|
readonly readOnly: false;
|
|
376
|
+
readonly idempotent: true;
|
|
370
377
|
readonly inputSchema: {
|
|
371
378
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
372
379
|
segmentId: import("zod").ZodString;
|
|
@@ -377,6 +384,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
377
384
|
readonly title: "Deactivate Segment";
|
|
378
385
|
readonly description: "Deactivate a segment. Deactivated segments are not used for campaign targeting but retain their configuration.";
|
|
379
386
|
readonly readOnly: false;
|
|
387
|
+
readonly idempotent: true;
|
|
380
388
|
readonly inputSchema: {
|
|
381
389
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
382
390
|
segmentId: import("zod").ZodString;
|
|
@@ -387,6 +395,7 @@ export declare const segmentToolDefinitions: readonly [{
|
|
|
387
395
|
readonly title: "Get Segment Resources";
|
|
388
396
|
readonly description: string;
|
|
389
397
|
readonly readOnly: true;
|
|
398
|
+
readonly idempotent: true;
|
|
390
399
|
readonly inputSchema: {
|
|
391
400
|
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
392
401
|
segmentId: import("zod").ZodString;
|
|
@@ -12,6 +12,7 @@ export const segmentToolDefinitions = [
|
|
|
12
12
|
title: "List Segments",
|
|
13
13
|
description: "List customer segments. Segments group members by criteria (purchase behavior, tier, location, etc). Use for campaign targeting and analytics.",
|
|
14
14
|
readOnly: true,
|
|
15
|
+
idempotent: true,
|
|
15
16
|
inputSchema: SegmentListInputSchema,
|
|
16
17
|
handler: segmentList,
|
|
17
18
|
},
|
|
@@ -24,8 +25,13 @@ export const segmentToolDefinitions = [
|
|
|
24
25
|
"2. Threshold values -- min/max boundaries? (e.g., min=5 transactions captures frequent buyers; min=2 captures nearly everyone) " +
|
|
25
26
|
"3. Intended use -- campaign targeting (activate immediately) or analytics only (can stay inactive)? " +
|
|
26
27
|
"REQUIRED: name, parts array with criteria. Parts use OR logic, criteria within parts use AND logic. " +
|
|
28
|
+
"CRITERION FIELDS BY TYPE: " +
|
|
29
|
+
"transaction_count: { type: 'transaction_count', min: N, max: N } (both required, MCP auto-fills max=999999 if omitted). " +
|
|
30
|
+
"purchase_in_period: { type: 'purchase_in_period', days: N, min: N, max: N }. " +
|
|
31
|
+
"average_transaction_value: { type: 'average_transaction_value', min: N, max: N }. " +
|
|
27
32
|
"NOTE: 'tier' and 'points_balance' types are REJECTED by the API despite being documented.",
|
|
28
33
|
readOnly: false,
|
|
34
|
+
idempotent: false,
|
|
29
35
|
inputSchema: SegmentCreateInputSchema,
|
|
30
36
|
handler: segmentCreate,
|
|
31
37
|
},
|
|
@@ -34,6 +40,7 @@ export const segmentToolDefinitions = [
|
|
|
34
40
|
title: "Get Segment Details",
|
|
35
41
|
description: "Get full segment details including all parts and criteria configurations.",
|
|
36
42
|
readOnly: true,
|
|
43
|
+
idempotent: true,
|
|
37
44
|
inputSchema: SegmentGetInputSchema,
|
|
38
45
|
handler: segmentGet,
|
|
39
46
|
},
|
|
@@ -42,6 +49,7 @@ export const segmentToolDefinitions = [
|
|
|
42
49
|
title: "Update Segment",
|
|
43
50
|
description: "Update segment configuration. Requires full segment definition (name, parts with criteria). Use segment_get first to retrieve current configuration.",
|
|
44
51
|
readOnly: false,
|
|
52
|
+
idempotent: true,
|
|
45
53
|
inputSchema: SegmentUpdateInputSchema,
|
|
46
54
|
handler: segmentUpdate,
|
|
47
55
|
},
|
|
@@ -51,6 +59,7 @@ export const segmentToolDefinitions = [
|
|
|
51
59
|
description: "Permanently delete a segment. Cannot be undone. Check segment_get_resources first to see what uses this segment.",
|
|
52
60
|
readOnly: false,
|
|
53
61
|
destructive: true,
|
|
62
|
+
idempotent: true,
|
|
54
63
|
inputSchema: SegmentDeleteInputSchema,
|
|
55
64
|
handler: segmentDelete,
|
|
56
65
|
},
|
|
@@ -59,6 +68,7 @@ export const segmentToolDefinitions = [
|
|
|
59
68
|
title: "Get Segment Members",
|
|
60
69
|
description: "Get members belonging to a segment. Returns paginated list of member details. Use for verifying segment criteria or exporting member lists.",
|
|
61
70
|
readOnly: true,
|
|
71
|
+
idempotent: true,
|
|
62
72
|
inputSchema: SegmentGetMembersInputSchema,
|
|
63
73
|
handler: segmentGetMembers,
|
|
64
74
|
},
|
|
@@ -67,6 +77,7 @@ export const segmentToolDefinitions = [
|
|
|
67
77
|
title: "Activate Segment",
|
|
68
78
|
description: "Activate a segment. Active segments are used for campaign targeting and can be queried for members.",
|
|
69
79
|
readOnly: false,
|
|
80
|
+
idempotent: true,
|
|
70
81
|
inputSchema: SegmentActivateInputSchema,
|
|
71
82
|
handler: segmentActivate,
|
|
72
83
|
},
|
|
@@ -75,6 +86,7 @@ export const segmentToolDefinitions = [
|
|
|
75
86
|
title: "Deactivate Segment",
|
|
76
87
|
description: "Deactivate a segment. Deactivated segments are not used for campaign targeting but retain their configuration.",
|
|
77
88
|
readOnly: false,
|
|
89
|
+
idempotent: true,
|
|
78
90
|
inputSchema: SegmentDeactivateInputSchema,
|
|
79
91
|
handler: segmentDeactivate,
|
|
80
92
|
},
|
|
@@ -84,6 +96,7 @@ export const segmentToolDefinitions = [
|
|
|
84
96
|
description: "Get resources (campaigns, rewards, etc.) that use this segment for targeting. Check before deleting a segment. " +
|
|
85
97
|
"NOTE: This endpoint may not be available in all API versions - if it returns NOT_FOUND, manually check campaigns and rewards that reference this segment.",
|
|
86
98
|
readOnly: true,
|
|
99
|
+
idempotent: true,
|
|
87
100
|
inputSchema: SegmentGetResourcesInputSchema,
|
|
88
101
|
handler: segmentGetResources,
|
|
89
102
|
},
|
|
@@ -15,16 +15,19 @@ const SegmentCriterionInputSchema = z.object({
|
|
|
15
15
|
type: z.string().describe("Criterion type. WORKING: 'transaction_count' (requires both min AND max; MCP auto-fills max if omitted). NOT WORKING: 'tier', 'points_balance' are rejected by the API."),
|
|
16
16
|
criterionId: z.string().optional().describe("Criterion ID (optional, generated if not provided)."),
|
|
17
17
|
// Common criterion data fields
|
|
18
|
-
days: z.number().optional().describe("Days for time-based criteria."),
|
|
18
|
+
days: z.number().optional().describe("Days for time-based criteria (e.g., 'in the last N days'). Used with transaction_count, purchase_period criteria."),
|
|
19
19
|
fromDate: z.string().optional().describe("Start date (ISO format)."),
|
|
20
20
|
toDate: z.string().optional().describe("End date (ISO format)."),
|
|
21
|
-
min: z.number().optional().describe("Minimum value. BUSINESS IMPACT: Too low a threshold (e.g., min=2 transactions) captures most members -- segment becomes too broad, wasting campaign budget."),
|
|
22
|
-
max: z.number().optional().describe("Maximum value. BUSINESS IMPACT: Too narrow a range (e.g., max=3 with min=3) captures very few members -- limited campaign impact."),
|
|
21
|
+
min: z.number().optional().describe("Minimum value (e.g., min=5 for 'at least 5 transactions'). Required for transaction_count type. BUSINESS IMPACT: Too low a threshold (e.g., min=2 transactions) captures most members -- segment becomes too broad, wasting campaign budget."),
|
|
22
|
+
max: z.number().optional().describe("Maximum value. Required for transaction_count type (MCP auto-fills max=999999 if omitted). BUSINESS IMPACT: Too narrow a range (e.g., max=3 with min=3) captures very few members -- limited campaign impact."),
|
|
23
23
|
posIds: z.array(z.string()).optional().describe("POS IDs."),
|
|
24
24
|
skus: z.array(z.string()).optional().describe("SKU codes."),
|
|
25
25
|
makers: z.array(z.string()).optional().describe("Maker/brand names."),
|
|
26
|
-
labels: z.array(z.object({
|
|
27
|
-
|
|
26
|
+
labels: z.array(z.object({
|
|
27
|
+
key: z.string().describe("Label key (e.g., 'category', 'brand', 'channel')."),
|
|
28
|
+
value: z.string().describe("Label value to match (e.g., 'electronics', 'nike', 'online')."),
|
|
29
|
+
})).optional().describe("Label key-value pairs for label-based criteria."),
|
|
30
|
+
tierIds: z.array(z.string()).optional().describe("Tier level IDs. WARNING: 'tier' criterion type is NOT WORKING -- API rejects it. Use campaign audience targeting for tier-based segmentation instead."),
|
|
28
31
|
campaignId: z.string().optional().describe("Campaign ID for campaign_completion criterion."),
|
|
29
32
|
countries: z.array(z.string()).optional().describe("Country codes."),
|
|
30
33
|
anniversaryType: z.string().optional().describe("Anniversary type."),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Store, StoreListResponse } from "./schemas.js";
|
|
2
|
+
export declare function storeList(input: {
|
|
3
|
+
page?: number;
|
|
4
|
+
perPage?: number;
|
|
5
|
+
active?: boolean;
|
|
6
|
+
name?: string;
|
|
7
|
+
code?: string;
|
|
8
|
+
}): Promise<StoreListResponse>;
|
|
9
|
+
export declare function storeCreate(input: {
|
|
10
|
+
code: string;
|
|
11
|
+
name: string;
|
|
12
|
+
currency?: string;
|
|
13
|
+
active?: boolean;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
storeId: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function storeGet(input: {
|
|
18
|
+
storeId: string;
|
|
19
|
+
}): Promise<Store>;
|
|
20
|
+
export declare function storeUpdate(input: {
|
|
21
|
+
storeId: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
active?: boolean;
|
|
24
|
+
currency?: string;
|
|
25
|
+
}): Promise<void>;
|