@champz-llc/legends-mcp-server 1.3.6 → 1.4.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.
Files changed (2) hide show
  1. package/index.js +116 -52
  2. package/package.json +3 -2
package/index.js CHANGED
@@ -7,8 +7,9 @@ import {
7
7
  ListToolsRequestSchema,
8
8
  } from '@modelcontextprotocol/sdk/types.js';
9
9
  import fetch from 'node-fetch';
10
+ import sharp from 'sharp';
10
11
 
11
- // Helper function to fetch image and convert to base64
12
+ // Helper function to fetch image, resize, and convert to base64
12
13
  async function fetchImageAsBase64(imageUrl) {
13
14
  try {
14
15
  console.error(`[MCP] Fetching image: ${imageUrl}`);
@@ -21,12 +22,25 @@ async function fetchImageAsBase64(imageUrl) {
21
22
  const contentType = response.headers.get('content-type');
22
23
  console.error(`[MCP] Image content-type: ${contentType}`);
23
24
 
24
- const buffer = await response.buffer();
25
- const base64 = buffer.toString('base64');
26
- console.error(`[MCP] Image converted to base64, size: ${base64.length} chars`);
25
+ // Fetch image as buffer
26
+ const arrayBuffer = await response.arrayBuffer();
27
+ const originalBuffer = Buffer.from(arrayBuffer);
28
+ console.error(`[MCP] Original image size: ${Math.round(originalBuffer.length / 1024)}KB`);
29
+
30
+ // Resize image to max 200x200 (perfect for chat) and convert to JPEG for smaller size
31
+ const resizedBuffer = await sharp(originalBuffer)
32
+ .resize(200, 200, {
33
+ fit: 'inside',
34
+ withoutEnlargement: true
35
+ })
36
+ .jpeg({ quality: 80, mozjpeg: true }) // JPEG is much smaller than PNG
37
+ .toBuffer();
38
+
39
+ const base64 = resizedBuffer.toString('base64');
40
+ console.error(`[MCP] Resized image size: ${Math.round(resizedBuffer.length / 1024)}KB, base64: ${Math.round(base64.length / 1024)}KB`);
27
41
  return base64;
28
42
  } catch (error) {
29
- console.error(`[MCP] Error fetching image ${imageUrl}:`, error.message);
43
+ console.error(`[MCP] Error processing image ${imageUrl}:`, error.message);
30
44
  return null;
31
45
  }
32
46
  }
@@ -645,39 +659,50 @@ You can still ask about:
645
659
  const stats = data.statistics;
646
660
  const claims = data.claims;
647
661
 
648
- let output = `Legends of Champz - Your Statistics\n\n`;
649
- output += `Player: ${displayName}\n`;
650
- output += `Wallet: ${data.wallet}\n`;
662
+ let output = `🍄 **LEGENDS OF CHAMPZ** - Player Stats 🍄\n\n`;
663
+ output += `👤 **Player:** ${displayName}\n`;
651
664
  if (data.basename) {
652
- output += `Basename: ${data.basename}\n`;
665
+ output += `🎯 **Basename:** ${data.basename}\n`;
653
666
  }
654
- output += `Member since: ${new Date(stats.member_since).toLocaleDateString()}\n\n`;
655
-
656
- output += `📦 Packs & Legends:\n`;
657
- output += ` • Total packs opened: ${stats.total_packs_opened}\n`;
658
- output += ` • CHAMPZ spent on packs: ${stats.champz_spent_on_packs.toLocaleString()}\n`;
659
- output += ` Legends owned: ${stats.legends_owned}\n`;
660
- output += ` Saved trainer slots: ${stats.saved_trainer_slots}\n\n`;
661
-
662
- output += `⚔️ Battle Statistics:\n`;
663
- output += ` • Total battles: ${stats.total_battles}\n`;
664
- output += ` • Wins: ${stats.battles_won} (${(stats.win_rate * 100).toFixed(1)}% win rate)\n`;
665
- output += ` Losses: ${stats.battles_lost}\n`;
666
- output += ` • Current streak: ${stats.current_win_streak}\n`;
667
- output += ` Best streak: ${stats.best_win_streak}\n\n`;
668
-
669
- output += `👑 Thrones & Guardian:\n`;
670
- output += ` Thrones owned: ${stats.thrones_owned}\n`;
671
- output += ` Times held guardian: ${stats.times_held_guardian}\n`;
672
- output += ` CHAMPZ spent on guardian: ${stats.champz_spent_on_guardian.toLocaleString()}\n\n`;
673
-
674
- output += `💰 Claims History:\n`;
675
- output += ` • Total USDC claimed: $${claims.total_usdc_claimed}\n`;
676
- output += ` • Total CHAMPZ claimed: ${claims.total_champz_claimed.toLocaleString()}\n`;
677
- output += ` • Battle USDC (type 6): ${claims.by_type['6'].count} claims, $${claims.by_type['6'].total_amount}\n`;
678
- output += ` Battle CHAMPZ (type 5): ${claims.by_type['5'].count} claims, ${claims.by_type['5'].total_amount.toLocaleString()} tokens\n`;
679
- output += ` Guardian USDC (type 19): ${claims.by_type['19'].count} claims, $${claims.by_type['19'].total_amount}\n`;
680
- output += ` Guardian CHAMPZ (type 18): ${claims.by_type['18'].count} claims, ${claims.by_type['18'].total_amount.toLocaleString()} tokens\n\n`;
667
+ output += `📅 **Member Since:** ${new Date(stats.member_since).toLocaleDateString()} - Let's go! 🎮\n\n`;
668
+
669
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
670
+ output += `📦 **PACKS & LEGENDS**\n`;
671
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
672
+ output += ` 🎲 Packs opened: **${stats.total_packs_opened}** ${stats.total_packs_opened > 50 ? '(Pack master! 🔥)' : ''}\n`;
673
+ output += ` 💎 CHAMPZ spent: **${stats.champz_spent_on_packs.toLocaleString()}** tokens\n`;
674
+ output += ` 🍄 Legends owned: **${stats.legends_owned}** ${stats.legends_owned > 30 ? '(Epic collection! ⭐)' : ''}\n`;
675
+ output += ` Trainer slots: **${stats.saved_trainer_slots}**\n\n`;
676
+
677
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
678
+ output += `⚔️ **BATTLE RECORD**\n`;
679
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
680
+ output += ` 🎯 Total battles: **${stats.total_battles}** fights!\n`;
681
+ const winRate = (stats.win_rate * 100).toFixed(1);
682
+ const winRateEmoji = winRate >= 70 ? '🔥🔥🔥' : winRate >= 60 ? '🔥🔥' : winRate >= 50 ? '🔥' : '💪';
683
+ output += ` 🏆 Wins: **${stats.battles_won}** (${winRate}% win rate ${winRateEmoji})\n`;
684
+ output += ` 💀 Losses: **${stats.battles_lost}**\n`;
685
+ output += ` Current streak: **${stats.current_win_streak}** ${stats.current_win_streak >= 5 ? '(ON FIRE! 🔥)' : ''}\n`;
686
+ output += ` 🌟 Best streak: **${stats.best_win_streak}** ${stats.best_win_streak >= 10 ? '(Legendary! 💎)' : ''}\n\n`;
687
+
688
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
689
+ output += `👑 **THRONES & GUARDIAN**\n`;
690
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
691
+ output += ` 🏆 Thrones owned: **${stats.thrones_owned}** ${stats.thrones_owned > 0 ? '(Champion! 👑)' : ''}\n`;
692
+ output += ` 🛡️ Times held guardian: **${stats.times_held_guardian}** ${stats.times_held_guardian > 5 ? '(Guardian master! ⚡)' : ''}\n`;
693
+ output += ` 💰 CHAMPZ spent: **${stats.champz_spent_on_guardian.toLocaleString()}** tokens\n\n`;
694
+
695
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
696
+ output += `💵 **REWARDS CLAIMED**\n`;
697
+ output += `━━━━━━━━━━━━━━━━━━━━━━\n`;
698
+ const totalUSDC = claims.total_usdc_claimed;
699
+ const totalCHAMPZ = claims.total_champz_claimed;
700
+ output += ` 💵 Total USDC: **$${totalUSDC}** ${totalUSDC > 50 ? '(Big earner! 💰)' : totalUSDC > 20 ? '(Nice! 🎯)' : ''}\n`;
701
+ output += ` 🍄 Total CHAMPZ: **${totalCHAMPZ.toLocaleString()}** tokens ${totalCHAMPZ > 10000 ? '(Whale alert! 🐋)' : ''}\n`;
702
+ if (claims.by_type['6'].count > 0 || claims.by_type['19'].count > 0) {
703
+ output += ` 🎉 You're earning rewards - keep battling! ⚔️\n`;
704
+ }
705
+ output += `\n`;
681
706
 
682
707
  // Build content array with text and images
683
708
  const content = [
@@ -806,17 +831,45 @@ You can still ask about:
806
831
  };
807
832
  }
