@hoya25/nctr-mcp-server 1.0.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.
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.hoya25/nctr-mcp-server",
4
+ "description": "NCTR Alliance rewards program — search bounties, check earning rates by tier, discover Impact Engine communities, and get onboarding links. The first rewards and loyalty MCP server.",
5
+ "repository": {
6
+ "url": "https://github.com/Hoya25/mcp-server",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "@hoya25/nctr-mcp-server",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ],
20
+ "remotes": [
21
+ {
22
+ "transportType": "streamable-http",
23
+ "url": "https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp/rpc"
24
+ }
25
+ ]
26
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NCTR Alliance
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # NCTR Alliance MCP Server
2
+
3
+ **The first rewards and loyalty MCP server.** Enables AI agents to discover and interact with the NCTR Alliance rewards program — bounties, earning rates, tier progression, promotions, and Impact Engine communities.
4
+
5
+ ## What It Does
6
+
7
+ When someone asks an AI assistant about NCTR, the assistant can call this server to get real, structured data instead of guessing. The server exposes 6 tools:
8
+
9
+ | Tool | What It Does |
10
+ |------|-------------|
11
+ | `search_bounties` | Search and filter all 19 available bounties by category, amount, keyword, or repeatability |
12
+ | `get_earning_rates` | Get earning multipliers by Crescendo tier, with optional bounty calculations |
13
+ | `check_tier_requirements` | Check tier thresholds, perks, and progress toward the next tier |
14
+ | `get_active_promotions` | Get current limited-time offers and launch bonuses |
15
+ | `get_onboarding_link` | Generate a join link with optional referral code |
16
+ | `get_impact_engines` | Discover NCTR's 6 passion-based communities |
17
+
18
+ ## Quick Start
19
+
20
+ ### Connect to the hosted server
21
+
22
+ Add this to your MCP client configuration (Claude Desktop, Cursor, etc.):
23
+
24
+ ```json
25
+ {
26
+ "mcpServers": {
27
+ "nctr-alliance": {
28
+ "url": "https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp/rpc"
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### Claude Code (terminal)
35
+
36
+ ```bash
37
+ claude mcp add nctr-alliance -t http https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp/rpc
38
+ ```
39
+
40
+ ### Or run locally
41
+
42
+ ```bash
43
+ git clone https://github.com/Hoya25/mcp-server.git
44
+ cd mcp-server
45
+ supabase start
46
+ supabase functions serve --no-verify-jwt mcp
47
+ ```
48
+
49
+ Server runs at: `http://localhost:54321/functions/v1/mcp/rpc`
50
+
51
+ ## Example Queries
52
+
53
+ Once connected, you can ask your AI assistant things like:
54
+
55
+ - "What bounties can I earn with NCTR?"
56
+ - "How much NCTR do I get for referring a friend?"
57
+ - "What tier am I at with 3,000 NCTR?"
58
+ - "What's the earning multiplier at Gold tier?"
59
+ - "Are there any active promotions?"
60
+ - "Tell me about the NCTR Impact Engines"
61
+
62
+ ## How Bounties Work
63
+
64
+ Every bounty in NCTR uses **360LOCK** — tokens are locked for exactly 360 days. They're committed, not spent. After the lock period, the NCTR is fully yours.
65
+
66
+ ### Bounty Categories
67
+
68
+ | Category | Examples |
69
+ |----------|---------|
70
+ | **Entry** | Sign-up (625), Early Adopter Bonus (1,250), Profile Completion (375) |
71
+ | **Revenue** | First Purchase (2,500), Shop & Earn (250 uncapped), Quarterly Spend (5,000) |
72
+ | **Merch** | Collection (5,000), Repeat (500) |
73
+ | **Referral** | Friend sign-ups (625), friend purchases (2,500), milestone bonuses |
74
+ | **Engagement** | Social shares (500), monthly activity (250), community contributions (2,000) |
75
+
76
+ ### Crescendo Status Tiers
77
+
78
+ | Tier | NCTR Required | Multiplier |
79
+ |------|--------------|------------|
80
+ | Bronze | 0 | 1.0x |
81
+ | Silver | 1,000 | 1.2x |
82
+ | Gold | 5,000 | 1.5x |
83
+ | Platinum | 25,000 | 1.8x |
84
+ | Diamond | 100,000 | 2.0x |
85
+
86
+ ## Impact Engines
87
+
88
+ NCTR includes 6 passion-based communities called Impact Engines:
89
+
90
+ - **THROTTLE** — Powersports
91
+ - **GROUNDBALL** — Lacrosse
92
+ - **STARDUST** — Entertainment
93
+ - **SWEAT** — Skilled Trades
94
+ - **SISU** — Recovery
95
+ - **INSPIRATION** — Wellness
96
+
97
+ ## API Endpoints
98
+
99
+ | Endpoint | Method | Description |
100
+ |----------|--------|-------------|
101
+ | `/` | GET | Server info and tool list |
102
+ | `/health` | GET | Health check |
103
+ | `/rpc` | POST | MCP protocol endpoint (Streamable HTTP) |
104
+
105
+ ### Test with curl
106
+
107
+ ```bash
108
+ # Health check
109
+ curl https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp/health
110
+
111
+ # Search all bounties
112
+ curl -X POST https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp/rpc \
113
+ -H "Content-Type: application/json" \
114
+ -H "Accept: application/json, text/event-stream" \
115
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_bounties","arguments":{}}}'
116
+ ```
117
+
118
+ ## Deployment
119
+
120
+ This server runs on **Supabase Edge Functions** using the official MCP TypeScript SDK (`@modelcontextprotocol/sdk@1.25.3`).
121
+
122
+ ```bash
123
+ supabase link --project-ref yhwcaodofmbusjurawhp
124
+ supabase functions deploy --no-verify-jwt mcp
125
+ ```
126
+
127
+ ## Links
128
+
129
+ - **NCTR Alliance**: [nctr.live](https://nctr.live)
130
+ - **The Garden** (shopping): [thegarden.nctr.live](https://thegarden.nctr.live)
131
+ - **Crescendo** (onboarding): [crescendo.nctr.live](https://crescendo.nctr.live)
132
+ - **For Agents**: [thegarden.nctr.live/for-agents](https://thegarden.nctr.live/for-agents)
133
+ - **Manifest**: [nctr.live/.well-known/nctr.json](https://nctr.live/.well-known/nctr.json)
134
+
135
+ ## License
136
+
137
+ MIT
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@hoya25/nctr-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for the NCTR Alliance rewards program. Enables AI agents to discover bounties, earning rates, tier requirements, promotions, and Impact Engine communities.",
5
+ "mcpName": "io.github.hoya25/nctr-mcp-server",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Hoya25/mcp-server.git"
9
+ },
10
+ "keywords": [
11
+ "mcp",
12
+ "rewards",
13
+ "loyalty",
14
+ "nctr",
15
+ "bounties",
16
+ "model-context-protocol"
17
+ ],
18
+ "author": "NCTR Alliance <anderson@butterflystudios.live>",
19
+ "license": "MIT",
20
+ "engines": {
21
+ "node": ">=20.0.0"
22
+ },
23
+ "scripts": {
24
+ "dev": "supabase functions serve --no-verify-jwt mcp",
25
+ "deploy": "supabase functions deploy --no-verify-jwt mcp",
26
+ "test": "bash test-mcp-server.sh",
27
+ "inspector": "npx @modelcontextprotocol/inspector"
28
+ }
29
+ }
@@ -0,0 +1,2 @@
1
+ [functions.mcp]
2
+ verify_jwt = false
@@ -0,0 +1,7 @@
1
+ {
2
+ "imports": {
3
+ "@modelcontextprotocol/sdk/": "npm:@modelcontextprotocol/sdk@1.25.3/",
4
+ "hono": "npm:hono@^4.9.7",
5
+ "zod": "npm:zod@^4.1.13"
6
+ }
7
+ }
@@ -0,0 +1,897 @@
1
+ /**
2
+ * NCTR Alliance MCP Server
3
+ * ========================
4
+ * Model Context Protocol server for AI agents to discover and interact
5
+ * with the NCTR rewards program, bounties, and Impact Engines.
6
+ *
7
+ * Deployment: Supabase Edge Functions
8
+ * Transport: Streamable HTTP (MCP specification standard)
9
+ * Auth: Public (no authentication required)
10
+ *
11
+ * Tools:
12
+ * 1. search_bounties — Search and filter available bounties
13
+ * 2. get_earning_rates — Get earning rates by Crescendo tier
14
+ * 3. check_tier_requirements — Check requirements for each tier
15
+ * 4. get_active_promotions — Get current promotions and limited offers
16
+ * 5. get_onboarding_link — Generate a member onboarding link
17
+ * 6. get_impact_engines — Discover NCTR Impact Engine communities
18
+ *
19
+ * NCTR Alliance — https://nctr.live
20
+ * The Garden — https://thegarden.nctr.live
21
+ */
22
+
23
+ import 'jsr:@supabase/functions-js/edge-runtime.d.ts'
24
+
25
+ import { McpServer } from 'npm:@modelcontextprotocol/sdk@1.25.3/server/mcp.js'
26
+ import { WebStandardStreamableHTTPServerTransport } from 'npm:@modelcontextprotocol/sdk@1.25.3/server/webStandardStreamableHttp.js'
27
+ import { Hono } from 'npm:hono@^4.9.7'
28
+ import { z } from 'npm:zod@^4.1.13'
29
+
30
+ // ─────────────────────────────────────────────────────────────
31
+ // DATA: Bounties
32
+ // ─────────────────────────────────────────────────────────────
33
+
34
+ interface Bounty {
35
+ id: string
36
+ name: string
37
+ category: 'entry' | 'revenue' | 'merch' | 'referral' | 'engagement'
38
+ description: string
39
+ amount: number
40
+ currency: string
41
+ lock_period: string
42
+ lock_days: number
43
+ repeatable: boolean
44
+ requirements: string[]
45
+ tags: string[]
46
+ }
47
+
48
+ const BOUNTIES: Bounty[] = [
49
+ // ── Entry Bounties ──
50
+ {
51
+ id: 'bounty-signup',
52
+ name: 'Sign-Up Bounty',
53
+ category: 'entry',
54
+ description: 'Create your NCTR account and complete onboarding. Earn 625 NCTR just for joining.',
55
+ amount: 625,
56
+ currency: 'NCTR',
57
+ lock_period: '360LOCK',
58
+ lock_days: 360,
59
+ repeatable: false,
60
+ requirements: ['Create account', 'Verify email', 'Complete profile'],
61
+ tags: ['new-member', 'onboarding', 'easy']
62
+ },
63
+ {
64
+ id: 'bounty-early-adopter',
65
+ name: 'Early Adopter Bonus',
66
+ category: 'entry',
67
+ description: 'Launch period only — earn 1,250 NCTR as an early adopter. Available during launch period.',
68
+ amount: 1250,
69
+ currency: 'NCTR',
70
+ lock_period: '360LOCK',
71
+ lock_days: 360,
72
+ repeatable: false,
73
+ requirements: ['Join during launch period'],
74
+ tags: ['limited-time', 'launch', 'bonus']
75
+ },
76
+ {
77
+ id: 'bounty-profile-complete',
78
+ name: 'Profile Completion Bounty',
79
+ category: 'entry',
80
+ description: 'Fill out your full profile including avatar, bio, and preferences. Earn 375 NCTR.',
81
+ amount: 375,
82
+ currency: 'NCTR',
83
+ lock_period: '360LOCK',
84
+ lock_days: 360,
85
+ repeatable: false,
86
+ requirements: ['Upload avatar', 'Write bio', 'Set preferences'],
87
+ tags: ['onboarding', 'profile', 'easy']
88
+ },
89
+ // ── Revenue Bounties ──
90
+ {
91
+ id: 'bounty-first-purchase',
92
+ name: 'First Purchase Bounty',
93
+ category: 'revenue',
94
+ description: 'Make your first purchase through The Garden and earn 2,500 NCTR.',
95
+ amount: 2500,
96
+ currency: 'NCTR',
97
+ lock_period: '360LOCK',
98
+ lock_days: 360,
99
+ repeatable: false,
100
+ requirements: ['Complete first purchase through The Garden'],
101
+ tags: ['shopping', 'first-time', 'the-garden']
102
+ },
103
+ {
104
+ id: 'bounty-shop-and-earn',
105
+ name: 'Shop & Earn',
106
+ category: 'revenue',
107
+ description: 'Earn 250 NCTR per qualifying purchase through The Garden. No cap — earn every time you shop.',
108
+ amount: 250,
109
+ currency: 'NCTR',
110
+ lock_period: '360LOCK',
111
+ lock_days: 360,
112
+ repeatable: true,
113
+ requirements: ['Make a qualifying purchase through The Garden'],
114
+ tags: ['shopping', 'recurring', 'the-garden', 'uncapped']
115
+ },
116
+ {
117
+ id: 'bounty-quarterly-spend',
118
+ name: 'Quarterly Spend Bounty',
119
+ category: 'revenue',
120
+ description: 'Hit the quarterly spend threshold and earn 5,000 NCTR. Resets each quarter.',
121
+ amount: 5000,
122
+ currency: 'NCTR',
123
+ lock_period: '360LOCK',
124
+ lock_days: 360,
125
+ repeatable: true,
126
+ requirements: ['Reach quarterly spend threshold'],
127
+ tags: ['shopping', 'quarterly', 'milestone']
128
+ },
129
+ {
130
+ id: 'bounty-annual-member',
131
+ name: 'Annual Member Bounty',
132
+ category: 'revenue',
133
+ description: 'Maintain active membership for a full year and earn 10,000 NCTR.',
134
+ amount: 10000,
135
+ currency: 'NCTR',
136
+ lock_period: '360LOCK',
137
+ lock_days: 360,
138
+ repeatable: true,
139
+ requirements: ['Maintain active membership for 12 months'],
140
+ tags: ['loyalty', 'annual', 'milestone']
141
+ },
142
+ {
143
+ id: 'bounty-whale-spend',
144
+ name: 'Whale Spend Bounty',
145
+ category: 'revenue',
146
+ description: 'Reach the top-tier annual spend level and earn 25,000 NCTR.',
147
+ amount: 25000,
148
+ currency: 'NCTR',
149
+ lock_period: '360LOCK',
150
+ lock_days: 360,
151
+ repeatable: true,
152
+ requirements: ['Reach top-tier annual spend threshold'],
153
+ tags: ['premium', 'annual', 'high-value']
154
+ },
155
+ // ── Merch Bounties ──
156
+ {
157
+ id: 'bounty-merch-collection',
158
+ name: 'Merch Collection Bounty',
159
+ category: 'merch',
160
+ description: 'Purchase from an NCTR merch collection and earn 5,000 NCTR.',
161
+ amount: 5000,
162
+ currency: 'NCTR',
163
+ lock_period: '360LOCK',
164
+ lock_days: 360,
165
+ repeatable: false,
166
+ requirements: ['Purchase from official NCTR merch collection'],
167
+ tags: ['merch', 'collection', 'branded']
168
+ },
169
+ {
170
+ id: 'bounty-merch-repeat',
171
+ name: 'Merch Repeat Bounty',
172
+ category: 'merch',
173
+ description: 'Earn 500 NCTR for each additional merch purchase.',
174
+ amount: 500,
175
+ currency: 'NCTR',
176
+ lock_period: '360LOCK',
177
+ lock_days: 360,
178
+ repeatable: true,
179
+ requirements: ['Purchase additional merch items'],
180
+ tags: ['merch', 'recurring']
181
+ },
182
+ // ── Referral Bounties ──
183
+ {
184
+ id: 'bounty-referral-signup',
185
+ name: 'Referral Sign-Up Bounty',
186
+ category: 'referral',
187
+ description: 'Refer a friend who creates an account. Earn 625 NCTR per referral.',
188
+ amount: 625,
189
+ currency: 'NCTR',
190
+ lock_period: '360LOCK',
191
+ lock_days: 360,
192
+ repeatable: true,
193
+ requirements: ['Referred friend creates account'],
194
+ tags: ['referral', 'friend', 'recurring']
195
+ },
196
+ {
197
+ id: 'bounty-referral-purchase',
198
+ name: 'Referral Purchase Bounty',
199
+ category: 'referral',
200
+ description: 'Earn 2,500 NCTR when your referral makes their first purchase.',
201
+ amount: 2500,
202
+ currency: 'NCTR',
203
+ lock_period: '360LOCK',
204
+ lock_days: 360,
205
+ repeatable: true,
206
+ requirements: ['Referred friend completes first purchase'],
207
+ tags: ['referral', 'purchase', 'recurring']
208
+ },
209
+ {
210
+ id: 'bounty-early-referral',
211
+ name: 'Early Referral Bonus',
212
+ category: 'referral',
213
+ description: 'Launch period referral bonus — earn 500 NCTR per referral during early access.',
214
+ amount: 500,
215
+ currency: 'NCTR',
216
+ lock_period: '360LOCK',
217
+ lock_days: 360,
218
+ repeatable: true,
219
+ requirements: ['Refer during launch period'],
220
+ tags: ['referral', 'launch', 'limited-time']
221
+ },
222
+ {
223
+ id: 'bounty-referral-milestone-5',
224
+ name: 'Referral Milestone — 5 Friends',
225
+ category: 'referral',
226
+ description: 'Refer 5 friends who all sign up. Earn a 2,500 NCTR milestone bonus.',
227
+ amount: 2500,
228
+ currency: 'NCTR',
229
+ lock_period: '360LOCK',
230
+ lock_days: 360,
231
+ repeatable: false,
232
+ requirements: ['5 referred friends create accounts'],
233
+ tags: ['referral', 'milestone']
234
+ },
235
+ {
236
+ id: 'bounty-referral-milestone-20',
237
+ name: 'Referral Milestone — 20 Friends',
238
+ category: 'referral',
239
+ description: 'Refer 20 friends who all sign up. Earn a 5,000 NCTR milestone bonus.',
240
+ amount: 5000,
241
+ currency: 'NCTR',
242
+ lock_period: '360LOCK',
243
+ lock_days: 360,
244
+ repeatable: false,
245
+ requirements: ['20 referred friends create accounts'],
246
+ tags: ['referral', 'milestone', 'ambassador']
247
+ },
248
+ // ── Engagement Bounties ──
249
+ {
250
+ id: 'bounty-social-share',
251
+ name: 'Social Share Bounty',
252
+ category: 'engagement',
253
+ description: 'Share NCTR on social media and earn 500 NCTR.',
254
+ amount: 500,
255
+ currency: 'NCTR',
256
+ lock_period: '360LOCK',
257
+ lock_days: 360,
258
+ repeatable: false,
259
+ requirements: ['Share NCTR content on social media', 'Tag @NCTRAlliance'],
260
+ tags: ['social', 'sharing', 'easy']
261
+ },
262
+ {
263
+ id: 'bounty-monthly-engagement',
264
+ name: 'Monthly Engagement Bounty',
265
+ category: 'engagement',
266
+ description: 'Stay active each month — earn 250 NCTR per month, up to 4 months.',
267
+ amount: 250,
268
+ currency: 'NCTR',
269
+ lock_period: '360LOCK',
270
+ lock_days: 360,
271
+ repeatable: true,
272
+ requirements: ['Log in and complete qualifying activity each month'],
273
+ tags: ['monthly', 'activity', 'recurring']
274
+ },
275
+ {
276
+ id: 'bounty-community-contributor',
277
+ name: 'Community Contributor Bounty',
278
+ category: 'engagement',
279
+ description: 'Make a meaningful contribution to the NCTR community and earn 2,000 NCTR.',
280
+ amount: 2000,
281
+ currency: 'NCTR',
282
+ lock_period: '360LOCK',
283
+ lock_days: 360,
284
+ repeatable: false,
285
+ requirements: ['Submit approved community contribution'],
286
+ tags: ['community', 'contribution']
287
+ },
288
+ {
289
+ id: 'bounty-impact-engine-join',
290
+ name: 'Impact Engine Join Bounty',
291
+ category: 'engagement',
292
+ description: 'Join an Impact Engine community and earn 5,000 NCTR.',
293
+ amount: 5000,
294
+ currency: 'NCTR',
295
+ lock_period: '360LOCK',
296
+ lock_days: 360,
297
+ repeatable: false,
298
+ requirements: ['Join any Impact Engine community'],
299
+ tags: ['impact-engine', 'community', 'joining']
300
+ }
301
+ ]
302
+
303
+ // ─────────────────────────────────────────────────────────────
304
+ // DATA: Crescendo Status Tiers
305
+ // ─────────────────────────────────────────────────────────────
306
+
307
+ interface Tier {
308
+ name: string
309
+ threshold: number
310
+ multiplier: number
311
+ description: string
312
+ perks: string[]
313
+ }
314
+
315
+ const TIERS: Tier[] = [
316
+ {
317
+ name: 'Bronze',
318
+ threshold: 0,
319
+ multiplier: 1.0,
320
+ description: 'Starting tier — all members begin here. Base earning rate on all bounties.',
321
+ perks: ['Access to all standard bounties', 'The Garden shopping', 'Community access']
322
+ },
323
+ {
324
+ name: 'Silver',
325
+ threshold: 1000,
326
+ multiplier: 1.2,
327
+ description: 'Committed members with 1,000+ NCTR locked. 1.2x earning multiplier.',
328
+ perks: ['1.2x earning multiplier', 'Early access to new bounties', 'Silver badge']
329
+ },
330
+ {
331
+ name: 'Gold',
332
+ threshold: 5000,
333
+ multiplier: 1.5,
334
+ description: 'Active members with 5,000+ NCTR locked. 1.5x earning multiplier.',
335
+ perks: ['1.5x earning multiplier', 'Exclusive Gold bounties', 'Priority support', 'Gold badge']
336
+ },
337
+ {
338
+ name: 'Platinum',
339
+ threshold: 25000,
340
+ multiplier: 1.8,
341
+ description: 'Power members with 25,000+ NCTR locked. 1.8x earning multiplier.',
342
+ perks: ['1.8x earning multiplier', 'VIP experiences', 'Platinum-only drops', 'Platinum badge']
343
+ },
344
+ {
345
+ name: 'Diamond',
346
+ threshold: 100000,
347
+ multiplier: 2.0,
348
+ description: 'Top-tier members with 100,000+ NCTR locked. 2.0x earning multiplier.',
349
+ perks: ['2.0x earning multiplier', 'Founding member recognition', 'Diamond-exclusive events', 'Diamond badge', 'Direct team access']
350
+ }
351
+ ]
352
+
353
+ // ─────────────────────────────────────────────────────────────
354
+ // DATA: Impact Engines
355
+ // ─────────────────────────────────────────────────────────────
356
+
357
+ interface ImpactEngine {
358
+ name: string
359
+ slug: string
360
+ category: string
361
+ description: string
362
+ status: string
363
+ }
364
+
365
+ const IMPACT_ENGINES: ImpactEngine[] = [
366
+ {
367
+ name: 'THROTTLE',
368
+ slug: 'throttle',
369
+ category: 'Powersports',
370
+ description: 'The powersports community within NCTR. Connecting riders, racers, and off-road enthusiasts through shared rewards.',
371
+ status: 'active'
372
+ },
373
+ {
374
+ name: 'GROUNDBALL',
375
+ slug: 'groundball',
376
+ category: 'Lacrosse',
377
+ description: 'The lacrosse community within NCTR. Uniting players, coaches, and fans at every level of the sport.',
378
+ status: 'active'
379
+ },
380
+ {
381
+ name: 'STARDUST',
382
+ slug: 'stardust',
383
+ category: 'Entertainment',
384
+ description: 'The entertainment community within NCTR. Connecting creators, performers, and fans across music, film, and live events.',
385
+ status: 'active'
386
+ },
387
+ {
388
+ name: 'SWEAT',
389
+ slug: 'sweat',
390
+ category: 'Skilled Trades',
391
+ description: 'The skilled trades community within NCTR. Supporting tradespeople, apprentices, and craftworkers.',
392
+ status: 'active'
393
+ },
394
+ {
395
+ name: 'SISU',
396
+ slug: 'sisu',
397
+ category: 'Recovery',
398
+ description: 'The recovery community within NCTR. A judgment-free space for people on recovery journeys.',
399
+ status: 'active'
400
+ },
401
+ {
402
+ name: 'INSPIRATION',
403
+ slug: 'inspiration',
404
+ category: 'Wellness',
405
+ description: 'The wellness community within NCTR. Focused on mindfulness, fitness, nutrition, and holistic well-being.',
406
+ status: 'active'
407
+ }
408
+ ]
409
+
410
+ // ─────────────────────────────────────────────────────────────
411
+ // DATA: Active Promotions
412
+ // ─────────────────────────────────────────────────────────────
413
+
414
+ interface Promotion {
415
+ name: string
416
+ description: string
417
+ type: string
418
+ bounty_id: string | null
419
+ active: boolean
420
+ details: string
421
+ }
422
+
423
+ const PROMOTIONS: Promotion[] = [
424
+ {
425
+ name: 'Early Adopter Bonus',
426
+ description: 'Earn 1,250 NCTR just for joining during the launch period. No counter, no slot limit — available while the launch window is open.',
427
+ type: 'launch-bonus',
428
+ bounty_id: 'bounty-early-adopter',
429
+ active: true,
430
+ details: 'Launch period only. 1,250 NCTR with 360LOCK. Open to all new members.'
431
+ },
432
+ {
433
+ name: 'Early Referral Bonus',
434
+ description: 'During the launch period, earn 500 NCTR for each friend you refer (instead of standard 100 NCTR post-launch).',
435
+ type: 'referral-boost',
436
+ bounty_id: 'bounty-early-referral',
437
+ active: true,
438
+ details: 'Launch period only. 5x the standard referral rate. No cap on referrals.'
439
+ }
440
+ ]
441
+
442
+ // ─────────────────────────────────────────────────────────────
443
+ // MCP SERVER
444
+ // ─────────────────────────────────────────────────────────────
445
+
446
+ const app = new Hono()
447
+
448
+ const server = new McpServer({
449
+ name: 'nctr-alliance',
450
+ version: '1.0.0',
451
+ })
452
+
453
+ // ── Tool 1: search_bounties ──
454
+
455
+ server.registerTool(
456
+ 'search_bounties',
457
+ {
458
+ title: 'Search Bounties',
459
+ description:
460
+ 'Search and filter available NCTR bounties. Filter by category (entry, revenue, merch, referral, engagement), minimum/maximum NCTR amount, or keyword. Returns bounty details including name, amount, lock period, and requirements. All bounties use 360LOCK — tokens stay yours after the lock period.',
461
+ inputSchema: {
462
+ category: z
463
+ .enum(['entry', 'revenue', 'merch', 'referral', 'engagement'])
464
+ .optional()
465
+ .describe('Filter by bounty category'),
466
+ min_amount: z.number().optional().describe('Minimum NCTR amount'),
467
+ max_amount: z.number().optional().describe('Maximum NCTR amount'),
468
+ keyword: z
469
+ .string()
470
+ .optional()
471
+ .describe('Search keyword to match against bounty name, description, or tags'),
472
+ repeatable_only: z
473
+ .boolean()
474
+ .optional()
475
+ .describe('If true, only return bounties that can be earned multiple times'),
476
+ },
477
+ },
478
+ ({ category, min_amount, max_amount, keyword, repeatable_only }) => {
479
+ let results = [...BOUNTIES]
480
+
481
+ if (category) {
482
+ results = results.filter((b) => b.category === category)
483
+ }
484
+ if (min_amount !== undefined) {
485
+ results = results.filter((b) => b.amount >= min_amount)
486
+ }
487
+ if (max_amount !== undefined) {
488
+ results = results.filter((b) => b.amount <= max_amount)
489
+ }
490
+ if (keyword) {
491
+ const kw = keyword.toLowerCase()
492
+ results = results.filter(
493
+ (b) =>
494
+ b.name.toLowerCase().includes(kw) ||
495
+ b.description.toLowerCase().includes(kw) ||
496
+ b.tags.some((t) => t.includes(kw))
497
+ )
498
+ }
499
+ if (repeatable_only) {
500
+ results = results.filter((b) => b.repeatable)
501
+ }
502
+
503
+ if (results.length === 0) {
504
+ return {
505
+ content: [
506
+ {
507
+ type: 'text',
508
+ text: 'No bounties found matching your filters. Try broadening your search — there are 19 bounties across 5 categories.',
509
+ },
510
+ ],
511
+ }
512
+ }
513
+
514
+ const formatted = results.map((b) => ({
515
+ id: b.id,
516
+ name: b.name,
517
+ category: b.category,
518
+ amount: `${b.amount.toLocaleString()} NCTR`,
519
+ lock: b.lock_period,
520
+ repeatable: b.repeatable,
521
+ description: b.description,
522
+ requirements: b.requirements,
523
+ }))
524
+
525
+ return {
526
+ content: [
527
+ {
528
+ type: 'text',
529
+ text: JSON.stringify(
530
+ {
531
+ total: results.length,
532
+ bounties: formatted,
533
+ note: 'All bounties use 360LOCK (exactly 360 days). Tokens are committed, not spent — they stay yours after the lock period.',
534
+ },
535
+ null,
536
+ 2
537
+ ),
538
+ },
539
+ ],
540
+ }
541
+ }
542
+ )
543
+
544
+ // ── Tool 2: get_earning_rates ──
545
+
546
+ server.registerTool(
547
+ 'get_earning_rates',
548
+ {
549
+ title: 'Get Earning Rates',
550
+ description:
551
+ 'Get NCTR earning rates for a specific Crescendo status tier, or compare all tiers. Shows the multiplier applied to bounty earnings at each tier level. Higher tiers earn more NCTR per bounty.',
552
+ inputSchema: {
553
+ tier: z
554
+ .enum(['Bronze', 'Silver', 'Gold', 'Platinum', 'Diamond'])
555
+ .optional()
556
+ .describe('Specific tier to check. Omit to see all tiers.'),
557
+ bounty_id: z
558
+ .string()
559
+ .optional()
560
+ .describe('Optional bounty ID to calculate tier-adjusted earning amount'),
561
+ },
562
+ },
563
+ ({ tier, bounty_id }) => {
564
+ let tiers = [...TIERS]
565
+ if (tier) {
566
+ tiers = tiers.filter((t) => t.name === tier)
567
+ }
568
+
569
+ const bounty = bounty_id ? BOUNTIES.find((b) => b.id === bounty_id) : null
570
+
571
+ const formatted = tiers.map((t) => {
572
+ const result: Record<string, unknown> = {
573
+ tier: t.name,
574
+ nctr_threshold: `${t.threshold.toLocaleString()} NCTR`,
575
+ multiplier: `${t.multiplier}x`,
576
+ description: t.description,
577
+ perks: t.perks,
578
+ }
579
+
580
+ if (bounty) {
581
+ const adjusted = Math.floor(bounty.amount * t.multiplier)
582
+ result.bounty_name = bounty.name
583
+ result.base_amount = `${bounty.amount.toLocaleString()} NCTR`
584
+ result.adjusted_amount = `${adjusted.toLocaleString()} NCTR`
585
+ }
586
+
587
+ return result
588
+ })
589
+
590
+ return {
591
+ content: [
592
+ {
593
+ type: 'text',
594
+ text: JSON.stringify(
595
+ {
596
+ tiers: formatted,
597
+ note: 'Crescendo Status Tiers determine your earning multiplier. Lock more NCTR to progress through tiers and earn more on every bounty.',
598
+ },
599
+ null,
600
+ 2
601
+ ),
602
+ },
603
+ ],
604
+ }
605
+ }
606
+ )
607
+
608
+ // ── Tool 3: check_tier_requirements ──
609
+
610
+ server.registerTool(
611
+ 'check_tier_requirements',
612
+ {
613
+ title: 'Check Tier Requirements',
614
+ description:
615
+ 'Check what is needed to reach a specific Crescendo status tier, or see the full progression path. Shows NCTR lock thresholds, multipliers, and perks for each tier.',
616
+ inputSchema: {
617
+ current_balance: z
618
+ .number()
619
+ .optional()
620
+ .describe('Current NCTR balance to check tier status and progress to next tier'),
621
+ target_tier: z
622
+ .enum(['Bronze', 'Silver', 'Gold', 'Platinum', 'Diamond'])
623
+ .optional()
624
+ .describe('Target tier to check requirements for'),
625
+ },
626
+ },
627
+ ({ current_balance, target_tier }) => {
628
+ if (target_tier) {
629
+ const tier = TIERS.find((t) => t.name === target_tier)!
630
+ const result: Record<string, unknown> = {
631
+ tier: tier.name,
632
+ nctr_required: `${tier.threshold.toLocaleString()} NCTR`,
633
+ multiplier: `${tier.multiplier}x`,
634
+ perks: tier.perks,
635
+ description: tier.description,
636
+ }
637
+
638
+ if (current_balance !== undefined) {
639
+ if (current_balance >= tier.threshold) {
640
+ result.status = 'QUALIFIED'
641
+ result.message = `You already qualify for ${tier.name} with ${current_balance.toLocaleString()} NCTR.`
642
+ } else {
643
+ const needed = tier.threshold - current_balance
644
+ result.status = 'NOT YET'
645
+ result.nctr_needed = `${needed.toLocaleString()} NCTR`
646
+ result.message = `You need ${needed.toLocaleString()} more NCTR to reach ${tier.name}.`
647
+ }
648
+ }
649
+
650
+ return {
651
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
652
+ }
653
+ }
654
+
655
+ // Full tier progression
656
+ const progression = TIERS.map((t) => {
657
+ const result: Record<string, unknown> = {
658
+ tier: t.name,
659
+ nctr_required: `${t.threshold.toLocaleString()} NCTR`,
660
+ multiplier: `${t.multiplier}x`,
661
+ perks: t.perks,
662
+ }
663
+
664
+ if (current_balance !== undefined) {
665
+ result.qualified = current_balance >= t.threshold
666
+ if (current_balance < t.threshold) {
667
+ result.nctr_needed = `${(t.threshold - current_balance).toLocaleString()} NCTR`
668
+ }
669
+ }
670
+
671
+ return result
672
+ })
673
+
674
+ let current_tier = 'Bronze'
675
+ if (current_balance !== undefined) {
676
+ for (const t of [...TIERS].reverse()) {
677
+ if (current_balance >= t.threshold) {
678
+ current_tier = t.name
679
+ break
680
+ }
681
+ }
682
+ }
683
+
684
+ return {
685
+ content: [
686
+ {
687
+ type: 'text',
688
+ text: JSON.stringify(
689
+ {
690
+ current_tier: current_balance !== undefined ? current_tier : undefined,
691
+ current_balance:
692
+ current_balance !== undefined
693
+ ? `${current_balance.toLocaleString()} NCTR`
694
+ : undefined,
695
+ progression,
696
+ note: 'Tiers are based on total NCTR locked. Higher tiers unlock better multipliers and exclusive perks.',
697
+ },
698
+ null,
699
+ 2
700
+ ),
701
+ },
702
+ ],
703
+ }
704
+ }
705
+ )
706
+
707
+ // ── Tool 4: get_active_promotions ──
708
+
709
+ server.registerTool(
710
+ 'get_active_promotions',
711
+ {
712
+ title: 'Get Active Promotions',
713
+ description:
714
+ 'Get currently active promotions, limited-time offers, and special earning opportunities in the NCTR program.',
715
+ inputSchema: {},
716
+ },
717
+ () => {
718
+ const active = PROMOTIONS.filter((p) => p.active)
719
+
720
+ if (active.length === 0) {
721
+ return {
722
+ content: [
723
+ {
724
+ type: 'text',
725
+ text: 'No special promotions are active right now. Check back soon — new opportunities launch regularly.',
726
+ },
727
+ ],
728
+ }
729
+ }
730
+
731
+ const formatted = active.map((p) => ({
732
+ name: p.name,
733
+ type: p.type,
734
+ description: p.description,
735
+ details: p.details,
736
+ related_bounty: p.bounty_id,
737
+ }))
738
+
739
+ return {
740
+ content: [
741
+ {
742
+ type: 'text',
743
+ text: JSON.stringify(
744
+ {
745
+ active_promotions: formatted,
746
+ count: active.length,
747
+ note: 'Promotions are time-limited. Join now to take advantage of launch period bonuses.',
748
+ },
749
+ null,
750
+ 2
751
+ ),
752
+ },
753
+ ],
754
+ }
755
+ }
756
+ )
757
+
758
+ // ── Tool 5: get_onboarding_link ──
759
+
760
+ server.registerTool(
761
+ 'get_onboarding_link',
762
+ {
763
+ title: 'Get Onboarding Link',
764
+ description:
765
+ 'Generate a link for a new member to join NCTR Alliance. Optionally include a referral code. Returns the sign-up URL and a summary of what new members earn.',
766
+ inputSchema: {
767
+ referral_code: z
768
+ .string()
769
+ .optional()
770
+ .describe('Optional referral code to credit the referring member'),
771
+ },
772
+ },
773
+ ({ referral_code }) => {
774
+ const baseUrl = 'https://crescendo.nctr.live/join'
775
+ const url = referral_code ? `${baseUrl}?ref=${encodeURIComponent(referral_code)}` : baseUrl
776
+
777
+ const welcomePackage = {
778
+ url,
779
+ welcome_bounties: [
780
+ { name: 'Sign-Up Bounty', amount: '625 NCTR', lock: '360LOCK' },
781
+ { name: 'Early Adopter Bonus', amount: '1,250 NCTR', lock: '360LOCK', note: 'Launch period only' },
782
+ { name: 'Profile Completion Bounty', amount: '375 NCTR', lock: '360LOCK' },
783
+ ],
784
+ total_potential: '2,250 NCTR',
785
+ referral_code: referral_code || null,
786
+ note: 'New members can earn up to 2,250 NCTR just by signing up and completing their profile during the launch period. All tokens use 360LOCK — committed, not spent.',
787
+ }
788
+
789
+ return {
790
+ content: [{ type: 'text', text: JSON.stringify(welcomePackage, null, 2) }],
791
+ }
792
+ }
793
+ )
794
+
795
+ // ── Tool 6: get_impact_engines ──
796
+
797
+ server.registerTool(
798
+ 'get_impact_engines',
799
+ {
800
+ title: 'Get Impact Engines',
801
+ description:
802
+ 'Discover NCTR Impact Engine communities. Impact Engines are passion-based communities within NCTR — each focused on a different lifestyle vertical. Members can join any Impact Engine to connect with like-minded people and access community-specific experiences.',
803
+ inputSchema: {
804
+ category: z
805
+ .string()
806
+ .optional()
807
+ .describe(
808
+ 'Filter by category (Powersports, Lacrosse, Entertainment, Skilled Trades, Recovery, Wellness)'
809
+ ),
810
+ },
811
+ },
812
+ ({ category }) => {
813
+ let engines = [...IMPACT_ENGINES]
814
+
815
+ if (category) {
816
+ const cat = category.toLowerCase()
817
+ engines = engines.filter((e) => e.category.toLowerCase().includes(cat))
818
+ }
819
+
820
+ if (engines.length === 0) {
821
+ return {
822
+ content: [
823
+ {
824
+ type: 'text',
825
+ text: `No Impact Engines found for "${category}". Available categories: Powersports, Lacrosse, Entertainment, Skilled Trades, Recovery, Wellness.`,
826
+ },
827
+ ],
828
+ }
829
+ }
830
+
831
+ const formatted = engines.map((e) => ({
832
+ name: e.name,
833
+ category: e.category,
834
+ description: e.description,
835
+ status: e.status,
836
+ }))
837
+
838
+ return {
839
+ content: [
840
+ {
841
+ type: 'text',
842
+ text: JSON.stringify(
843
+ {
844
+ impact_engines: formatted,
845
+ count: engines.length,
846
+ bounty: 'Join any Impact Engine to earn the Impact Engine Join Bounty — 5,000 NCTR with 360LOCK.',
847
+ note: 'Impact Engines are passion-based communities. Each one connects people around a shared interest, with community-specific experiences and rewards.',
848
+ },
849
+ null,
850
+ 2
851
+ ),
852
+ },
853
+ ],
854
+ }
855
+ }
856
+ )
857
+
858
+ // ─────────────────────────────────────────────────────────────
859
+ // HTTP HANDLER
860
+ // ─────────────────────────────────────────────────────────────
861
+
862
+ app.get('/', (c) => {
863
+ return c.json({
864
+ name: 'NCTR Alliance MCP Server',
865
+ version: '1.0.0',
866
+ description:
867
+ 'Model Context Protocol server for AI agents to discover and interact with the NCTR rewards program.',
868
+ tools: [
869
+ 'search_bounties',
870
+ 'get_earning_rates',
871
+ 'check_tier_requirements',
872
+ 'get_active_promotions',
873
+ 'get_onboarding_link',
874
+ 'get_impact_engines',
875
+ ],
876
+ links: {
877
+ website: 'https://nctr.live',
878
+ the_garden: 'https://thegarden.nctr.live',
879
+ onboarding: 'https://crescendo.nctr.live',
880
+ for_agents: 'https://thegarden.nctr.live/for-agents',
881
+ manifest: 'https://nctr.live/.well-known/nctr.json',
882
+ },
883
+ })
884
+ })
885
+
886
+ app.all('/mcp', async (c) => {
887
+ const transport = new WebStandardStreamableHTTPServerTransport()
888
+ await server.connect(transport)
889
+ return transport.handleRequest(c.req.raw)
890
+ })
891
+
892
+ // Health check
893
+ app.get('/health', (c) => {
894
+ return c.json({ status: 'ok', timestamp: new Date().toISOString() })
895
+ })
896
+
897
+ Deno.serve(app.fetch)
@@ -0,0 +1,197 @@
1
+ #!/bin/bash
2
+ # ═══════════════════════════════════════════════════════════════
3
+ # NCTR Alliance MCP Server — Test Script
4
+ # ═══════════════════════════════════════════════════════════════
5
+ # Usage:
6
+ # bash test-mcp-server.sh # Test local server
7
+ # bash test-mcp-server.sh https://xyz.supabase.co/functions/v1/mcp # Test production
8
+ # ═══════════════════════════════════════════════════════════════
9
+
10
+ BASE_URL="${1:-https://yhwcaodofmbusjurawhp.supabase.co/functions/v1/mcp}"
11
+ MCP_URL="${BASE_URL}/rpc"
12
+ PASS=0
13
+ FAIL=0
14
+
15
+ echo ""
16
+ echo "╔══════════════════════════════════════════════════════╗"
17
+ echo "║ NCTR Alliance MCP Server — Test Suite ║"
18
+ echo "╠══════════════════════════════════════════════════════╣"
19
+ echo "║ Target: $BASE_URL"
20
+ echo "╚══════════════════════════════════════════════════════╝"
21
+ echo ""
22
+
23
+ # ── Helper ──
24
+ run_test() {
25
+ local test_name="$1"
26
+ local method_name="$2"
27
+ local params="$3"
28
+ local expect_text="$4"
29
+
30
+ echo "─── Test: $test_name ───"
31
+
32
+ RESPONSE=$(curl -s -X POST "$MCP_URL" \
33
+ -H "Content-Type: application/json" \
34
+ -H "Accept: application/json, text/event-stream" \
35
+ -d "{
36
+ \"jsonrpc\": \"2.0\",
37
+ \"id\": 1,
38
+ \"method\": \"tools/call\",
39
+ \"params\": {
40
+ \"name\": \"$method_name\",
41
+ \"arguments\": $params
42
+ }
43
+ }")
44
+
45
+ # Extract data line from SSE response
46
+ DATA_LINE=$(echo "$RESPONSE" | grep "^data:" | head -1 | sed 's/^data: //')
47
+
48
+ if [ -z "$DATA_LINE" ]; then
49
+ # Try parsing as direct JSON (non-SSE response)
50
+ DATA_LINE="$RESPONSE"
51
+ fi
52
+
53
+ if echo "$DATA_LINE" | grep -q "$expect_text"; then
54
+ echo " ✅ PASS — Found expected: $expect_text"
55
+ PASS=$((PASS + 1))
56
+ else
57
+ echo " ❌ FAIL — Expected to find: $expect_text"
58
+ echo " Response: $(echo "$DATA_LINE" | head -c 200)"
59
+ FAIL=$((FAIL + 1))
60
+ fi
61
+ echo ""
62
+ }
63
+
64
+ # ── Test 0: Health Check ──
65
+ echo "─── Test: Health Check ───"
66
+ HEALTH=$(curl -s "$BASE_URL/health")
67
+ if echo "$HEALTH" | grep -q '"status":"ok"'; then
68
+ echo " ✅ PASS — Server is healthy"
69
+ PASS=$((PASS + 1))
70
+ else
71
+ echo " ❌ FAIL — Health check failed"
72
+ echo " Response: $HEALTH"
73
+ FAIL=$((FAIL + 1))
74
+ fi
75
+ echo ""
76
+
77
+ # ── Test 1: Root Info ──
78
+ echo "─── Test: Root Info Endpoint ───"
79
+ ROOT=$(curl -s "$BASE_URL/")
80
+ if echo "$ROOT" | grep -q "NCTR Alliance MCP Server"; then
81
+ echo " ✅ PASS — Root endpoint returns server info"
82
+ PASS=$((PASS + 1))
83
+ else
84
+ echo " ❌ FAIL — Root endpoint missing server info"
85
+ FAIL=$((FAIL + 1))
86
+ fi
87
+ echo ""
88
+
89
+ # ── Test 2: search_bounties — All Bounties ──
90
+ run_test "search_bounties — All Bounties" \
91
+ "search_bounties" \
92
+ "{}" \
93
+ "total"
94
+
95
+ # ── Test 3: search_bounties — Filter by Category ──
96
+ run_test "search_bounties — Entry Category" \
97
+ "search_bounties" \
98
+ '{"category": "entry"}' \
99
+ "Sign-Up Bounty"
100
+
101
+ # ── Test 4: search_bounties — Filter by Amount ──
102
+ run_test "search_bounties — Min 5000 NCTR" \
103
+ "search_bounties" \
104
+ '{"min_amount": 5000}' \
105
+ "5,000 NCTR"
106
+
107
+ # ── Test 5: search_bounties — Keyword Search ──
108
+ run_test "search_bounties — Keyword: referral" \
109
+ "search_bounties" \
110
+ '{"keyword": "referral"}' \
111
+ "Referral"
112
+
113
+ # ── Test 6: search_bounties — Repeatable Only ──
114
+ run_test "search_bounties — Repeatable Only" \
115
+ "search_bounties" \
116
+ '{"repeatable_only": true}' \
117
+ "repeatable"
118
+
119
+ # ── Test 7: get_earning_rates — All Tiers ──
120
+ run_test "get_earning_rates — All Tiers" \
121
+ "get_earning_rates" \
122
+ "{}" \
123
+ "Diamond"
124
+
125
+ # ── Test 8: get_earning_rates — Specific Tier ──
126
+ run_test "get_earning_rates — Gold Tier" \
127
+ "get_earning_rates" \
128
+ '{"tier": "Gold"}' \
129
+ "1.5x"
130
+
131
+ # ── Test 9: get_earning_rates — With Bounty Calculation ──
132
+ run_test "get_earning_rates — Gold + First Purchase Bounty" \
133
+ "get_earning_rates" \
134
+ '{"tier": "Gold", "bounty_id": "bounty-first-purchase"}' \
135
+ "adjusted_amount"
136
+
137
+ # ── Test 10: check_tier_requirements — Full Progression ──
138
+ run_test "check_tier_requirements — Full Progression" \
139
+ "check_tier_requirements" \
140
+ "{}" \
141
+ "progression"
142
+
143
+ # ── Test 11: check_tier_requirements — With Balance ──
144
+ run_test "check_tier_requirements — Balance 3000 NCTR" \
145
+ "check_tier_requirements" \
146
+ '{"current_balance": 3000}' \
147
+ "Silver"
148
+
149
+ # ── Test 12: check_tier_requirements — Target Tier ──
150
+ run_test "check_tier_requirements — Target Diamond" \
151
+ "check_tier_requirements" \
152
+ '{"target_tier": "Diamond", "current_balance": 500}' \
153
+ "NOT YET"
154
+
155
+ # ── Test 13: get_active_promotions ──
156
+ run_test "get_active_promotions" \
157
+ "get_active_promotions" \
158
+ "{}" \
159
+ "Early Adopter"
160
+
161
+ # ── Test 14: get_onboarding_link — No Referral ──
162
+ run_test "get_onboarding_link — No Referral" \
163
+ "get_onboarding_link" \
164
+ "{}" \
165
+ "crescendo.nctr.live/join"
166
+
167
+ # ── Test 15: get_onboarding_link — With Referral ──
168
+ run_test "get_onboarding_link — With Referral Code" \
169
+ "get_onboarding_link" \
170
+ '{"referral_code": "ANDERSON123"}' \
171
+ "ANDERSON123"
172
+
173
+ # ── Test 16: get_impact_engines — All Engines ──
174
+ run_test "get_impact_engines — All Engines" \
175
+ "get_impact_engines" \
176
+ "{}" \
177
+ "THROTTLE"
178
+
179
+ # ── Test 17: get_impact_engines — Filter by Category ──
180
+ run_test "get_impact_engines — Lacrosse" \
181
+ "get_impact_engines" \
182
+ '{"category": "Lacrosse"}' \
183
+ "GROUNDBALL"
184
+
185
+ # ── Results ──
186
+ echo "╔══════════════════════════════════════════════════════╗"
187
+ echo "║ Results: $PASS passed, $FAIL failed "
188
+ echo "╚══════════════════════════════════════════════════════╝"
189
+ echo ""
190
+
191
+ if [ $FAIL -gt 0 ]; then
192
+ echo "⚠️ Some tests failed. Check the output above."
193
+ exit 1
194
+ else
195
+ echo "All tests passed."
196
+ exit 0
197
+ fi