@champz-llc/legends-mcp-server 1.1.1 → 1.2.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 +46 -0
- package/index.js +287 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,6 +58,12 @@ Once configured, you can ask Claude:
|
|
|
58
58
|
- "How much CHAMPZ has been burned?"
|
|
59
59
|
- "How much USDC has been distributed to players?"
|
|
60
60
|
|
|
61
|
+
### Leaderboards
|
|
62
|
+
- "Show me the current cycle leaderboard for Legends"
|
|
63
|
+
- "Who's winning the weekly battle leaderboard?"
|
|
64
|
+
- "What are the all-time leaderboards for Legends of Champz?"
|
|
65
|
+
- "Show me the top 20 players in the current cycle"
|
|
66
|
+
|
|
61
67
|
### Reward Management
|
|
62
68
|
- "Check my claimable rewards in Legends"
|
|
63
69
|
- "Get my CHAMPZ claim data"
|
|
@@ -85,10 +91,50 @@ Get contract call data for claiming CHAMPZ tokens.
|
|
|
85
91
|
### `get_usdc_claim_data`
|
|
86
92
|
Get contract call data for claiming USDC rewards.
|
|
87
93
|
|
|
94
|
+
### `legends_leaderboard_current`
|
|
95
|
+
Get current cycle battle leaderboard (top players in active 12-hour cycle).
|
|
96
|
+
|
|
97
|
+
**Parameters**:
|
|
98
|
+
- `limit` (optional): Number of players to show (1-100, default: 10)
|
|
99
|
+
|
|
100
|
+
**Returns**:
|
|
101
|
+
- Current cycle ID and letter
|
|
102
|
+
- Cycle end time
|
|
103
|
+
- Top players with wins/losses, win rate, streaks
|
|
104
|
+
- Player tier badges and legend rarity
|
|
105
|
+
|
|
106
|
+
### `legends_leaderboard_weekly`
|
|
107
|
+
Get weekly battle leaderboard with USDC prize distribution.
|
|
108
|
+
|
|
109
|
+
**Parameters**:
|
|
110
|
+
- `limit` (optional): Number of players to show (1-100, default: 10)
|
|
111
|
+
|
|
112
|
+
**Returns**:
|
|
113
|
+
- Week number and cycle range
|
|
114
|
+
- Total USDC prize pool ($100)
|
|
115
|
+
- Top players with battle stats and USDC rewards
|
|
116
|
+
- Cycles remaining in current week
|
|
117
|
+
|
|
118
|
+
### `legends_leaderboard_alltime`
|
|
119
|
+
Get all-time leaderboards across 10 categories.
|
|
120
|
+
|
|
121
|
+
**Parameters**:
|
|
122
|
+
- `limit` (optional): Players per category (1-50, default: 10)
|
|
123
|
+
|
|
124
|
+
**Returns**:
|
|
125
|
+
- Most CHAMPZ earned
|
|
126
|
+
- Most USDC earned
|
|
127
|
+
- Most total wins
|
|
128
|
+
- Most guardian wins
|
|
129
|
+
- Highest win rate (min 100 battles)
|
|
130
|
+
- Longest win streak
|
|
131
|
+
- Elemental Charge high scores and stats
|
|
132
|
+
|
|
88
133
|
## 📡 API Endpoints
|
|
89
134
|
|
|
90
135
|
The server connects to:
|
|
91
136
|
- **Global Stats**: `https://api.champz.world/game/spore-trainer/global-stats`
|
|
137
|
+
- **Leaderboards**: `https://api.champz.world/game/spore-trainer/public-leaderboard`
|
|
92
138
|
- **Rewards**: (Coming soon - player-specific endpoints)
|
|
93
139
|
|
|
94
140
|
## 🔧 Development
|
package/index.js
CHANGED
|
@@ -137,6 +137,69 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
137
137
|
properties: {},
|
|
138
138
|
required: []
|
|
139
139
|
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'legends_leaderboard_current',
|
|
143
|
+
description: 'Get current cycle leaderboard for Legends of Champz. Shows top players in the active 12-hour cycle across battles, guardian (throne), or Elemental Charge mini-game.',
|
|
144
|
+
inputSchema: {
|
|
145
|
+
type: 'object',
|
|
146
|
+
properties: {
|
|
147
|
+
category: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description: 'Leaderboard category: battles (default), guardian (throne holders), or ec (Elemental Charge)',
|
|
150
|
+
enum: ['battles', 'guardian', 'ec']
|
|
151
|
+
},
|
|
152
|
+
limit: {
|
|
153
|
+
type: 'number',
|
|
154
|
+
description: 'Number of top players to show (default: 10, max: 100)',
|
|
155
|
+
minimum: 1,
|
|
156
|
+
maximum: 100
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
required: []
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'legends_leaderboard_weekly',
|
|
164
|
+
description: 'Get weekly leaderboard for Legends of Champz. Shows top players for the current week (21 cycles) across battles (with USDC rewards) or guardian (throne competition).',
|
|
165
|
+
inputSchema: {
|
|
166
|
+
type: 'object',
|
|
167
|
+
properties: {
|
|
168
|
+
category: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
description: 'Leaderboard category: battles (default - with USDC rewards) or guardian (throne holders). Note: ec not available for weekly.',
|
|
171
|
+
enum: ['battles', 'guardian']
|
|
172
|
+
},
|
|
173
|
+
limit: {
|
|
174
|
+
type: 'number',
|
|
175
|
+
description: 'Number of top players to show (default: 10, max: 100)',
|
|
176
|
+
minimum: 1,
|
|
177
|
+
maximum: 100
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
required: []
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'legends_leaderboard_alltime',
|
|
185
|
+
description: 'Get all-time leaderboards for Legends of Champz. Can show all categories or filter by battles, guardian, or ec (Elemental Charge) stats.',
|
|
186
|
+
inputSchema: {
|
|
187
|
+
type: 'object',
|
|
188
|
+
properties: {
|
|
189
|
+
category: {
|
|
190
|
+
type: 'string',
|
|
191
|
+
description: 'Filter by category: all (default - shows everything), battles (wins/earnings/streaks), guardian (throne wins), or ec (Elemental Charge scores)',
|
|
192
|
+
enum: ['all', 'battles', 'guardian', 'ec']
|
|
193
|
+
},
|
|
194
|
+
limit: {
|
|
195
|
+
type: 'number',
|
|
196
|
+
description: 'Number of top players per category (default: 10, max: 50)',
|
|
197
|
+
minimum: 1,
|
|
198
|
+
maximum: 50
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
required: []
|
|
202
|
+
},
|
|
140
203
|
}
|
|
141
204
|
],
|
|
142
205
|
};
|
|
@@ -158,19 +221,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
158
221
|
|
|
159
222
|
const stats = data.stats;
|
|
160
223
|
|
|
161
|
-
// CHAMPZ values are
|
|
162
|
-
//
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
// Format in millions for readability
|
|
168
|
-
const earnedMillions = (champzEarned / 1000000).toFixed(2);
|
|
169
|
-
const spentMillions = (champzSpent / 1000000).toFixed(2);
|
|
170
|
-
const burnedMillions = (champzBurned / 1000000).toFixed(2);
|
|
224
|
+
// CHAMPZ values are integers in token units (already divided by 10^8)
|
|
225
|
+
// Just divide by 1,000,000 to display as millions
|
|
226
|
+
const earnedMillions = (stats.champz_earned / 1000000).toFixed(2);
|
|
227
|
+
const spentMillions = (stats.champz_spent / 1000000).toFixed(2);
|
|
228
|
+
const burnedMillions = (stats.champz_burned / 1000000).toFixed(2);
|
|
171
229
|
|
|
172
230
|
// Calculate percentage of 1 billion supply
|
|
173
|
-
const burnedPercent = ((
|
|
231
|
+
const burnedPercent = ((stats.champz_burned / 1000000000) * 100).toFixed(2);
|
|
174
232
|
|
|
175
233
|
const formattedStats = `Legends of Champz - Global Statistics
|
|
176
234
|
|
|
@@ -183,7 +241,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
183
241
|
⚔️ Total Battles: ${stats.battles_total.toLocaleString()}
|
|
184
242
|
🎯 Battles Today: ${stats.battles_today.toLocaleString()}
|
|
185
243
|
|
|
186
|
-
Token Economics: CHAMPZ has 1 billion total supply. ${burnedMillions}
|
|
244
|
+
Token Economics: CHAMPZ has 1 billion total supply. ${burnedMillions}M tokens (${burnedPercent}%) permanently removed from circulation through burns.
|
|
187
245
|
|
|
188
246
|
Last updated: ${new Date(stats.cached_at * 1000).toLocaleString()}`;
|
|
189
247
|
|
|
@@ -256,6 +314,223 @@ Last updated: ${new Date(stats.cached_at * 1000).toLocaleString()}`;
|
|
|
256
314
|
],
|
|
257
315
|
};
|
|
258
316
|
|
|
317
|
+
case 'legends_leaderboard_current':
|
|
318
|
+
try {
|
|
319
|
+
const category = request.params.arguments?.category || 'battles';
|
|
320
|
+
const limit = request.params.arguments?.limit || 10;
|
|
321
|
+
const response = await fetch(`https://api.champz.world/game/spore-trainer/public-leaderboard?type=current&category=${category}&limit=${limit}`);
|
|
322
|
+
const data = await response.json();
|
|
323
|
+
|
|
324
|
+
if (!data.success) {
|
|
325
|
+
throw new Error(data.error || 'Failed to fetch current cycle leaderboard');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let output = '';
|
|
329
|
+
const cycleInfo = `Cycle #${data.cycle_id} (${data.cycle_key}) - Ends: ${new Date(data.ends_at * 1000).toLocaleString()}\n`;
|
|
330
|
+
|
|
331
|
+
if (category === 'battles') {
|
|
332
|
+
output = `🏆 Legends of Champz - Current Cycle Battle Leaderboard\n\n`;
|
|
333
|
+
output += cycleInfo;
|
|
334
|
+
output += `Active Players: ${data.total_players.toLocaleString()}\n\n`;
|
|
335
|
+
output += `Top ${data.showing_top} Players:\n\n`;
|
|
336
|
+
|
|
337
|
+
data.leaderboard.forEach((player, index) => {
|
|
338
|
+
const tierEmoji = player.tier_emoji || '';
|
|
339
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...${player.wallet.slice(-4)}`;
|
|
340
|
+
const winRate = player.win_rate.toFixed(1);
|
|
341
|
+
const record = `${player.wins}W-${player.losses}L`;
|
|
342
|
+
|
|
343
|
+
output += `${index + 1}. ${tierEmoji} ${name}\n`;
|
|
344
|
+
output += ` ${record} (${winRate}% win rate)`;
|
|
345
|
+
if (player.streak > 0) {
|
|
346
|
+
output += ` 🔥 ${player.streak} streak`;
|
|
347
|
+
}
|
|
348
|
+
output += `\n`;
|
|
349
|
+
if (player.rarity) {
|
|
350
|
+
output += ` ${player.rarity.charAt(0).toUpperCase() + player.rarity.slice(1)} • ${player.elements.join('/')}\n`;
|
|
351
|
+
}
|
|
352
|
+
output += `\n`;
|
|
353
|
+
});
|
|
354
|
+
} else if (category === 'guardian') {
|
|
355
|
+
output = `👑 Legends of Champz - Current Cycle Guardian (Throne) Leaderboard\n\n`;
|
|
356
|
+
output += cycleInfo;
|
|
357
|
+
output += `Current Guardian: ${data.current_guardian ? data.current_guardian.slice(0, 6) + '...' : 'None'}\n`;
|
|
358
|
+
output += `Prize Pool: ${data.prize_pool.toLocaleString()} CHAMPZ\n\n`;
|
|
359
|
+
output += `Top ${data.showing_top} Guardian Holders:\n\n`;
|
|
360
|
+
|
|
361
|
+
data.leaderboard.forEach((player) => {
|
|
362
|
+
const tierEmoji = player.tier_emoji || '';
|
|
363
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...${player.wallet.slice(-4)}`;
|
|
364
|
+
const crown = player.is_current ? '👑 ' : '';
|
|
365
|
+
|
|
366
|
+
output += `${player.rank}. ${crown}${tierEmoji} ${name}\n`;
|
|
367
|
+
output += ` Held ${player.times_held}x • Sent ${player.total_sent.toLocaleString()} CHAMPZ\n\n`;
|
|
368
|
+
});
|
|
369
|
+
} else if (category === 'ec') {
|
|
370
|
+
output = `⚡ Legends of Champz - Current Cycle Elemental Charge Leaderboard\n\n`;
|
|
371
|
+
output += cycleInfo;
|
|
372
|
+
output += `Top ${data.showing_top} High Scores:\n\n`;
|
|
373
|
+
|
|
374
|
+
data.leaderboard.forEach((player) => {
|
|
375
|
+
const tierEmoji = player.tier_emoji || '';
|
|
376
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...${player.wallet.slice(-4)}`;
|
|
377
|
+
|
|
378
|
+
output += `${player.rank}. ${tierEmoji} ${name}\n`;
|
|
379
|
+
output += ` Score: ${player.best_score} • Rounds: ${player.best_rounds} • Streak: ${player.best_streak}\n\n`;
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
content: [
|
|
385
|
+
{
|
|
386
|
+
type: 'text',
|
|
387
|
+
text: output,
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
};
|
|
391
|
+
} catch (error) {
|
|
392
|
+
return {
|
|
393
|
+
content: [
|
|
394
|
+
{
|
|
395
|
+
type: 'text',
|
|
396
|
+
text: `Error fetching current cycle leaderboard: ${error.message}`,
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
case 'legends_leaderboard_weekly':
|
|
403
|
+
try {
|
|
404
|
+
const category = request.params.arguments?.category || 'battles';
|
|
405
|
+
const limit = request.params.arguments?.limit || 10;
|
|
406
|
+
const response = await fetch(`https://api.champz.world/game/spore-trainer/public-leaderboard?type=weekly&category=${category}&limit=${limit}`);
|
|
407
|
+
const data = await response.json();
|
|
408
|
+
|
|
409
|
+
if (!data.success) {
|
|
410
|
+
throw new Error(data.error || 'Failed to fetch weekly leaderboard');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
let output = '';
|
|
414
|
+
const weekInfo = `Week ${data.week_number} (Cycles ${data.week_start_cycle}-${data.week_end_cycle})\nCurrent Cycle: ${data.current_cycle} | Cycles Remaining: ${data.cycles_remaining}\n`;
|
|
415
|
+
|
|
416
|
+
if (category === 'battles') {
|
|
417
|
+
output = `💰 Legends of Champz - Weekly Battle Leaderboard\n\n`;
|
|
418
|
+
output += weekInfo;
|
|
419
|
+
output += `Total Prize Pool: $${data.total_pool_usdc} USDC\n`;
|
|
420
|
+
output += `Active Players: ${data.total_players.toLocaleString()}\n\n`;
|
|
421
|
+
output += `Top ${data.showing_top} Players:\n\n`;
|
|
422
|
+
|
|
423
|
+
data.leaderboard.forEach((player, index) => {
|
|
424
|
+
const tierEmoji = player.tier_emoji || '';
|
|
425
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...${player.wallet.slice(-4)}`;
|
|
426
|
+
const winRate = player.win_rate.toFixed(1);
|
|
427
|
+
const record = `${player.wins}W-${player.losses}L`;
|
|
428
|
+
const reward = player.usdc_reward > 0 ? ` 💵 $${player.usdc_reward.toFixed(2)}` : '';
|
|
429
|
+
|
|
430
|
+
output += `${index + 1}. ${tierEmoji} ${name}\n`;
|
|
431
|
+
output += ` ${record} in ${player.battles} battles (${winRate}% WR)${reward}\n\n`;
|
|
432
|
+
});
|
|
433
|
+
} else if (category === 'guardian') {
|
|
434
|
+
output = `👑 Legends of Champz - Weekly Guardian (Throne) Leaderboard\n\n`;
|
|
435
|
+
output += weekInfo;
|
|
436
|
+
output += `\nTop ${data.showing_top} Guardian Competitors:\n\n`;
|
|
437
|
+
|
|
438
|
+
data.leaderboard.forEach((player) => {
|
|
439
|
+
const tierEmoji = player.tier_emoji || '';
|
|
440
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...${player.wallet.slice(-4)}`;
|
|
441
|
+
|
|
442
|
+
output += `${player.rank}. ${tierEmoji} ${name}\n`;
|
|
443
|
+
output += ` ${player.cycles_participated} cycles • ${player.total_sends} sends • ${player.total_sent.toLocaleString()} CHAMPZ\n\n`;
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
content: [
|
|
449
|
+
{
|
|
450
|
+
type: 'text',
|
|
451
|
+
text: output,
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
};
|
|
455
|
+
} catch (error) {
|
|
456
|
+
return {
|
|
457
|
+
content: [
|
|
458
|
+
{
|
|
459
|
+
type: 'text',
|
|
460
|
+
text: `Error fetching weekly leaderboard: ${error.message}`,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
case 'legends_leaderboard_alltime':
|
|
467
|
+
try {
|
|
468
|
+
const category = request.params.arguments?.category || 'all';
|
|
469
|
+
const limit = request.params.arguments?.limit || 10;
|
|
470
|
+
const response = await fetch(`https://api.champz.world/game/spore-trainer/public-leaderboard?type=alltime&category=${category}&limit=${limit}`);
|
|
471
|
+
const data = await response.json();
|
|
472
|
+
|
|
473
|
+
if (!data.success) {
|
|
474
|
+
throw new Error(data.error || 'Failed to fetch all-time leaderboards');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const boards = data.leaderboards;
|
|
478
|
+
let output = `🏅 Legends of Champz - All-Time Leaderboards`;
|
|
479
|
+
if (category !== 'all') {
|
|
480
|
+
output += ` (${category.toUpperCase()})`;
|
|
481
|
+
}
|
|
482
|
+
output += `\n\n`;
|
|
483
|
+
|
|
484
|
+
// Define categories to display based on what's available
|
|
485
|
+
const allCategories = [
|
|
486
|
+
{ key: 'champz_earned', title: '💰 Most CHAMPZ Earned', format: (v) => `${(v / 1000000).toFixed(2)}M` },
|
|
487
|
+
{ key: 'usdc_earned', title: '💵 Most USDC Earned', format: (v) => `$${v.toFixed(2)}` },
|
|
488
|
+
{ key: 'champz_spent', title: '🔥 Most CHAMPZ Spent', format: (v) => `${(v / 1000000).toFixed(2)}M` },
|
|
489
|
+
{ key: 'total_wins', title: '⚔️ Most Total Wins', format: (v) => v.toLocaleString() },
|
|
490
|
+
{ key: 'win_rate', title: '🎯 Highest Win Rate (100+ battles)', format: (v) => `${v.toFixed(1)}%` },
|
|
491
|
+
{ key: 'longest_streak', title: '🔥 Longest Win Streak', format: (v) => `${v} wins` },
|
|
492
|
+
{ key: 'guardian_wins', title: '👑 Most Guardian (Throne) Wins', format: (v) => v },
|
|
493
|
+
{ key: 'ec_best_score', title: '⚡ Best EC Score', format: (v) => v },
|
|
494
|
+
{ key: 'ec_total_rounds', title: '⚡ Most EC Rounds Completed', format: (v) => v.toLocaleString() },
|
|
495
|
+
{ key: 'ec_games_played', title: '⚡ Most EC Games Played', format: (v) => v },
|
|
496
|
+
];
|
|
497
|
+
|
|
498
|
+
allCategories.forEach(cat => {
|
|
499
|
+
const board = boards[cat.key];
|
|
500
|
+
if (board && board.length > 0) {
|
|
501
|
+
output += `${cat.title}\n`;
|
|
502
|
+
board.slice(0, 3).forEach((player, i) => {
|
|
503
|
+
const name = player.display_name || `${player.wallet.slice(0, 6)}...`;
|
|
504
|
+
const value = cat.format(player.value);
|
|
505
|
+
output += ` ${i + 1}. ${name} - ${value}`;
|
|
506
|
+
if (player.battles) {
|
|
507
|
+
output += ` (${player.wins}/${player.battles})`;
|
|
508
|
+
}
|
|
509
|
+
output += `\n`;
|
|
510
|
+
});
|
|
511
|
+
output += `\n`;
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
content: [
|
|
517
|
+
{
|
|
518
|
+
type: 'text',
|
|
519
|
+
text: output,
|
|
520
|
+
},
|
|
521
|
+
],
|
|
522
|
+
};
|
|
523
|
+
} catch (error) {
|
|
524
|
+
return {
|
|
525
|
+
content: [
|
|
526
|
+
{
|
|
527
|
+
type: 'text',
|
|
528
|
+
text: `Error fetching all-time leaderboards: ${error.message}`,
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
259
534
|
default:
|
|
260
535
|
throw new Error(`Unknown tool: ${name}`);
|
|
261
536
|
}
|
package/package.json
CHANGED