808
833
 
809
- // Build output
810
- let output = `Legend #${legend.legend_id} - ${legend.name}\n\n`;
811
- output += `Rarity: ${legend.rarity.toUpperCase()}\n`;
812
- output += `Total Power: ${legend.total_power}\n`;
813
- output += `ATK: ${legend.attack} | DEF: ${legend.defense} | SPD: ${legend.speed}\n`;
814
- output += `Elements: ${legend.elements.join(', ')}\n`;
815
- output += `Rolled: ${new Date(legend.rolled_at).toLocaleDateString()}\n`;
816
- output += `Saved: ${legend.is_saved ? 'Yes ⭐' : 'No'}\n`;
834
+ // Build card-like output with gaming vibes
835
+ const rarityEmojis = {
836
+ unique: '💎',
837
+ legendary: '🌟',
838
+ epic: '🟣',
839
+ rare: '🔵',
840
+ common: '⚪'
841
+ };
842
+ const elementEmojis = {
843
+ fire: '🔥',
844
+ water: '💧',
845
+ wind: '🌪️',
846
+ earth: '🌍',
847
+ light: '✨',
848
+ dark: '🌑'
849
+ };
817
850
 
818
- // Fetch and convert image to base64
851
+ let output = `╔════════════════════════╗\n`;
852
+ output += `║ ${rarityEmojis[legend.rarity]} ${legend.rarity.toUpperCase()} LEGEND #${legend.legend_id} ║\n`;
853
+ output += `╚════════════════════════╝\n\n`;
854
+
855
+ output += `🍄 **${legend.name}**\n\n`;
856
+
857
+ // Elements with emojis
858
+ const elementIcons = legend.elements.map(e => `${elementEmojis[e] || '⭐'} ${e.charAt(0).toUpperCase() + e.slice(1)}`).join(' ');
859
+ output += `${elementIcons}\n\n`;
860
+
861
+ output += `⚡ **Total Power:** ${legend.total_power}\n`;
862
+ output += `⚔️ **ATK:** ${legend.attack}\n`;
863
+ output += `🛡️ **DEF:** ${legend.defense}\n`;
864
+ output += `💨 **SPD:** ${legend.speed}\n\n`;
865
+
866
+ output += `📅 Rolled: ${new Date(legend.rolled_at).toLocaleDateString()}\n`;
867
+ output += legend.is_saved ? `⭐ **Saved Trainer** - This legend is in your collection!\n` : `💡 Not saved yet - save this legend to keep it forever!\n`;
868
+
869
+ // Fetch image
819
870
  const imageUrl = `https://img.champz.world${legend.image_path}`;
