@champz-llc/legends-mcp-server 1.4.0 ā 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +518 -126
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -51,10 +51,14 @@ const SIGNATURE = process.env.SIGNATURE;
|
|
|
51
51
|
const SIGNED_AT = process.env.SIGNED_AT;
|
|
52
52
|
const hasWalletAuth = WALLET && SIGNATURE && SIGNED_AT;
|
|
53
53
|
|
|
54
|
-
//
|
|
54
|
+
// ============================================================
|
|
55
|
+
// LEGACY: Hardcoded rewards data for BuildOnBase contest demo
|
|
56
|
+
// NOTE: This is no longer used! Real claims now fetched from API
|
|
57
|
+
// with mode=claims parameter. Kept for reference only.
|
|
58
|
+
// ============================================================
|
|
55
59
|
const DEMO_WALLET = '0xfbc159e35f56580d5d297af18a8c19f83d66088a';
|
|
56
60
|
|
|
57
|
-
const
|
|
61
|
+
const REWARDS_DATA_LEGACY = {
|
|
58
62
|
wallet: DEMO_WALLET,
|
|
59
63
|
champz_claims: [
|
|
60
64
|
{
|
|
@@ -155,7 +159,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
155
159
|
},
|
|
156
160
|
{
|
|
157
161
|
name: 'check_legends_rewards',
|
|
158
|
-
description: 'Check claimable rewards in Legends of Champz
|
|
162
|
+
description: 'Check YOUR pending claimable rewards in Legends of Champz. Returns CHAMPZ tokens and USDC claims with amounts and expiration dates. Requires wallet authentication.',
|
|
159
163
|
inputSchema: {
|
|
160
164
|
type: 'object',
|
|
161
165
|
properties: {},
|
|
@@ -164,7 +168,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
164
168
|
},
|
|
165
169
|
{
|
|
166
170
|
name: 'get_champz_claim_data',
|
|
167
|
-
description: 'Get complete contract call data for claiming CHAMPZ
|
|
171
|
+
description: 'Get complete contract call data for claiming YOUR CHAMPZ token rewards. Returns contract address, ABI, function parameters, and signature ready for Base MCP execution. Requires wallet authentication.',
|
|
168
172
|
inputSchema: {
|
|
169
173
|
type: 'object',
|
|
170
174
|
properties: {},
|
|
@@ -173,7 +177,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
173
177
|
},
|
|
174
178
|
{
|
|
175
179
|
name: 'get_usdc_claim_data',
|
|
176
|
-
description: 'Get complete contract call data for claiming USDC rewards
|
|
180
|
+
description: 'Get complete contract call data for claiming YOUR USDC rewards. Returns contract address, ABI, function parameters, and signature ready for Base MCP execution. Requires wallet authentication.',
|
|
177
181
|
inputSchema: {
|
|
178
182
|
type: 'object',
|
|
179
183
|
properties: {},
|
|
@@ -351,54 +355,154 @@ Last updated: ${new Date(stats.cached_at * 1000).toLocaleString()}`;
|
|
|
351
355
|
}
|
|
352
356
|
|
|
353
357
|
case 'check_legends_rewards':
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
{
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
if (!hasWalletAuth) {
|
|
359
|
+
return {
|
|
360
|
+
content: [{ type: 'text', text: 'Authentication required. Visit https://legends.champz.world/mcp-setup' }],
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
// Fetch pending claims
|
|
366
|
+
const url = `https://api.champz.world/game/spore-trainer/player-data?wallet=${encodeURIComponent(WALLET)}&signature=${encodeURIComponent(SIGNATURE)}×tamp=${encodeURIComponent(SIGNED_AT)}&mode=claims`;
|
|
367
|
+
const response = await fetch(url);
|
|
368
|
+
const data = await response.json();
|
|
369
|
+
|
|
370
|
+
if (!data.success) {
|
|
371
|
+
throw new Error('Failed to fetch claims data');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (data.champz_claims.length === 0 && data.usdc_claims.length === 0) {
|
|
375
|
+
return {
|
|
376
|
+
content: [
|
|
377
|
+
{
|
|
378
|
+
type: 'text',
|
|
379
|
+
text: 'š Legends of Champz - Claimable Rewards\n\nNo pending claims available at the moment.\n\nKeep battling and holding thrones to earn rewards! āļøš',
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
let output = 'š Legends of Champz - Claimable Rewards\n\n';
|
|
386
|
+
output += `${data.message}\n\n`;
|
|
387
|
+
output += `š° **Total Claimable:**\n`;
|
|
388
|
+
if (data.total_champz !== '0.00 CHAMPZ') output += ` š ${data.total_champz}\n`;
|
|
389
|
+
if (data.total_usdc !== '0.00 USDC') output += ` šµ ${data.total_usdc}\n`;
|
|
390
|
+
output += `\nš Ready to execute on Base L2 (Chain ID: ${data.chain_id})\n`;
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
content: [{ type: 'text', text: output }],
|
|
394
|
+
};
|
|
395
|
+
} catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
content: [{ type: 'text', text: `Error fetching claims: ${error.message}` }],
|
|
398
|
+
};
|
|
399
|
+
}
|
|
362
400
|
|
|
363
401
|
case 'get_champz_claim_data':
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
{
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
402
|
+
if (!hasWalletAuth) {
|
|
403
|
+
return {
|
|
404
|
+
content: [{ type: 'text', text: 'Authentication required. Visit https://legends.champz.world/mcp-setup' }],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
// Fetch pending claims
|
|
410
|
+
const url = `https://api.champz.world/game/spore-trainer/player-data?wallet=${encodeURIComponent(WALLET)}&signature=${encodeURIComponent(SIGNATURE)}×tamp=${encodeURIComponent(SIGNED_AT)}&mode=claims`;
|
|
411
|
+
const response = await fetch(url);
|
|
412
|
+
const data = await response.json();
|
|
413
|
+
|
|
414
|
+
if (!data.success) {
|
|
415
|
+
throw new Error('Failed to fetch claims data');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (data.champz_claims.length === 0) {
|
|
419
|
+
return {
|
|
420
|
+
content: [{ type: 'text', text: 'No pending CHAMPZ claims available' }],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Return all CHAMPZ claims with contract data
|
|
425
|
+
const claimsOutput = data.champz_claims.map(claim => ({
|
|
426
|
+
claim_id: claim.claim_id,
|
|
427
|
+
claim_type: claim.claim_type_name,
|
|
428
|
+
amount: claim.amount_human,
|
|
429
|
+
contract_address: claim.contract,
|
|
430
|
+
chain: 'Base (8453)',
|
|
431
|
+
expires_at: claim.expires_at,
|
|
432
|
+
contract_call: {
|
|
433
|
+
function: claim.function_name,
|
|
434
|
+
parameters: claim.parameters,
|
|
435
|
+
abi_function: claim.abi_function,
|
|
436
|
+
abi: CHAMPZ_REWARDS_ABI
|
|
437
|
+
}
|
|
438
|
+
}));
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
content: [
|
|
442
|
+
{
|
|
443
|
+
type: 'text',
|
|
444
|
+
text: JSON.stringify(claimsOutput, null, 2),
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
};
|
|
448
|
+
} catch (error) {
|
|
449
|
+
return {
|
|
450
|
+
content: [{ type: 'text', text: `Error fetching CHAMPZ claims: ${error.message}` }],
|
|
451
|
+
};
|
|
452
|
+
}
|
|
382
453
|
|
|
383
454
|
case 'get_usdc_claim_data':
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
{
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
455
|
+
if (!hasWalletAuth) {
|
|
456
|
+
return {
|
|
457
|
+
content: [{ type: 'text', text: 'Authentication required. Visit https://legends.champz.world/mcp-setup' }],
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
// Fetch pending claims
|
|
463
|
+
const url = `https://api.champz.world/game/spore-trainer/player-data?wallet=${encodeURIComponent(WALLET)}&signature=${encodeURIComponent(SIGNATURE)}×tamp=${encodeURIComponent(SIGNED_AT)}&mode=claims`;
|
|
464
|
+
const response = await fetch(url);
|
|
465
|
+
const data = await response.json();
|
|
466
|
+
|
|
467
|
+
if (!data.success) {
|
|
468
|
+
throw new Error('Failed to fetch claims data');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (data.usdc_claims.length === 0) {
|
|
472
|
+
return {
|
|
473
|
+
content: [{ type: 'text', text: 'No pending USDC claims available' }],
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Return all USDC claims with contract data
|
|
478
|
+
const claimsOutput = data.usdc_claims.map(claim => ({
|
|
479
|
+
claim_id: claim.claim_id,
|
|
480
|
+
claim_type: claim.claim_type_name,
|
|
481
|
+
amount: claim.amount_human,
|
|
482
|
+
contract_address: claim.contract,
|
|
483
|
+
chain: 'Base (8453)',
|
|
484
|
+
expires_at: claim.expires_at,
|
|
485
|
+
contract_call: {
|
|
486
|
+
function: claim.function_name,
|
|
487
|
+
parameters: claim.parameters,
|
|
488
|
+
abi_function: claim.abi_function,
|
|
489
|
+
abi: USDC_REWARDS_ABI
|
|
490
|
+
}
|
|
491
|
+
}));
|
|
492
|
+
|
|
493
|
+
return {
|
|
494
|
+
content: [
|
|
495
|
+
{
|
|
496
|
+
type: 'text',
|
|
497
|
+
text: JSON.stringify(claimsOutput, null, 2),
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
};
|
|
501
|
+
} catch (error) {
|
|
502
|
+
return {
|
|
503
|
+
content: [{ type: 'text', text: `Error fetching USDC claims: ${error.message}` }],
|
|
504
|
+
};
|
|
505
|
+
}
|
|
402
506
|
|
|
403
507
|
case 'legends_leaderboard_current':
|
|
404
508
|
try {
|
|
@@ -831,13 +935,17 @@ You can still ask about:
|
|
|
831
935
|
};
|
|
832
936
|
}
|
|
833
937
|
|
|
834
|
-
//
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
938
|
+
// Fetch image
|
|
939
|
+
const imageUrl = `https://img.champz.world${legend.image_path}`;
|
|
940
|
+
const base64Data = await fetchImageAsBase64(imageUrl);
|
|
941
|
+
|
|
942
|
+
// Build HTML card with embedded image
|
|
943
|
+
const rarityColors = {
|
|
944
|
+
unique: '#FFD700',
|
|
945
|
+
legendary: '#FF6B35',
|
|
946
|
+
epic: '#9D4EDD',
|
|
947
|
+
rare: '#4EA8DE',
|
|
948
|
+
common: '#CCCCCC'
|
|
841
949
|
};
|
|
842
950
|
const elementEmojis = {
|
|
843
951
|
fire: 'š„',
|
|
@@ -848,46 +956,193 @@ You can still ask about:
|
|
|
848
956
|
dark: 'š'
|
|
849
957
|
};
|
|
850
958
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
959
|
+
const elementIcons = legend.elements.map(e => `${elementEmojis[e] || 'ā'} ${e.charAt(0).toUpperCase() + e.slice(1)}`).join(' ');
|
|
960
|
+
const rarityColor = rarityColors[legend.rarity] || '#9D4EDD';
|
|
961
|
+
const rarityBadge = legend.rarity.toUpperCase();
|
|
962
|
+
|
|
963
|
+
const html = `<!DOCTYPE html>
|
|
964
|
+
<html>
|
|
965
|
+
<head>
|
|
966
|
+
<meta charset="UTF-8">
|
|
967
|
+
<style>
|
|
968
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
969
|
+
body {
|
|
970
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
971
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
972
|
+
display: flex;
|
|
973
|
+
justify-content: center;
|
|
974
|
+
align-items: center;
|
|
975
|
+
min-height: 100vh;
|
|
976
|
+
padding: 20px;
|
|
977
|
+
}
|
|
978
|
+
.card {
|
|
979
|
+
background: linear-gradient(145deg, #2a2a3e 0%, #1f1f2e 100%);
|
|
980
|
+
border-radius: 16px;
|
|
981
|
+
padding: 24px;
|
|
982
|
+
max-width: 400px;
|
|
983
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
984
|
+
border: 2px solid ${rarityColor};
|
|
985
|
+
position: relative;
|
|
986
|
+
overflow: hidden;
|
|
987
|
+
}
|
|
988
|
+
.card::before {
|
|
989
|
+
content: '';
|
|
990
|
+
position: absolute;
|
|
991
|
+
top: 0;
|
|
992
|
+
left: 0;
|
|
993
|
+
right: 0;
|
|
994
|
+
height: 4px;
|
|
995
|
+
background: linear-gradient(90deg, ${rarityColor}, transparent);
|
|
996
|
+
}
|
|
997
|
+
.header {
|
|
998
|
+
text-align: center;
|
|
999
|
+
margin-bottom: 16px;
|
|
1000
|
+
border-bottom: 2px solid rgba(255,255,255,0.1);
|
|
1001
|
+
padding-bottom: 12px;
|
|
1002
|
+
}
|
|
1003
|
+
.rarity-badge {
|
|
1004
|
+
background: ${rarityColor};
|
|
1005
|
+
color: #000;
|
|
1006
|
+
padding: 4px 12px;
|
|
1007
|
+
border-radius: 12px;
|
|
1008
|
+
font-weight: bold;
|
|
1009
|
+
font-size: 11px;
|
|
1010
|
+
display: inline-block;
|
|
1011
|
+
margin-bottom: 8px;
|
|
1012
|
+
text-transform: uppercase;
|
|
1013
|
+
letter-spacing: 1px;
|
|
1014
|
+
}
|
|
1015
|
+
.legend-id {
|
|
1016
|
+
color: #fff;
|
|
1017
|
+
font-size: 20px;
|
|
1018
|
+
font-weight: bold;
|
|
1019
|
+
margin-bottom: 4px;
|
|
1020
|
+
}
|
|
1021
|
+
.legend-name {
|
|
1022
|
+
color: ${rarityColor};
|
|
1023
|
+
font-size: 18px;
|
|
1024
|
+
font-weight: bold;
|
|
1025
|
+
}
|
|
1026
|
+
.image-container {
|
|
1027
|
+
text-align: center;
|
|
1028
|
+
margin: 16px 0;
|
|
1029
|
+
background: rgba(0,0,0,0.3);
|
|
1030
|
+
border-radius: 12px;
|
|
1031
|
+
padding: 12px;
|
|
1032
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
1033
|
+
}
|
|
1034
|
+
.legend-image {
|
|
1035
|
+
max-width: 200px;
|
|
1036
|
+
border-radius: 8px;
|
|
1037
|
+
display: block;
|
|
1038
|
+
margin: 0 auto;
|
|
1039
|
+
}
|
|
1040
|
+
.elements {
|
|
1041
|
+
text-align: center;
|
|
1042
|
+
font-size: 14px;
|
|
1043
|
+
color: #fff;
|
|
1044
|
+
margin: 12px 0;
|
|
1045
|
+
padding: 8px;
|
|
1046
|
+
background: rgba(255,255,255,0.05);
|
|
1047
|
+
border-radius: 8px;
|
|
1048
|
+
}
|
|
1049
|
+
.stats {
|
|
1050
|
+
display: grid;
|
|
1051
|
+
grid-template-columns: 1fr 1fr;
|
|
1052
|
+
gap: 12px;
|
|
1053
|
+
margin: 16px 0;
|
|
1054
|
+
}
|
|
1055
|
+
.stat {
|
|
1056
|
+
background: rgba(255,255,255,0.05);
|
|
1057
|
+
padding: 12px;
|
|
1058
|
+
border-radius: 8px;
|
|
1059
|
+
border-left: 3px solid ${rarityColor};
|
|
1060
|
+
}
|
|
1061
|
+
.stat-label {
|
|
1062
|
+
color: #aaa;
|
|
1063
|
+
font-size: 12px;
|
|
1064
|
+
margin-bottom: 4px;
|
|
1065
|
+
}
|
|
1066
|
+
.stat-value {
|
|
1067
|
+
color: #fff;
|
|
1068
|
+
font-size: 18px;
|
|
1069
|
+
font-weight: bold;
|
|
1070
|
+
}
|
|
1071
|
+
.power {
|
|
1072
|
+
grid-column: 1 / -1;
|
|
1073
|
+
text-align: center;
|
|
1074
|
+
background: linear-gradient(135deg, rgba(157, 78, 221, 0.2), rgba(77, 144, 254, 0.2));
|
|
1075
|
+
border: 2px solid ${rarityColor};
|
|
1076
|
+
}
|
|
1077
|
+
.power .stat-value {
|
|
1078
|
+
font-size: 24px;
|
|
1079
|
+
color: ${rarityColor};
|
|
1080
|
+
}
|
|
1081
|
+
.footer {
|
|
1082
|
+
margin-top: 16px;
|
|
1083
|
+
padding-top: 12px;
|
|
1084
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
1085
|
+
text-align: center;
|
|
1086
|
+
color: #888;
|
|
1087
|
+
font-size: 12px;
|
|
1088
|
+
}
|
|
1089
|
+
.saved-badge {
|
|
1090
|
+
display: inline-block;
|
|
1091
|
+
background: linear-gradient(135deg, #FFD700, #FFA500);
|
|
1092
|
+
color: #000;
|
|
1093
|
+
padding: 6px 12px;
|
|
1094
|
+
border-radius: 8px;
|
|
1095
|
+
font-weight: bold;
|
|
1096
|
+
margin-top: 8px;
|
|
1097
|
+
}
|
|
1098
|
+
</style>
|
|
1099
|
+
</head>
|
|
1100
|
+
<body>
|
|
1101
|
+
<div class="card">
|
|
1102
|
+
<div class="header">
|
|
1103
|
+
<div class="rarity-badge">${rarityBadge}</div>
|
|
1104
|
+
<div class="legend-id">Legend #${legend.legend_id}</div>
|
|
1105
|
+
<div class="legend-name">š ${legend.name}</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
${base64Data ? `
|
|
1108
|
+
<div class="image-container">
|
|
1109
|
+
<img src="data:image/jpeg;base64,${base64Data}" alt="${legend.name}" class="legend-image">
|
|
1110
|
+
</div>` : ''}
|
|
1111
|
+
<div class="elements">${elementIcons}</div>
|
|
1112
|
+
<div class="stats">
|
|
1113
|
+
<div class="stat power">
|
|
1114
|
+
<div class="stat-label">ā” TOTAL POWER</div>
|
|
1115
|
+
<div class="stat-value">${legend.total_power}</div>
|
|
1116
|
+
</div>
|
|
1117
|
+
<div class="stat">
|
|
1118
|
+
<div class="stat-label">āļø ATTACK</div>
|
|
1119
|
+
<div class="stat-value">${legend.attack}</div>
|
|
1120
|
+
</div>
|
|
1121
|
+
<div class="stat">
|
|
1122
|
+
<div class="stat-label">š”ļø DEFENSE</div>
|
|
1123
|
+
<div class="stat-value">${legend.defense}</div>
|
|
1124
|
+
</div>
|
|
1125
|
+
<div class="stat">
|
|
1126
|
+
<div class="stat-label">šØ SPEED</div>
|
|
1127
|
+
<div class="stat-value">${legend.speed}</div>
|
|
1128
|
+
</div>
|
|
1129
|
+
</div>
|
|
1130
|
+
<div class="footer">
|
|
1131
|
+
š
Rolled: ${new Date(legend.rolled_at).toLocaleDateString()}
|
|
1132
|
+
${legend.is_saved ? '<div class="saved-badge">ā SAVED TRAINER</div>' : ''}
|
|
1133
|
+
</div>
|
|
1134
|
+
</div>
|
|
1135
|
+
</body>
|
|
1136
|
+
</html>`;
|
|
889
1137
|
|
|
890
|
-
return {
|
|
1138
|
+
return {
|
|
1139
|
+
content: [
|
|
1140
|
+
{
|
|
1141
|
+
type: 'text',
|
|
1142
|
+
text: html,
|
|
1143
|
+
},
|
|
1144
|
+
],
|
|
1145
|
+
};
|
|
891
1146
|
} catch (error) {
|
|
892
1147
|
return {
|
|
893
1148
|
content: [
|
|
@@ -935,43 +1190,180 @@ You can still ask about:
|
|
|
935
1190
|
};
|
|
936
1191
|
}
|
|
937
1192
|
|
|
938
|
-
// Build card-like output with gaming vibes
|
|
939
|
-
const rarityEmojis = {
|
|
940
|
-
legendary: 'š',
|
|
941
|
-
epic: 'š',
|
|
942
|
-
rare: 'š',
|
|
943
|
-
common: 'š¤'
|
|
944
|
-
};
|
|
945
|
-
|
|
946
|
-
let output = `āāāāāāāāāāāāāāāāāāāāāāāāāā\n`;
|
|
947
|
-
output += `ā ${rarityEmojis[throne.rarity] || 'š'} ${throne.rarity.toUpperCase()} THRONE #${throne.throne_id} ā\n`;
|
|
948
|
-
output += `āāāāāāāāāāāāāāāāāāāāāāāāāā\n\n`;
|
|
949
|
-
|
|
950
|
-
output += `š **${throne.name}**\n\n`;
|
|
951
|
-
output += `š® **Earned in Cycle:** ${throne.cycle_id}\n`;
|
|
952
|
-
output += `š
**Date Earned:** ${new Date(throne.earned_at).toLocaleDateString()}\n\n`;
|
|
953
|
-
output += `š You're a champion! This throne proves you held the Guardian position and won the cycle!\n`;
|
|
954
|
-
|
|
955
1193
|
// Fetch and convert image to base64
|
|
956
1194
|
const imageUrl = `https://img.champz.world${throne.image_path}`;
|
|
957
1195
|
const base64Data = await fetchImageAsBase64(imageUrl);
|
|
958
1196
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1197
|
+
// Build HTML card with embedded image
|
|
1198
|
+
const rarityColors = {
|
|
1199
|
+
legendary: '#FFD700',
|
|
1200
|
+
epic: '#9D4EDD',
|
|
1201
|
+
rare: '#4EA8DE',
|
|
1202
|
+
common: '#CCCCCC'
|
|
1203
|
+
};
|
|
965
1204
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1205
|
+
const rarityColor = rarityColors[throne.rarity] || '#FFD700';
|
|
1206
|
+
const rarityBadge = throne.rarity.toUpperCase();
|
|
1207
|
+
|
|
1208
|
+
const html = `<!DOCTYPE html>
|
|
1209
|
+
<html>
|
|
1210
|
+
<head>
|
|
1211
|
+
<meta charset="UTF-8">
|
|
1212
|
+
<style>
|
|
1213
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
1214
|
+
body {
|
|
1215
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
1216
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
1217
|
+
display: flex;
|
|
1218
|
+
justify-content: center;
|
|
1219
|
+
align-items: center;
|
|
1220
|
+
min-height: 100vh;
|
|
1221
|
+
padding: 20px;
|
|
1222
|
+
}
|
|
1223
|
+
.card {
|
|
1224
|
+
background: linear-gradient(145deg, #2a2a3e 0%, #1f1f2e 100%);
|
|
1225
|
+
border-radius: 16px;
|
|
1226
|
+
padding: 24px;
|
|
1227
|
+
max-width: 400px;
|
|
1228
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
1229
|
+
border: 2px solid ${rarityColor};
|
|
1230
|
+
position: relative;
|
|
1231
|
+
overflow: hidden;
|
|
1232
|
+
}
|
|
1233
|
+
.card::before {
|
|
1234
|
+
content: '';
|
|
1235
|
+
position: absolute;
|
|
1236
|
+
top: 0;
|
|
1237
|
+
left: 0;
|
|
1238
|
+
right: 0;
|
|
1239
|
+
height: 4px;
|
|
1240
|
+
background: linear-gradient(90deg, ${rarityColor}, transparent);
|
|
1241
|
+
}
|
|
1242
|
+
.header {
|
|
1243
|
+
text-align: center;
|
|
1244
|
+
margin-bottom: 16px;
|
|
1245
|
+
border-bottom: 2px solid rgba(255,255,255,0.1);
|
|
1246
|
+
padding-bottom: 12px;
|
|
1247
|
+
}
|
|
1248
|
+
.rarity-badge {
|
|
1249
|
+
background: ${rarityColor};
|
|
1250
|
+
color: #000;
|
|
1251
|
+
padding: 4px 12px;
|
|
1252
|
+
border-radius: 12px;
|
|
1253
|
+
font-weight: bold;
|
|
1254
|
+
font-size: 11px;
|
|
1255
|
+
display: inline-block;
|
|
1256
|
+
margin-bottom: 8px;
|
|
1257
|
+
text-transform: uppercase;
|
|
1258
|
+
letter-spacing: 1px;
|
|
1259
|
+
}
|
|
1260
|
+
.throne-id {
|
|
1261
|
+
color: #fff;
|
|
1262
|
+
font-size: 20px;
|
|
1263
|
+
font-weight: bold;
|
|
1264
|
+
margin-bottom: 4px;
|
|
1265
|
+
}
|
|
1266
|
+
.throne-name {
|
|
1267
|
+
color: ${rarityColor};
|
|
1268
|
+
font-size: 18px;
|
|
1269
|
+
font-weight: bold;
|
|
1270
|
+
}
|
|
1271
|
+
.image-container {
|
|
1272
|
+
text-align: center;
|
|
1273
|
+
margin: 16px 0;
|
|
1274
|
+
background: rgba(0,0,0,0.3);
|
|
1275
|
+
border-radius: 12px;
|
|
1276
|
+
padding: 12px;
|
|
1277
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
1278
|
+
}
|
|
1279
|
+
.throne-image {
|
|
1280
|
+
max-width: 200px;
|
|
1281
|
+
border-radius: 8px;
|
|
1282
|
+
display: block;
|
|
1283
|
+
margin: 0 auto;
|
|
1284
|
+
}
|
|
1285
|
+
.info {
|
|
1286
|
+
background: rgba(255,255,255,0.05);
|
|
1287
|
+
padding: 16px;
|
|
1288
|
+
border-radius: 8px;
|
|
1289
|
+
border-left: 3px solid ${rarityColor};
|
|
1290
|
+
margin: 16px 0;
|
|
1291
|
+
}
|
|
1292
|
+
.info-row {
|
|
1293
|
+
display: flex;
|
|
1294
|
+
justify-content: space-between;
|
|
1295
|
+
color: #fff;
|
|
1296
|
+
padding: 8px 0;
|
|
1297
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
1298
|
+
}
|
|
1299
|
+
.info-row:last-child {
|
|
1300
|
+
border-bottom: none;
|
|
1301
|
+
}
|
|
1302
|
+
.info-label {
|
|
1303
|
+
color: #aaa;
|
|
1304
|
+
font-size: 14px;
|
|
1305
|
+
}
|
|
1306
|
+
.info-value {
|
|
1307
|
+
font-weight: bold;
|
|
1308
|
+
font-size: 14px;
|
|
1309
|
+
}
|
|
1310
|
+
.trophy-message {
|
|
1311
|
+
text-align: center;
|
|
1312
|
+
background: linear-gradient(135deg, rgba(255, 215, 0, 0.2), rgba(255, 165, 0, 0.2));
|
|
1313
|
+
border: 2px solid ${rarityColor};
|
|
1314
|
+
padding: 16px;
|
|
1315
|
+
border-radius: 8px;
|
|
1316
|
+
margin-top: 16px;
|
|
1317
|
+
}
|
|
1318
|
+
.trophy-message .emoji {
|
|
1319
|
+
font-size: 32px;
|
|
1320
|
+
display: block;
|
|
1321
|
+
margin-bottom: 8px;
|
|
1322
|
+
}
|
|
1323
|
+
.trophy-message .text {
|
|
1324
|
+
color: #fff;
|
|
1325
|
+
font-weight: bold;
|
|
1326
|
+
font-size: 14px;
|
|
1327
|
+
}
|
|
1328
|
+
</style>
|
|
1329
|
+
</head>
|
|
1330
|
+
<body>
|
|
1331
|
+
<div class="card">
|
|
1332
|
+
<div class="header">
|
|
1333
|
+
<div class="rarity-badge">${rarityBadge} THRONE</div>
|
|
1334
|
+
<div class="throne-id">Throne #${throne.throne_id}</div>
|
|
1335
|
+
<div class="throne-name">š ${throne.name}</div>
|
|
1336
|
+
</div>
|
|
1337
|
+
${base64Data ? `
|
|
1338
|
+
<div class="image-container">
|
|
1339
|
+
<img src="data:image/jpeg;base64,${base64Data}" alt="${throne.name}" class="throne-image">
|
|
1340
|
+
</div>` : ''}
|
|
1341
|
+
<div class="info">
|
|
1342
|
+
<div class="info-row">
|
|
1343
|
+
<span class="info-label">š® Cycle</span>
|
|
1344
|
+
<span class="info-value">#${throne.cycle_id}</span>
|
|
1345
|
+
</div>
|
|
1346
|
+
<div class="info-row">
|
|
1347
|
+
<span class="info-label">š
Date Earned</span>
|
|
1348
|
+
<span class="info-value">${new Date(throne.earned_at).toLocaleDateString()}</span>
|
|
1349
|
+
</div>
|
|
1350
|
+
</div>
|
|
1351
|
+
<div class="trophy-message">
|
|
1352
|
+
<span class="emoji">š</span>
|
|
1353
|
+
<span class="text">CHAMPION! You held the Guardian position and won Cycle ${throne.cycle_id}!</span>
|
|
1354
|
+
</div>
|
|
1355
|
+
</div>
|
|
1356
|
+
</body>
|
|
1357
|
+
</html>`;
|
|
973
1358
|
|
|
974
|
-
return {
|
|
1359
|
+
return {
|
|
1360
|
+
content: [
|
|
1361
|
+
{
|
|
1362
|
+
type: 'text',
|
|
1363
|
+
text: html,
|
|
1364
|
+
},
|
|
1365
|
+
],
|
|
1366
|
+
};
|
|
975
1367
|
} catch (error) {
|
|
976
1368
|
return {
|
|
977
1369
|
content: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@champz-llc/legends-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "MCP server for Legends of Champz - Query game stats, access personal data with signature auth, and claim rewards through Claude Desktop",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|