maplestorysea-mcp-server
Version:
NEXON MapleStory SEA API MCP Server for Claude Desktop - Complete character info, union details, guild data, rankings optimized for SEA servers
165 lines • 7.4 kB
JavaScript
;
/**
* Ranking Tools for MCP Maple
* Provides MCP tools for retrieving various MapleStory SEA rankings
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetOverallRankingTool = void 0;
const base_tool_1 = require("./base-tool");
const constants_1 = require("../api/constants");
const server_utils_1 = require("../utils/server-utils");
/**
* Tool for getting overall level rankings
*/
class GetOverallRankingTool extends base_tool_1.EnhancedBaseTool {
name = 'get_overall_ranking';
description = 'Retrieve overall level rankings for MapleStory SEA characters with filtering options';
inputSchema = {
type: 'object',
properties: {
worldName: {
type: 'string',
description: 'World name to get rankings for (optional)',
enum: ['Aquila', 'Bootes', 'Cassiopeia', 'Draco'],
},
className: {
type: 'string',
description: 'Character class filter (optional)',
enum: [...constants_1.JOB_CLASSES],
},
characterName: {
type: 'string',
description: 'Specific character name to search for (optional)',
minLength: 1,
maxLength: 12,
pattern: '^[a-zA-Z0-9]+$',
},
page: {
type: 'integer',
description: 'Page number for pagination (1-based, optional, defaults to 1)',
minimum: 1,
maximum: 200,
default: 1,
},
date: {
type: 'string',
description: 'Date for rankings in YYYY-MM-DD format (optional, defaults to yesterday)',
pattern: '^\\d{4}-\\d{2}-\\d{2}$',
},
},
additionalProperties: false,
};
metadata = {
category: base_tool_1.ToolCategory.RANKING,
tags: ['ranking', 'overall', 'level', 'leaderboard'],
examples: [
{
description: 'Get overall rankings for all worlds',
arguments: {},
},
{
description: 'Get rankings for specific world',
arguments: { worldName: 'Aquila' },
},
{
description: 'Get rankings for specific class',
arguments: { className: 'Arch Mage (Ice, Lightning)' },
},
{
description: 'Get rankings with pagination',
arguments: { page: 2 },
},
],
};
async executeImpl(args, context) {
const worldName = this.getOptionalString(args, 'worldName');
const className = this.getOptionalString(args, 'className');
const characterName = this.getOptionalString(args, 'characterName');
const page = this.getOptionalNumber(args, 'page', 1);
const date = this.getOptionalString(args, 'date');
try {
const startTime = Date.now();
let ocid;
// If character name is provided, get OCID for search
if (characterName) {
context.logger.info('Looking up character OCID for ranking search', { characterName });
const ocidResult = await context.nexonClient.getCharacterOcid(characterName);
ocid = ocidResult.ocid;
}
// Get overall rankings
context.logger.info('Fetching overall rankings', {
worldName: worldName || undefined,
className: className || undefined,
characterName: characterName || undefined,
page,
});
const rankings = await context.nexonClient.getOverallRanking(worldName, undefined, className, ocid, page, date);
const executionTime = Date.now() - startTime;
const rankingData = rankings.ranking?.map((entry) => ({
rank: (0, server_utils_1.formatSEANumber)(entry.ranking),
characterName: entry.character_name,
world: entry.world_name,
class: entry.class_name,
subClass: entry.sub_class_name,
level: (0, server_utils_1.formatSEANumber)(entry.character_level),
exp: (0, server_utils_1.formatSEANumber)(entry.character_exp),
popularity: (0, server_utils_1.formatSEANumber)(entry.character_popularity),
guildName: entry.character_guildname,
date: entry.date ? (0, server_utils_1.formatSEADate)(entry.date) : (0, server_utils_1.getCurrentSEADate)(),
})) || [];
context.logger.info('Overall rankings retrieved successfully', {
worldName: worldName || undefined,
className: className || undefined,
characterName: characterName || undefined,
page,
resultsCount: rankingData.length,
executionTime,
});
return this.formatResult({
page,
pageSize: rankingData.length,
filters: {
worldName: worldName || 'all',
className: className || 'all',
searchCharacter: characterName || undefined,
},
date: date ? (0, server_utils_1.formatSEADate)(date) : (0, server_utils_1.getCurrentSEADate)(),
rankings: rankingData,
summary: {
totalResults: (0, server_utils_1.formatSEANumber)(rankingData.length),
topLevel: rankingData.length > 0
? (0, server_utils_1.formatSEANumber)(Math.max(...rankingData.map((r) => parseInt(r.level.replace(/,/g, '')))))
: '0',
averageLevel: rankingData.length > 0
? (0, server_utils_1.formatSEANumber)(Math.round(rankingData.reduce((sum, r) => sum + parseInt(r.level.replace(/,/g, '')), 0) /
rankingData.length))
: '0',
worldDistribution: rankingData.reduce((acc, entry) => {
acc[entry.world] = (acc[entry.world] || 0) + 1;
return acc;
}, {}),
classDistribution: rankingData.reduce((acc, entry) => {
acc[entry.class] = (acc[entry.class] || 0) + 1;
return acc;
}, {}),
},
}, {
executionTime,
cacheHit: false,
apiCalls: characterName ? 2 : 1, // OCID lookup (if needed) + rankings
});
}
catch (error) {
context.logger.error('Failed to get overall rankings', {
worldName: worldName || undefined,
className: className || undefined,
characterName: characterName || undefined,
page,
error: error instanceof Error ? error.message : String(error),
});
return this.formatError(`Failed to get overall rankings: ${error instanceof Error ? error.message : String(error)}`);
}
}
}
exports.GetOverallRankingTool = GetOverallRankingTool;
//# sourceMappingURL=ranking-tools.js.map