@open-loyalty/mcp-server 1.0.3 → 1.3.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/README.md +180 -177
- package/dist/auth/provider.js +2 -14
- package/dist/auth/storage.js +22 -0
- package/dist/client/http.d.ts +5 -0
- package/dist/client/http.js +62 -3
- package/dist/config.d.ts +6 -5
- package/dist/config.js +15 -11
- package/dist/http.js +170 -65
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +420 -0
- package/dist/prompts/fan-engagement-setup.d.ts +107 -0
- package/dist/prompts/fan-engagement-setup.js +492 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +68 -278
- package/dist/tools/achievement/handlers.d.ts +117 -0
- package/dist/tools/achievement/handlers.js +161 -0
- package/dist/tools/achievement/index.d.ts +479 -0
- package/dist/tools/achievement/index.js +74 -0
- package/dist/tools/achievement/schemas.d.ts +433 -0
- package/dist/tools/achievement/schemas.js +142 -0
- package/dist/tools/achievement.d.ts +155 -121
- package/dist/tools/achievement.js +82 -39
- package/dist/tools/admin.d.ts +18 -6
- package/dist/tools/admin.js +24 -12
- package/dist/tools/analytics.d.ts +29 -11
- package/dist/tools/analytics.js +58 -48
- package/dist/tools/apikey.d.ts +10 -3
- package/dist/tools/apikey.js +13 -6
- package/dist/tools/audit.d.ts +6 -2
- package/dist/tools/audit.js +8 -4
- package/dist/tools/badge.d.ts +14 -6
- package/dist/tools/badge.js +36 -27
- package/dist/tools/campaign/handlers.d.ts +42 -0
- package/dist/tools/campaign/handlers.js +223 -0
- package/dist/tools/campaign/index.d.ts +783 -0
- package/dist/tools/campaign/index.js +112 -0
- package/dist/tools/campaign/member-handlers.d.ts +60 -0
- package/dist/tools/campaign/member-handlers.js +159 -0
- package/dist/tools/campaign/schemas.d.ts +704 -0
- package/dist/tools/campaign/schemas.js +259 -0
- package/dist/tools/campaign/types.d.ts +161 -0
- package/dist/tools/campaign/types.js +2 -0
- package/dist/tools/campaign.d.ts +41 -16
- package/dist/tools/campaign.js +38 -25
- package/dist/tools/custom-event.d.ts +315 -0
- package/dist/tools/custom-event.js +270 -0
- package/dist/tools/export.d.ts +12 -4
- package/dist/tools/export.js +25 -20
- package/dist/tools/import.d.ts +9 -3
- package/dist/tools/import.js +33 -21
- package/dist/tools/index.d.ts +3 -11
- package/dist/tools/index.js +17 -475
- package/dist/tools/member/handlers.d.ts +111 -0
- package/dist/tools/member/handlers.js +206 -0
- package/dist/tools/member/index.d.ts +169 -0
- package/dist/tools/member/index.js +92 -0
- package/dist/tools/member/schemas.d.ts +89 -0
- package/dist/tools/member/schemas.js +65 -0
- package/dist/tools/member.d.ts +21 -0
- package/dist/tools/member.js +56 -62
- package/dist/tools/points.d.ts +19 -6
- package/dist/tools/points.js +51 -49
- package/dist/tools/referral/handlers.d.ts +47 -0
- package/dist/tools/referral/handlers.js +115 -0
- package/dist/tools/referral/index.d.ts +44 -0
- package/dist/tools/referral/index.js +44 -0
- package/dist/tools/referral/schemas.d.ts +34 -0
- package/dist/tools/referral/schemas.js +52 -0
- package/dist/tools/reward/handlers.d.ts +110 -0
- package/dist/tools/reward/handlers.js +289 -0
- package/dist/tools/reward/index.d.ts +177 -0
- package/dist/tools/reward/index.js +90 -0
- package/dist/tools/reward/schemas.d.ts +116 -0
- package/dist/tools/reward/schemas.js +91 -0
- package/dist/tools/reward.d.ts +18 -0
- package/dist/tools/reward.js +56 -66
- package/dist/tools/role.d.ts +26 -7
- package/dist/tools/role.js +25 -12
- package/dist/tools/segment/handlers.d.ts +87 -0
- package/dist/tools/segment/handlers.js +174 -0
- package/dist/tools/segment/index.d.ts +395 -0
- package/dist/tools/segment/index.js +87 -0
- package/dist/tools/segment/schemas.d.ts +337 -0
- package/dist/tools/segment/schemas.js +79 -0
- package/dist/tools/segment.d.ts +29 -10
- package/dist/tools/segment.js +84 -50
- package/dist/tools/store.d.ts +12 -4
- package/dist/tools/store.js +16 -8
- package/dist/tools/tierset.d.ts +19 -7
- package/dist/tools/tierset.js +44 -35
- package/dist/tools/transaction.d.ts +16 -8
- package/dist/tools/transaction.js +25 -21
- package/dist/tools/wallet-type.d.ts +7 -3
- package/dist/tools/wallet-type.js +14 -12
- package/dist/tools/webhook.d.ts +23 -10
- package/dist/tools/webhook.js +135 -33
- package/dist/types/schemas/achievement.d.ts +12 -309
- package/dist/types/schemas/achievement.js +0 -13
- package/dist/types/schemas/admin.d.ts +10 -97
- package/dist/types/schemas/admin.js +0 -38
- package/dist/types/schemas/badge.d.ts +0 -37
- package/dist/types/schemas/badge.js +0 -11
- package/dist/types/schemas/campaign.d.ts +64 -832
- package/dist/types/schemas/campaign.js +2 -25
- package/dist/types/schemas/common.d.ts +5 -0
- package/dist/types/schemas/common.js +5 -0
- package/dist/types/schemas/export.d.ts +0 -17
- package/dist/types/schemas/export.js +0 -7
- package/dist/types/schemas/member.d.ts +37 -176
- package/dist/types/schemas/member.js +0 -27
- package/dist/types/schemas/points.d.ts +0 -63
- package/dist/types/schemas/points.js +0 -22
- package/dist/types/schemas/reward.d.ts +71 -68
- package/dist/types/schemas/reward.js +8 -28
- package/dist/types/schemas/role.d.ts +0 -100
- package/dist/types/schemas/role.js +0 -29
- package/dist/types/schemas/segment.d.ts +0 -58
- package/dist/types/schemas/segment.js +0 -17
- package/dist/types/schemas/tierset.d.ts +0 -176
- package/dist/types/schemas/tierset.js +0 -27
- package/dist/types/schemas/transaction.d.ts +23 -254
- package/dist/types/schemas/transaction.js +0 -7
- package/dist/types/schemas/wallet-type.d.ts +8 -8
- package/dist/types/schemas/wallet-type.js +1 -1
- package/dist/types/schemas/webhook.d.ts +0 -58
- package/dist/types/schemas/webhook.js +0 -12
- package/dist/utils/errors.js +30 -3
- package/dist/utils/payload.d.ts +12 -0
- package/dist/utils/payload.js +14 -0
- package/dist/workflows/app-login-streak.d.ts +39 -0
- package/dist/workflows/app-login-streak.js +298 -0
- package/dist/workflows/early-arrival.d.ts +33 -0
- package/dist/workflows/early-arrival.js +148 -0
- package/dist/workflows/index.d.ts +101 -0
- package/dist/workflows/index.js +208 -0
- package/dist/workflows/match-attendance.d.ts +45 -0
- package/dist/workflows/match-attendance.js +308 -0
- package/dist/workflows/sportsbar-visit.d.ts +41 -0
- package/dist/workflows/sportsbar-visit.js +284 -0
- package/dist/workflows/vod-watching.d.ts +43 -0
- package/dist/workflows/vod-watching.js +326 -0
- package/package.json +10 -2
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan Engagement Setup Prompts
|
|
3
|
+
*
|
|
4
|
+
* MCP prompt templates for guided campaign setup.
|
|
5
|
+
* These define conversational flows and default values for AI agents
|
|
6
|
+
* to help program admins create fan engagement campaigns.
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Default Values
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const DEFAULTS = {
|
|
12
|
+
// Match Attendance
|
|
13
|
+
matchAttendance: {
|
|
14
|
+
coinsPerMatch: 50,
|
|
15
|
+
milestones: [6, 12],
|
|
16
|
+
milestoneBonuses: { 6: 500, 12: 1000, "80%": 2000 },
|
|
17
|
+
limitPerDay: 1,
|
|
18
|
+
badges: { 6: "Silver", 12: "Gold", "80%": "Platinum" },
|
|
19
|
+
},
|
|
20
|
+
// Early Arrival
|
|
21
|
+
earlyArrival: {
|
|
22
|
+
minutesBefore: 60,
|
|
23
|
+
coinsPerArrival: 25,
|
|
24
|
+
limitPerMatch: 1,
|
|
25
|
+
},
|
|
26
|
+
// Sports Bar
|
|
27
|
+
sportsbarVisit: {
|
|
28
|
+
coinsPerVisit: 50,
|
|
29
|
+
visitMilestone: 5,
|
|
30
|
+
milestoneBonus: 500,
|
|
31
|
+
limitPerDay: 1,
|
|
32
|
+
},
|
|
33
|
+
// VOD Watching
|
|
34
|
+
vodWatching: {
|
|
35
|
+
trackBy: "minutes",
|
|
36
|
+
coinsPerUnit: 10,
|
|
37
|
+
unitSize: 10, // coins per X minutes
|
|
38
|
+
achievementMinutes: 300,
|
|
39
|
+
achievementBonus: 200,
|
|
40
|
+
},
|
|
41
|
+
// App Login Streak
|
|
42
|
+
appLoginStreak: {
|
|
43
|
+
coinsPerLogin: 5,
|
|
44
|
+
streakDays: 7,
|
|
45
|
+
streakBonus: 50,
|
|
46
|
+
limitPerDay: 1,
|
|
47
|
+
},
|
|
48
|
+
// General
|
|
49
|
+
seasonDates: {
|
|
50
|
+
start: new Date().toISOString().split("T")[0],
|
|
51
|
+
end: new Date(new Date().setFullYear(new Date().getFullYear() + 1)).toISOString().split("T")[0],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Workflow Definitions
|
|
56
|
+
// ============================================================================
|
|
57
|
+
export const MATCH_ATTENDANCE_WORKFLOW = {
|
|
58
|
+
id: "match-attendance",
|
|
59
|
+
name: "Match Attendance Campaign",
|
|
60
|
+
description: "Reward fans for attending matches with coins and achievements",
|
|
61
|
+
triggerPhrases: [
|
|
62
|
+
"set up a campaign to reward fans for attending matches",
|
|
63
|
+
"create match attendance rewards",
|
|
64
|
+
"reward match attendance",
|
|
65
|
+
"attendance campaign",
|
|
66
|
+
"match attendance",
|
|
67
|
+
],
|
|
68
|
+
questions: [
|
|
69
|
+
{
|
|
70
|
+
id: "coinsPerMatch",
|
|
71
|
+
question: "How many coins should fans receive per match attendance?",
|
|
72
|
+
type: "number",
|
|
73
|
+
default: DEFAULTS.matchAttendance.coinsPerMatch,
|
|
74
|
+
hint: "Common values: 50, 100, 200",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "createAchievements",
|
|
78
|
+
question: "Set up achievements for attending multiple matches?",
|
|
79
|
+
type: "boolean",
|
|
80
|
+
default: true,
|
|
81
|
+
hint: "Creates milestone achievements (e.g., 6 matches, 12 matches)",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "milestones",
|
|
85
|
+
question: "What attendance milestones should earn achievements?",
|
|
86
|
+
type: "string",
|
|
87
|
+
default: "6,12",
|
|
88
|
+
hint: "Comma-separated numbers (e.g., '6,12' or '6,12,80%')",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "badgeNames",
|
|
92
|
+
question: "What badge names for each milestone?",
|
|
93
|
+
type: "string",
|
|
94
|
+
default: "Silver,Gold",
|
|
95
|
+
hint: "Comma-separated names matching milestones (e.g., 'Silver,Gold,Platinum')",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "milestoneBonuses",
|
|
99
|
+
question: "Bonus coins for each milestone?",
|
|
100
|
+
type: "string",
|
|
101
|
+
default: "500,1000",
|
|
102
|
+
hint: "Comma-separated values matching milestones",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "limitPerDay",
|
|
106
|
+
question: "Maximum attendances per day (anti-fraud)?",
|
|
107
|
+
type: "number",
|
|
108
|
+
default: DEFAULTS.matchAttendance.limitPerDay,
|
|
109
|
+
hint: "Usually 1 to prevent multiple scans per match",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "seasonStart",
|
|
113
|
+
question: "Season start date?",
|
|
114
|
+
type: "string",
|
|
115
|
+
default: DEFAULTS.seasonDates.start,
|
|
116
|
+
hint: "ISO format: YYYY-MM-DD",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "seasonEnd",
|
|
120
|
+
question: "Season end date?",
|
|
121
|
+
type: "string",
|
|
122
|
+
default: DEFAULTS.seasonDates.end,
|
|
123
|
+
hint: "ISO format: YYYY-MM-DD",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
steps: [
|
|
127
|
+
{
|
|
128
|
+
id: "create-base-campaign",
|
|
129
|
+
action: "Create base match attendance campaign",
|
|
130
|
+
tool: "openloyalty_campaign_create",
|
|
131
|
+
description: "Creates campaign with custom_event trigger for match_attendance event",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "create-achievements",
|
|
135
|
+
action: "Create milestone achievements",
|
|
136
|
+
tool: "openloyalty_achievement_create",
|
|
137
|
+
description: "Creates achievements for each attendance milestone with badges",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "create-achievement-campaigns",
|
|
141
|
+
action: "Create achievement bonus campaigns",
|
|
142
|
+
tool: "openloyalty_campaign_create",
|
|
143
|
+
description: "Creates campaigns triggered by achievement completion for bonus coins",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: "verify",
|
|
147
|
+
action: "Verify all campaigns and achievements",
|
|
148
|
+
tool: "openloyalty_campaign_list",
|
|
149
|
+
description: "Lists created campaigns to confirm setup",
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
export const EARLY_ARRIVAL_WORKFLOW = {
|
|
154
|
+
id: "early-arrival",
|
|
155
|
+
name: "Early Arrival Campaign",
|
|
156
|
+
description: "Reward fans who arrive early to matches",
|
|
157
|
+
triggerPhrases: [
|
|
158
|
+
"reward fans who arrive early",
|
|
159
|
+
"early arrival rewards",
|
|
160
|
+
"early arrival campaign",
|
|
161
|
+
"reward early arrival",
|
|
162
|
+
],
|
|
163
|
+
questions: [
|
|
164
|
+
{
|
|
165
|
+
id: "minutesBefore",
|
|
166
|
+
question: "How early (in minutes) counts as 'early arrival'?",
|
|
167
|
+
type: "number",
|
|
168
|
+
default: DEFAULTS.earlyArrival.minutesBefore,
|
|
169
|
+
hint: "Common values: 30, 45, 60 minutes before kickoff",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: "coinsPerArrival",
|
|
173
|
+
question: "How many coins for early arrival?",
|
|
174
|
+
type: "number",
|
|
175
|
+
default: DEFAULTS.earlyArrival.coinsPerArrival,
|
|
176
|
+
hint: "Usually less than match attendance reward",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: "limitPerMatch",
|
|
180
|
+
question: "Limit early arrival bonus per match?",
|
|
181
|
+
type: "number",
|
|
182
|
+
default: DEFAULTS.earlyArrival.limitPerMatch,
|
|
183
|
+
hint: "1 = one bonus per match day",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
steps: [
|
|
187
|
+
{
|
|
188
|
+
id: "create-campaign",
|
|
189
|
+
action: "Create early arrival campaign",
|
|
190
|
+
tool: "openloyalty_campaign_create",
|
|
191
|
+
description: "Creates campaign with custom_event trigger and minutes_before condition",
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
export const SPORTSBAR_VISIT_WORKFLOW = {
|
|
196
|
+
id: "sportsbar-visit",
|
|
197
|
+
name: "Sports Bar Visit Campaign",
|
|
198
|
+
description: "Reward fans for visiting the sports bar",
|
|
199
|
+
triggerPhrases: [
|
|
200
|
+
"set up rewards for visiting the sports bar",
|
|
201
|
+
"sports bar visit rewards",
|
|
202
|
+
"sportsbar visit campaign",
|
|
203
|
+
"reward bar visits",
|
|
204
|
+
],
|
|
205
|
+
questions: [
|
|
206
|
+
{
|
|
207
|
+
id: "coinsPerVisit",
|
|
208
|
+
question: "How many coins per sports bar visit?",
|
|
209
|
+
type: "number",
|
|
210
|
+
default: DEFAULTS.sportsbarVisit.coinsPerVisit,
|
|
211
|
+
hint: "Common values: 25, 50, 100",
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: "createAchievement",
|
|
215
|
+
question: "Set up achievement for multiple visits?",
|
|
216
|
+
type: "boolean",
|
|
217
|
+
default: true,
|
|
218
|
+
hint: "Creates milestone achievement for visiting X times",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: "visitMilestone",
|
|
222
|
+
question: "How many visits for the achievement?",
|
|
223
|
+
type: "number",
|
|
224
|
+
default: DEFAULTS.sportsbarVisit.visitMilestone,
|
|
225
|
+
hint: "Common values: 5, 10, 20",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: "milestoneBonus",
|
|
229
|
+
question: "Bonus coins for completing the achievement?",
|
|
230
|
+
type: "number",
|
|
231
|
+
default: DEFAULTS.sportsbarVisit.milestoneBonus,
|
|
232
|
+
hint: "Bonus awarded when milestone is reached",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
id: "limitPerDay",
|
|
236
|
+
question: "Maximum visits counted per day?",
|
|
237
|
+
type: "number",
|
|
238
|
+
default: DEFAULTS.sportsbarVisit.limitPerDay,
|
|
239
|
+
hint: "Prevents abuse from multiple scans",
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
steps: [
|
|
243
|
+
{
|
|
244
|
+
id: "create-visit-campaign",
|
|
245
|
+
action: "Create visit campaign",
|
|
246
|
+
tool: "openloyalty_campaign_create",
|
|
247
|
+
description: "Creates campaign with custom_event trigger for sportsbar_visit",
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
id: "create-achievement",
|
|
251
|
+
action: "Create visit milestone achievement",
|
|
252
|
+
tool: "openloyalty_achievement_create",
|
|
253
|
+
description: "Creates achievement for visiting X times",
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: "create-achievement-campaign",
|
|
257
|
+
action: "Create achievement bonus campaign",
|
|
258
|
+
tool: "openloyalty_campaign_create",
|
|
259
|
+
description: "Creates campaign triggered by achievement completion",
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
};
|
|
263
|
+
export const VOD_WATCHING_WORKFLOW = {
|
|
264
|
+
id: "vod-watching",
|
|
265
|
+
name: "VOD Watching Campaign",
|
|
266
|
+
description: "Reward fans for watching video content",
|
|
267
|
+
triggerPhrases: [
|
|
268
|
+
"reward fans for watching video content",
|
|
269
|
+
"vod watching rewards",
|
|
270
|
+
"video content rewards",
|
|
271
|
+
"reward watching videos",
|
|
272
|
+
],
|
|
273
|
+
questions: [
|
|
274
|
+
{
|
|
275
|
+
id: "trackBy",
|
|
276
|
+
question: "Track by views or minutes watched?",
|
|
277
|
+
type: "select",
|
|
278
|
+
options: ["views", "minutes"],
|
|
279
|
+
default: DEFAULTS.vodWatching.trackBy,
|
|
280
|
+
hint: "Minutes watched is more engagement-focused",
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: "coinsPerUnit",
|
|
284
|
+
question: "How many coins per unit (view or X minutes)?",
|
|
285
|
+
type: "number",
|
|
286
|
+
default: DEFAULTS.vodWatching.coinsPerUnit,
|
|
287
|
+
hint: "For minutes: coins per unitSize minutes",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
id: "unitSize",
|
|
291
|
+
question: "If tracking minutes, how many minutes per reward?",
|
|
292
|
+
type: "number",
|
|
293
|
+
default: DEFAULTS.vodWatching.unitSize,
|
|
294
|
+
hint: "e.g., 10 = earn coins every 10 minutes watched",
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: "createAchievement",
|
|
298
|
+
question: "Set up achievement for total minutes/views?",
|
|
299
|
+
type: "boolean",
|
|
300
|
+
default: true,
|
|
301
|
+
hint: "Creates milestone achievement for watching X total",
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: "achievementTarget",
|
|
305
|
+
question: "Target for achievement (minutes or views)?",
|
|
306
|
+
type: "number",
|
|
307
|
+
default: DEFAULTS.vodWatching.achievementMinutes,
|
|
308
|
+
hint: "Total minutes or views to earn achievement",
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
id: "achievementBonus",
|
|
312
|
+
question: "Bonus coins for completing the achievement?",
|
|
313
|
+
type: "number",
|
|
314
|
+
default: DEFAULTS.vodWatching.achievementBonus,
|
|
315
|
+
hint: "Bonus awarded when target is reached",
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
steps: [
|
|
319
|
+
{
|
|
320
|
+
id: "create-watch-campaign",
|
|
321
|
+
action: "Create VOD watching campaign",
|
|
322
|
+
tool: "openloyalty_campaign_create",
|
|
323
|
+
description: "Creates campaign with custom_event trigger for vod_watch",
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: "create-achievement",
|
|
327
|
+
action: "Create watching achievement",
|
|
328
|
+
tool: "openloyalty_achievement_create",
|
|
329
|
+
description: "Creates achievement tracking total minutes/views with attribute sum",
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: "create-achievement-campaign",
|
|
333
|
+
action: "Create achievement bonus campaign",
|
|
334
|
+
tool: "openloyalty_campaign_create",
|
|
335
|
+
description: "Creates campaign triggered by achievement completion",
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
};
|
|
339
|
+
export const APP_LOGIN_STREAK_WORKFLOW = {
|
|
340
|
+
id: "app-login-streak",
|
|
341
|
+
name: "App Login Streak Campaign",
|
|
342
|
+
description: "Reward fans for daily login streaks",
|
|
343
|
+
triggerPhrases: [
|
|
344
|
+
"set up daily login rewards",
|
|
345
|
+
"daily login streak",
|
|
346
|
+
"app login rewards",
|
|
347
|
+
"login streak campaign",
|
|
348
|
+
],
|
|
349
|
+
questions: [
|
|
350
|
+
{
|
|
351
|
+
id: "coinsPerLogin",
|
|
352
|
+
question: "How many coins per daily login?",
|
|
353
|
+
type: "number",
|
|
354
|
+
default: DEFAULTS.appLoginStreak.coinsPerLogin,
|
|
355
|
+
hint: "Usually a small amount (5-20)",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: "createStreakBonus",
|
|
359
|
+
question: "Set up streak bonus?",
|
|
360
|
+
type: "boolean",
|
|
361
|
+
default: true,
|
|
362
|
+
hint: "Extra reward for consecutive daily logins",
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
id: "streakDays",
|
|
366
|
+
question: "How many consecutive days for streak bonus?",
|
|
367
|
+
type: "number",
|
|
368
|
+
default: DEFAULTS.appLoginStreak.streakDays,
|
|
369
|
+
hint: "Common values: 7, 14, 30 days",
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "streakBonus",
|
|
373
|
+
question: "Bonus coins for completing the streak?",
|
|
374
|
+
type: "number",
|
|
375
|
+
default: DEFAULTS.appLoginStreak.streakBonus,
|
|
376
|
+
hint: "Bonus awarded when streak is achieved",
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
steps: [
|
|
380
|
+
{
|
|
381
|
+
id: "create-login-campaign",
|
|
382
|
+
action: "Create daily login campaign",
|
|
383
|
+
tool: "openloyalty_campaign_create",
|
|
384
|
+
description: "Creates campaign with custom_event trigger for app_login, limited to 1/day",
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
id: "create-streak-achievement",
|
|
388
|
+
action: "Create login streak achievement",
|
|
389
|
+
tool: "openloyalty_achievement_create",
|
|
390
|
+
description: "Creates achievement for X consecutive daily logins",
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
id: "create-streak-campaign",
|
|
394
|
+
action: "Create streak bonus campaign",
|
|
395
|
+
tool: "openloyalty_campaign_create",
|
|
396
|
+
description: "Creates campaign triggered by streak achievement completion",
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
};
|
|
400
|
+
// ============================================================================
|
|
401
|
+
// All Workflows
|
|
402
|
+
// ============================================================================
|
|
403
|
+
export const ALL_WORKFLOWS = [
|
|
404
|
+
MATCH_ATTENDANCE_WORKFLOW,
|
|
405
|
+
EARLY_ARRIVAL_WORKFLOW,
|
|
406
|
+
SPORTSBAR_VISIT_WORKFLOW,
|
|
407
|
+
VOD_WATCHING_WORKFLOW,
|
|
408
|
+
APP_LOGIN_STREAK_WORKFLOW,
|
|
409
|
+
];
|
|
410
|
+
// ============================================================================
|
|
411
|
+
// Helper Functions
|
|
412
|
+
// ============================================================================
|
|
413
|
+
/**
|
|
414
|
+
* Find matching workflow based on user input
|
|
415
|
+
*/
|
|
416
|
+
export function findMatchingWorkflow(userInput) {
|
|
417
|
+
const input = userInput.toLowerCase();
|
|
418
|
+
return ALL_WORKFLOWS.find((workflow) => workflow.triggerPhrases.some((phrase) => input.includes(phrase.toLowerCase())));
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Get workflow by ID
|
|
422
|
+
*/
|
|
423
|
+
export function getWorkflowById(id) {
|
|
424
|
+
return ALL_WORKFLOWS.find((workflow) => workflow.id === id);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Parse comma-separated values to array
|
|
428
|
+
*/
|
|
429
|
+
export function parseCommaSeparated(value) {
|
|
430
|
+
return value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Parse milestones (handles both numbers and percentages like "80%")
|
|
434
|
+
*/
|
|
435
|
+
export function parseMilestones(value) {
|
|
436
|
+
return parseCommaSeparated(value).map((v) => {
|
|
437
|
+
if (v.includes("%"))
|
|
438
|
+
return v;
|
|
439
|
+
const num = parseInt(v, 10);
|
|
440
|
+
return isNaN(num) ? v : num;
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Format ISO date for Open Loyalty (YYYY-MM-DD HH:mm+TZ)
|
|
445
|
+
*/
|
|
446
|
+
export function formatOLDate(date) {
|
|
447
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
448
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
449
|
+
const offset = -d.getTimezoneOffset();
|
|
450
|
+
const offsetHours = Math.floor(Math.abs(offset) / 60);
|
|
451
|
+
const offsetSign = offset >= 0 ? "+" : "-";
|
|
452
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} 00:00${offsetSign}${pad(offsetHours)}:00`;
|
|
453
|
+
}
|
|
454
|
+
// ============================================================================
|
|
455
|
+
// Prompt Templates for AI Agents
|
|
456
|
+
// ============================================================================
|
|
457
|
+
export const AGENT_PROMPTS = {
|
|
458
|
+
/**
|
|
459
|
+
* System prompt for fan engagement setup
|
|
460
|
+
*/
|
|
461
|
+
systemPrompt: `You are helping a program admin set up fan engagement campaigns in Open Loyalty.
|
|
462
|
+
For each campaign type, guide the user through the setup questions step by step.
|
|
463
|
+
Use the default values when the user doesn't have a preference.
|
|
464
|
+
After collecting all information, execute the workflow to create the campaigns and achievements.
|
|
465
|
+
|
|
466
|
+
Available campaign types:
|
|
467
|
+
1. Match Attendance - Reward fans for attending matches with coins and milestone achievements
|
|
468
|
+
2. Early Arrival - Bonus for arriving early to matches
|
|
469
|
+
3. Sports Bar Visits - Reward visits to the sports bar
|
|
470
|
+
4. VOD Watching - Reward watching video content
|
|
471
|
+
5. App Login Streak - Daily login rewards with streak bonuses
|
|
472
|
+
|
|
473
|
+
When creating campaigns:
|
|
474
|
+
- Always use custom_event trigger for fan engagement events
|
|
475
|
+
- Custom events are defined inline (no separate create step needed)
|
|
476
|
+
- Use achievement trigger for bonus campaigns on milestones
|
|
477
|
+
- Set appropriate execution limits to prevent abuse
|
|
478
|
+
- Create achievements with badges for milestone rewards`,
|
|
479
|
+
/**
|
|
480
|
+
* Workflow completion template
|
|
481
|
+
*/
|
|
482
|
+
completionTemplate: (results) => `Your fan engagement program is now set up!
|
|
483
|
+
|
|
484
|
+
Created campaigns:
|
|
485
|
+
${results.campaignIds.map((id) => `- Campaign ID: ${id}`).join("\n")}
|
|
486
|
+
|
|
487
|
+
Created achievements:
|
|
488
|
+
${results.achievementIds.map((id) => `- Achievement ID: ${id}`).join("\n")}
|
|
489
|
+
|
|
490
|
+
Summary:
|
|
491
|
+
${results.summary}`,
|
|
492
|
+
};
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
declare const SERVER_INSTRUCTIONS = "\nOpen Loyalty MCP Server - Complete Loyalty Program Management\n\n## Domain Model\n\nMember (loyalty program participant)\n \u2514\u2500\u2500 Points (wallet balance, transfers)\n \u2514\u2500\u2500 Tier (current level: Bronze, Silver, Gold)\n \u2514\u2500\u2500 Transactions (purchase history)\n \u2514\u2500\u2500 Rewards (redeemed coupons)\n \u2514\u2500\u2500 Achievements (gamification progress)\n \u2514\u2500\u2500 Badges (visual rewards from achievements)\n\nTierSet (loyalty program structure)\n \u2514\u2500\u2500 Conditions (criteria: activeUnits, totalSpending)\n \u2514\u2500\u2500 Tiers (levels with thresholds)\n\nWalletType (points currency configuration)\n\nReward (redeemable items)\n \u2514\u2500\u2500 Categories (reward groupings)\n\nCampaign (automated points/rewards rules)\n \u2514\u2500\u2500 Type (earning, spending, custom, instant_reward)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer)\n \u2514\u2500\u2500 Rules (SKU, category, transaction amount conditions)\n \u2514\u2500\u2500 Effects (give_points, multiply_points, percentage_discount)\n \u2514\u2500\u2500 Targeting (segments, tiers for audience)\n\nSegment (member audience grouping)\n \u2514\u2500\u2500 Parts (groups of criteria - OR logic between parts)\n \u2514\u2500\u2500 Criteria (conditions - AND logic within part)\n Types: purchase_period, transaction_count, average_transaction,\n anniversary, last_purchase_days, tier\n\nAchievement (gamification goals)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer, referral, login)\n \u2514\u2500\u2500 CompleteRule (periodGoal, period type, unique counting)\n \u2514\u2500\u2500 Badge (visual reward when completed)\n\nBadge (visual recognition)\n \u2514\u2500\u2500 Linked to achievements via badgeTypeId\n \u2514\u2500\u2500 Auto-created when referenced by achievement\n\n## Key Workflows\n\n### 1. Create 3-tier Loyalty Program:\nwallet_type_list \u2192 tierset_create \u2192 tierset_get \u2192 tierset_update_tiers\n\n### 2. Register and Reward Member:\nmember_create \u2192 points_add (welcome bonus) \u2192 member_get (verify)\n\n### 3. Record Purchase and Earn Points:\ntransaction_create (with customerData) \u2192 triggers campaigns \u2192 points auto-added\n\n### 4. Redeem Reward:\nreward_list \u2192 reward_buy (deducts points) \u2192 reward_redeem (mark coupon used)\n\n### 5. Assign Unmatched Transaction:\ntransaction_list (matched=false) \u2192 transaction_assign_member \u2192 points earned\n\n### 6. Check Member Tier Progress:\nmember_get_tier_progress \u2192 shows current tier, next tier, progress %\n\n### 7. Double Points for VIP Members:\nsegment_create (with tier criteria for VIP level) \u2192 campaign_create (targeting that segment with give_points effect and multiplier: 2)\n\n### 8. Purchase Achievement with Badge:\nbadge_list (find or note badgeTypeId) \u2192 achievement_create (trigger: transaction, periodGoal for amount, badgeTypeId)\n\n### 9. Create Targeted Promotion:\nsegment_create (define audience) \u2192 campaign_create (type: earning, target: segment, segmentIds: [segmentId])\n\n### 10. Track Member Gamification:\nachievement_list_member_achievements \u2192 badge_get_member_badges \u2192 achievement_get_member_progress\n\n## Discovery Paths:\n- Members: member_list \u2192 member_get \u2192 points_get_balance\n- Tiers: tierset_list \u2192 tierset_get \u2192 tierset_get_tiers\n- Rewards: reward_category_list \u2192 reward_list \u2192 reward_get\n- Transactions: transaction_list \u2192 transaction_get\n- Campaigns: campaign_list \u2192 campaign_get \u2192 campaign_simulate\n- Segments: segment_list \u2192 segment_get \u2192 segment_get_members \u2192 campaign_create (audience targeting)\n- Achievements: achievement_list \u2192 badge_list \u2192 achievement_create (with badge)\n- Member Gamification: achievement_list_member_achievements \u2192 badge_get_member_badges\n\n## Important Patterns:\n- conditionId REQUIRED for tier thresholds - call tierset_get after tierset_create\n- Points operations: check balance with points_get_balance before spending\n- Reward flow: reward_buy returns couponCode, use reward_redeem to mark used\n- Transactions auto-match to members via customerData (email, phone, loyaltyCardNumber)\n\n### Pagination:\n- Traditional pagination: use page + perPage params\n- Cursor pagination: provide cursor from previous response for efficient deep pagination\n- Cursor-enabled tools: member_list, transaction_list, points_get_history\n- First scroll request: cursor=\"\" (empty string)\n- Subsequent requests: use cursor value from previous response\n- When cursor provided, page param is ignored\n\n### Campaign Patterns:\n- Campaign types: earning (earn points), spending (spend points), custom (custom events), instant_reward\n- Triggers: transaction (purchase), custom_event, points_transfer, referral, registration\n- Effects: give_points, multiply_points, percentage_discount, fixed_discount\n- Target campaigns to segments or tiers using target: \"segment\" and segmentIds array\n\n### Segment Patterns:\n- Parts use OR logic (member matches ANY part)\n- Criteria within a part use AND logic (member must match ALL criteria in that part)\n- Common criteria: purchase_period (spending), transaction_count, average_transaction, anniversary, last_purchase_days, tier\n\n### Achievement Patterns:\n- Triggers: transaction, custom_event, points_transfer, reward_redemption, referral, achievement, tier_change, registration, profile_update, login\n- periodGoal sets the target (e.g., 5 purchases, 1000 points spent)\n- period defines timeframe: day, week, month, year, forever\n- Link to badge via badgeTypeId - badge auto-created if doesn't exist\n- uniqueAttribute for counting distinct values (e.g., unique products)\n\n## Phase 3: Analytics, Admin, Roles & Stores\n\n### Domain Model (Extended)\n\nAdmin (system user)\n \u2514\u2500\u2500 Roles (permission sets)\n \u2514\u2500\u2500 Permissions (resource + access level)\n \u2514\u2500\u2500 API Keys (programmatic access)\n\nStore (multi-tenant container)\n \u2514\u2500\u2500 Members, Campaigns, Rewards (isolated per store)\n\nAudit Log (compliance tracking)\n \u2514\u2500\u2500 eventType, entityType, entityId, username, timestamp\n\n### Analytics Workflows:\n\n#### 11. Get Program Overview:\nanalytics_dashboard \u2192 analytics_tiers \u2192 analytics_members\n\n#### 12. Analyze Points Economy:\nanalytics_points \u2192 analytics_units (per wallet) \u2192 points_get_histogram\n\n#### 13. Measure Campaign Performance:\nanalytics_campaigns \u2192 analytics_campaign_detail (specific campaign)\n\n#### 14. Track Transactions:\nanalytics_transactions \u2192 transaction_list (details)\n\n### Aggregation Queries (Top Spenders, Purchase Analysis):\n\nIMPORTANT: For queries like \"top 5 spenders in July 2025\", use this approach:\n\n#### 15. Find Top Spenders by Date Range:\n1. transaction_list(purchasedAtFrom, purchasedAtTo, perPage=50, cursor='') - returns customerId with each transaction\n2. Use cursor pagination to fetch ALL pages - even if there are 1000+ transactions\n3. Aggregate grossValue by customerId in your code\n4. Sort by total spent, take top N\n5. member_get for each top spender to get names/details\n\nCRITICAL - DO NOT TRY TO BE SMART OR OPTIMIZE:\n- ALWAYS iterate through ALL pages using cursor pagination - this is the ONLY correct approach\n- DO NOT skip pages or try to sample data - you will get inaccurate results\n- DO NOT use transaction_get individually - transaction_list already includes customerId\n- DO NOT try to find \"smarter\" analytics endpoints - they don't exist for per-customer aggregation\n- Large datasets (1000+ transactions) are normal - just keep paginating until cursor is empty\n- Start with cursor='' (empty string), use returned cursor for next request, repeat until done\n\nExample: Top 5 spenders July 2025\n- First request: transaction_list(purchasedAtFrom: \"2025-07-01\", purchasedAtTo: \"2025-07-31\", perPage: 50, cursor: \"\")\n- Each result includes: transactionId, grossValue, customerId, purchasedAt\n- Keep fetching with returned cursor until response has no cursor or empty transactions\n- Even if there are 1500 transactions (30 pages), iterate through ALL of them\n- Group by customerId, sum grossValue, sort descending, take 5\n\n### Admin & Security Workflows:\n\n#### 15. Create Admin with Limited Role:\nacl_get_resources \u2192 role_create \u2192 admin_create (with roleId)\n\n#### 16. Generate API Key for Integration:\nadmin_get \u2192 apikey_create \u2192 SAVE TOKEN IMMEDIATELY (shown once!)\n\n#### 17. Audit User Actions:\naudit_list (filter by username/entity) \u2192 audit_export (compliance report)\n\n### Store Multi-Tenancy:\n\n#### 18. Create New Store:\nstore_create \u2192 configure campaigns/tiers \u2192 member_create (with storeCode)\n\n### Analytics Query Patterns:\n- All analytics tools support dateFrom/dateTo ISO date filters\n- analytics_dashboard: high-level program metrics\n- analytics_units: wallet-specific metrics (requires walletTypeCode)\n- analytics_campaign_detail: detailed metrics for single campaign\n\n### Admin \u2192 Role \u2192 Permission Model:\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Admin \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Role \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Permission \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502 \u2502\n \u2502 resource + access\n \u2502 (VIEW, MODIFY, etc.)\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 API Key \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n### Store Multi-Tenancy:\n- Each store is isolated: members, campaigns, rewards, transactions\n- storeCode parameter routes requests to correct tenant\n- Default store used when storeCode omitted\n\n## Phase 4: Webhooks, Import & Export\n\n### Domain Model (Extended)\n\nWebhook Subscription (event notification)\n \u2514\u2500\u2500 eventName (event to subscribe to)\n \u2514\u2500\u2500 url (callback endpoint)\n \u2514\u2500\u2500 headers (custom HTTP headers)\n\nImport (bulk data upload)\n \u2514\u2500\u2500 type: member, groupValue, segmentMembers, unitTransferAdding, etc.\n \u2514\u2500\u2500 status: pending, processing, succeed, failed\n \u2514\u2500\u2500 items (individual row results)\n\nExport (bulk data download)\n \u2514\u2500\u2500 type: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n \u2514\u2500\u2500 status: pending, done, failed, error\n \u2514\u2500\u2500 CSV file (when status='done')\n\n### Webhook Workflows:\n\n#### 19. Subscribe to Member Events for CRM Sync:\nwebhook_events \u2192 webhook_create (eventName: 'member.created', url: 'https://crm.example.com/webhook')\n\n#### 20. List and Manage Subscriptions:\nwebhook_list \u2192 webhook_get \u2192 webhook_update or webhook_delete\n\n### Import Workflows:\n\n#### 21. Bulk Import Members from CSV:\nimport_create (type: 'member', fileContent: CSV data) \u2192 import_list \u2192 import_get (check status)\n\n#### 22. Bulk Add Points to Members:\nimport_create (type: 'unitTransferAdding', fileContent: CSV) \u2192 poll import_get until complete\n\n### Export Workflows:\n\n#### 23. Export Campaign Codes:\nexport_create (type: 'campaignCode', filters: { campaignId }) \u2192 poll export_get (until status='done') \u2192 export_download\n\n#### 24. Export Member Data:\nexport_create (type: 'member') \u2192 export_get \u2192 export_download (returns CSV)\n\n### Webhook Patterns:\n- Use webhook_events to discover available event types before subscribing\n- API uses wrapper: { webhookSubscription: { eventName, url, headers? } }\n- Common events: member.created, member.updated, transaction.created, reward.purchased\n\n### Import Patterns:\n- Import is async: create returns importId, poll status with import_get\n- CSV format required - provide plain text, not base64\n- Types: member, groupValue, segmentMembers, unitTransferAdding, unitTransferSpending, transaction, campaignCode, rewardCoupon\n\n### Export Patterns:\n- Export is async: create returns exportId, poll status until 'done'\n- API body wrapper varies by type: { campaignCode: { filters... } }\n- Only call export_download when status='done'\n- Types: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n";
|
|
2
|
+
import { SERVER_INSTRUCTIONS } from "./instructions.js";
|
|
3
3
|
export declare function createServer(): McpServer;
|
|
4
4
|
export { SERVER_INSTRUCTIONS };
|