Skip to main content
Glama
grovesjosephn

Pokemon MCP Server

getPokemon.ts5.36 kB
import Database from 'better-sqlite3'; import { Pokemon, Stat, Type, Ability, ToolResponse } from '../types/index.js'; import { ResponseFormatter, PokemonData, MarkdownFormatter, } from '../formatters/index.js'; interface PokemonCompleteRow { // Pokemon data id: number; name: string; height: number; weight: number; base_experience: number; generation: number; species_url: string; sprite_url: string; // Stats data stat_name: string | null; base_stat: number | null; effort: number | null; // Type data type_name: string | null; type_slot: number | null; // Ability data ability_name: string | null; is_hidden: boolean | null; ability_slot: number | null; } export class GetPokemonTool { private preparedQuery: Database.Statement | null = null; private formatter: ResponseFormatter; constructor( private db: Database.Database, formatter?: ResponseFormatter ) { // Default to markdown formatter for backward compatibility this.formatter = formatter || new MarkdownFormatter(); // Pre-prepare the optimized query for better performance this.preparedQuery = this.db.prepare(` SELECT p.*, s.stat_name, s.base_stat, s.effort, t.name as type_name, pt.slot as type_slot, a.name as ability_name, pa.is_hidden, pa.slot as ability_slot FROM pokemon p LEFT JOIN stats s ON p.id = s.pokemon_id LEFT JOIN pokemon_types pt ON p.id = pt.pokemon_id LEFT JOIN types t ON pt.type_id = t.id LEFT JOIN pokemon_abilities pa ON p.id = pa.pokemon_id LEFT JOIN abilities a ON pa.ability_id = a.id WHERE p.id = ? OR LOWER(p.name) = LOWER(?) ORDER BY s.stat_name, pt.slot, pa.slot `); } async execute(identifier: string): Promise<ToolResponse> { if (!this.preparedQuery) { throw new Error('Database query not prepared'); } // Execute single optimized query const rows = this.preparedQuery.all( identifier, identifier ) as PokemonCompleteRow[]; if (rows.length === 0) { return this.formatter.formatNotFound(identifier); } // Process the denormalized data and convert to PokemonData format const pokemon = this.extractPokemonData(rows[0]); const stats = this.extractStats(rows); const types = this.extractTypes(rows); const abilities = this.extractAbilities(rows); // Convert to PokemonData format for formatter const pokemonData: PokemonData = { id: pokemon.id, name: pokemon.name, height: pokemon.height, weight: pokemon.weight, base_experience: pokemon.base_experience, generation: pokemon.generation, species_url: pokemon.species_url, sprite_url: pokemon.sprite_url, stats: stats.map((stat) => ({ stat_name: stat.stat_name, base_stat: stat.base_stat, effort: stat.effort, })), types: types.map((type, index) => ({ name: type.name, slot: index + 1, })), abilities: abilities.map((ability, index) => ({ name: ability.name, is_hidden: ability.is_hidden, slot: index + 1, })), }; return this.formatter.formatPokemon(pokemonData); } private extractPokemonData(row: PokemonCompleteRow): Pokemon { return { id: row.id, name: row.name, height: row.height, weight: row.weight, base_experience: row.base_experience, generation: row.generation, species_url: row.species_url, sprite_url: row.sprite_url, }; } private extractStats(rows: PokemonCompleteRow[]): Stat[] { const statsMap = new Map<string, Stat>(); for (const row of rows) { if (row.stat_name && row.base_stat !== null && row.effort !== null) { if (!statsMap.has(row.stat_name)) { statsMap.set(row.stat_name, { stat_name: row.stat_name, base_stat: row.base_stat, effort: row.effort, }); } } } // Return stats in consistent order const statOrder = [ 'hp', 'attack', 'defense', 'special-attack', 'special-defense', 'speed', ]; return statOrder .map((statName) => statsMap.get(statName)) .filter((stat): stat is Stat => stat !== undefined); } private extractTypes(rows: PokemonCompleteRow[]): Type[] { const typesMap = new Map<number, Type>(); for (const row of rows) { if (row.type_name && row.type_slot !== null) { typesMap.set(row.type_slot, { name: row.type_name, }); } } // Return types ordered by slot return Array.from(typesMap.entries()) .sort(([slotA], [slotB]) => slotA - slotB) .map(([, type]) => type); } private extractAbilities(rows: PokemonCompleteRow[]): Ability[] { const abilitiesMap = new Map<number, Ability>(); for (const row of rows) { if ( row.ability_name && row.is_hidden !== null && row.ability_slot !== null ) { abilitiesMap.set(row.ability_slot, { name: row.ability_name, is_hidden: row.is_hidden, }); } } // Return abilities ordered by slot return Array.from(abilitiesMap.entries()) .sort(([slotA], [slotB]) => slotA - slotB) .map(([, ability]) => ability); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/grovesjosephn/pokemcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server