871
+
872
+ // Fetch and convert image to base64
820
873
  const base64Data = await fetchImageAsBase64(imageUrl);
821
874
 
822
875
  const content = [
@@ -830,7 +883,7 @@ You can still ask about:
830
883
  content.push({
831
884
  type: 'image',
832
885
  data: base64Data,
833
- mimeType: 'image/png',
886
+ mimeType: 'image/jpeg',
834
887
  });
835
888
  }
836
889
 
@@ -882,11 +935,22 @@ You can still ask about:
882
935
  };
883
936
  }
884
937
 
885
- // Build output
886
- let output = `Throne #${throne.throne_id} - ${throne.name}\n\n`;
887
- output += `Rarity: ${throne.rarity.toUpperCase()}\n`;
888
- output += `Earned in Cycle: ${throne.cycle_id}\n`;
889
- output += `Earned: ${new Date(throne.earned_at).toLocaleDateString()}\n`;
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`;
890
954
 
891
955
  // Fetch and convert image to base64
892
956
  const imageUrl = `https://img.champz.world${throne.image_path}`;
@@ -903,7 +967,7 @@ You can still ask about:
903
967
  content.push({
904
968
  type: 'image',
905
969
  data: base64Data,
906
- mimeType: 'image/png',
970
+ mimeType: 'image/jpeg',
907
971
  });
908
972
  }
909
973
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@champz-llc/legends-mcp-server",
3
- "version": "1.3.6",
3
+ "version": "1.4.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",
@@ -34,6 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.0.0",
37
- "node-fetch": "^3.3.2"
37
+ "node-fetch": "^3.3.2",
38
+ "sharp": "^0.34.5"
38
39
  }
39
40
  }