pokemon-card-search
Search and filter Pokémon TCG cards by name, type, legality, HP, retreat cost, and other attributes to find specific cards or build optimized decks.
Instructions
Searches for Pokemon cards
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| attacks | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The attacks available to this Pokemon card. Use dot notation (.) to search nested fields (e.g., "set.id:sm1" for set ID, "attacks.name:Spelunk" for attack names). For example, "attacks.name:Spelunk" to find cards with a specific attack name. If no attack information is explicitly mentioned, omit this field entirely. | |
| convertedRetreatCost | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. CRITICAL: Query exactly what was asked for. Do not try to be systematic. Do not try to find specific examples. Do not try to be methodical. Just make the exact query requested. The converted retreat cost for a given Pokemon card. If no converted retreat cost is explicitly mentioned, omit this field. If the user explicitly specifies "free retreat", set this to 0. Use ! for exact matching (e.g., "!value" to match only exact value). Use [ and ] for inclusive ranges (e.g., [1 TO 3] for values 1-3). Use { and } for exclusive ranges (e.g., {1 TO 3} for values more than 1 and less than 3). Use * for unbounded ranges (e.g., [* TO 100] for values up to 100, or [100 TO *] for values 100 or higher). | |
| evolvesTo | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The Pokemon this card evolves into. Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). If no evolution information is explicitly mentioned, omit this field entirely. | |
| hp | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The HP (Hit Points) of the Pokemon card. Use ! for exact matching (e.g., "!value" to match only exact value). Use [ and ] for inclusive ranges (e.g., [1 TO 3] for values 1-3). Use { and } for exclusive ranges (e.g., {1 TO 3} for values more than 1 and less than 3). Use * for unbounded ranges (e.g., [* TO 100] for values up to 100, or [100 TO *] for values 100 or higher). If no HP is explicitly mentioned, omit this field entirely. | |
| legalities | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. CRITICAL: Query exactly what was asked for. Do not try to be systematic. Do not try to find specific examples. Do not try to be methodical. Just make the exact query requested. The legalities for a given card. For each legality passed in, the value is "legal" without quotes. Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). Use dot notation (.) to search nested fields (e.g., "set.id:sm1" for set ID, "attacks.name:Spelunk" for attack names). For example, "legalities.standard:banned" to find cards banned in Standard. If no legalities are explicitly mentioned, omit this field entirely. | |
| name | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. CRITICAL: Query exactly what was asked for. Do not try to be systematic. Do not try to find specific examples. Do not try to be methodical. Just make the exact query requested. IMPORTANT: For hyphenated names like "chien-pao", you MUST preserve the hyphen exactly as it appears. For example, "chien-pao ex" should have name "chien-pao" (with the hyphen) and subtypes ["EX"]. Never remove or modify hyphens in the name. Use * for wildcard matching (e.g., "char*" to match all cards starting with "char", or "char*der" to match cards starting with "char" and ending with "der"). Use ! for exact matching (e.g., "!value" to match only exact value). IMPORTANT: If no name is explicitly provided in the query, do not include a name field at all. | |
| nationalPokedexNumbers | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The National Pokedex numbers of the Pokemon. Use ! for exact matching (e.g., "!value" to match only exact value). Use [ and ] for inclusive ranges (e.g., [1 TO 3] for values 1-3). Use { and } for exclusive ranges (e.g., {1 TO 3} for values more than 1 and less than 3). Use * for unbounded ranges (e.g., [* TO 100] for values up to 100, or [100 TO *] for values 100 or higher). If no Pokedex numbers are explicitly mentioned, omit this field entirely. | |
| page | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The page number for pagination. Use ! for exact matching (e.g., "!value" to match only exact value). Use [ and ] for inclusive ranges (e.g., [1 TO 3] for values 1-3). Use { and } for exclusive ranges (e.g., {1 TO 3} for values more than 1 and less than 3). Use * for unbounded ranges (e.g., [* TO 100] for values up to 100, or [100 TO *] for values 100 or higher). If no page is explicitly mentioned, omit this field entirely. | |
| pageSize | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The number of cards per page. Use ! for exact matching (e.g., "!value" to match only exact value). Use [ and ] for inclusive ranges (e.g., [1 TO 3] for values 1-3). Use { and } for exclusive ranges (e.g., {1 TO 3} for values more than 1 and less than 3). Use * for unbounded ranges (e.g., [* TO 100] for values up to 100, or [100 TO *] for values 100 or higher). If no page size is explicitly mentioned, omit this field entirely. | |
| regulationMark | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The regulation mark (also known as "block") of the card (e.g., "F", "G", "H"). This indicates which regulation block the card belongs to. Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). If no regulation mark is explicitly mentioned, omit this field entirely. | |
| set | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The set information for this card. Use dot notation (.) to search nested fields (e.g., "set.id:sm1" for set ID, "attacks.name:Spelunk" for attack names). For example, "set.id:sm1" to find cards from a specific set. If no set information is explicitly mentioned, omit this field entirely. | |
| subtypes | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. CRITICAL: Query exactly what was asked for. Do not try to be systematic. Do not try to find specific examples. Do not try to be methodical. Just make the exact query requested. For example, "chien pao ex" should have name "chien pao" and subtypes ["EX"]. If multiple subtypes are present like "basic pikachu ex", use ["Basic", "EX"]. Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). If no subtypes are explicitly mentioned in the query, omit this field entirely. | |
| types | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The types of the Pokemon card (e.g., ["Grass", "Psychic"]). Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). If no types are explicitly mentioned, omit this field entirely. | |
| weaknesses | No | CRITICAL: Never infer or guess values. Never provide default values. Never make assumptions about what the user might want. Never try to be systematic or methodical. Never try to find "specific examples". Just query exactly what was asked for, nothing more and nothing less. The weaknesses of this Pokemon card. Use negative values with a "-" prefix to exclude values (e.g., ["-value"] to exclude value). Use ! for exact matching (e.g., "!value" to match only exact value). Use dot notation (.) to search nested fields (e.g., "set.id:sm1" for set ID, "attacks.name:Spelunk" for attack names). For example, "weaknesses.type:Water" to find cards weak to Water. If no weakness information is explicitly mentioned, omit this field entirely. |
Implementation Reference
- index.ts:276-343 (handler)The async handler function that processes the input parameters, builds the search query, handles negative type filters, calls the ptcg_search API, and returns the result as JSON.async ({ name, subtypes, legalities, convertedRetreatCost, hp, types, evolvesTo, attacks, weaknesses, set, nationalPokedexNumbers, page, pageSize, regulationMark, }) => { // Split types into positive and negative filters const positiveTypes = types?.filter(t => !t.startsWith('-')) || []; const negativeTypes = types?.filter(t => t.startsWith('-')).map(t => t.slice(1)) || []; let query = buildQuery( name, subtypes, legalities, hp, positiveTypes, evolvesTo, convertedRetreatCost, nationalPokedexNumbers, page, pageSize, set, attacks, weaknesses, regulationMark ); // Add negative type filters if (negativeTypes.length > 0) { const negativeQuery = buildQuery( undefined, undefined, undefined, undefined, negativeTypes, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined ); query = `${query} ${negativeQuery}`; } const result = await ptcg_search(query); return { content: [ { type: 'text', text: JSON.stringify(result), }, ], }; }
- index.ts:178-275 (schema)The Zod input schema for the pokemon-card-search tool, defining optional parameters such as name, subtypes, legalities, hp, types, and more, each with detailed descriptions.{ name: z.string().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.NAME), subtypes: z .array( z.enum([ 'BREAK', 'Baby', 'Basic', 'EX', 'GX', 'Goldenrod Game Corner', 'Item', 'LEGEND', 'Level-Up', 'MEGA', 'Pokémon Tool', 'Pokémon Tool F', 'Rapid Strike', 'Restored', "Rocket's Secret Machine", 'Single Strike', 'Special', 'Stadium', 'Stage 1', 'Stage 2', 'Supporter', 'TAG TEAM', 'Technical Machine', 'V', 'VMAX', 'VSTAR', 'Tera', ]) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.SUBTYPES), legalities: z .object({ standard: z.enum(['legal', 'banned']).optional(), expanded: z.enum(['legal', 'banned']).optional(), unlimited: z.enum(['legal', 'banned']).optional(), }) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.LEGALITIES), convertedRetreatCost: z .number() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.CONVERTED_RETREAT_COST), hp: z.string().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.HP), nationalPokedexNumbers: z .string() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.NATIONAL_POKEDEX_NUMBERS), page: z.number().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.PAGE), pageSize: z .number() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.PAGE_SIZE), types: z .array(z.string()) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.TYPES), evolvesTo: z .array(z.string()) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.EVOLVES_TO), attacks: z .array( z.object({ name: z.string(), cost: z.array(z.string()), damage: z.string(), text: z.string(), }) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.ATTACKS), weaknesses: z .array( z.object({ type: z.string(), value: z.string(), }) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.WEAKNESSES), set: z .object({ name: z.string(), series: z.string(), }) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.SET), regulationMark: z .string() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.REGULATION_MARK), },
- index.ts:175-344 (registration)The server.tool registration call for the 'pokemon-card-search' tool, specifying name, description, input schema, and handler function.server.tool( 'pokemon-card-search', 'Searches for Pokemon cards', { name: z.string().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.NAME), subtypes: z .array( z.enum([ 'BREAK', 'Baby', 'Basic', 'EX', 'GX', 'Goldenrod Game Corner', 'Item', 'LEGEND', 'Level-Up', 'MEGA', 'Pokémon Tool', 'Pokémon Tool F', 'Rapid Strike', 'Restored', "Rocket's Secret Machine", 'Single Strike', 'Special', 'Stadium', 'Stage 1', 'Stage 2', 'Supporter', 'TAG TEAM', 'Technical Machine', 'V', 'VMAX', 'VSTAR', 'Tera', ]) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.SUBTYPES), legalities: z .object({ standard: z.enum(['legal', 'banned']).optional(), expanded: z.enum(['legal', 'banned']).optional(), unlimited: z.enum(['legal', 'banned']).optional(), }) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.LEGALITIES), convertedRetreatCost: z .number() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.CONVERTED_RETREAT_COST), hp: z.string().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.HP), nationalPokedexNumbers: z .string() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.NATIONAL_POKEDEX_NUMBERS), page: z.number().optional().describe(FIELD_DESCRIPTIONS_SPECIFIC.PAGE), pageSize: z .number() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.PAGE_SIZE), types: z .array(z.string()) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.TYPES), evolvesTo: z .array(z.string()) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.EVOLVES_TO), attacks: z .array( z.object({ name: z.string(), cost: z.array(z.string()), damage: z.string(), text: z.string(), }) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.ATTACKS), weaknesses: z .array( z.object({ type: z.string(), value: z.string(), }) ) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.WEAKNESSES), set: z .object({ name: z.string(), series: z.string(), }) .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.SET), regulationMark: z .string() .optional() .describe(FIELD_DESCRIPTIONS_SPECIFIC.REGULATION_MARK), }, async ({ name, subtypes, legalities, convertedRetreatCost, hp, types, evolvesTo, attacks, weaknesses, set, nationalPokedexNumbers, page, pageSize, regulationMark, }) => { // Split types into positive and negative filters const positiveTypes = types?.filter(t => !t.startsWith('-')) || []; const negativeTypes = types?.filter(t => t.startsWith('-')).map(t => t.slice(1)) || []; let query = buildQuery( name, subtypes, legalities, hp, positiveTypes, evolvesTo, convertedRetreatCost, nationalPokedexNumbers, page, pageSize, set, attacks, weaknesses, regulationMark ); // Add negative type filters if (negativeTypes.length > 0) { const negativeQuery = buildQuery( undefined, undefined, undefined, undefined, negativeTypes, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined ); query = `${query} ${negativeQuery}`; } const result = await ptcg_search(query); return { content: [ { type: 'text', text: JSON.stringify(result), }, ], }; } );
- index.ts:421-529 (helper)Helper function buildQuery that constructs the search query string for the Pokemon TCG API based on the provided parameters, handling filters, ranges, nested fields, etc.function buildQuery( name?: string, subtypes?: string[], legalities?: | { standard?: 'legal' | 'banned'; expanded?: 'legal' | 'banned'; unlimited?: 'legal' | 'banned'; } | string, hp?: string, types?: string[], evolvesTo?: string[], convertedRetreatCost?: number, nationalPokedexNumbers?: string, page?: number | string, pageSize?: number | string, set?: { id?: string; name?: string; series?: string } | string, attacks?: | Array<{ name?: string; cost?: string[]; damage?: string; text?: string }> | string, weaknesses?: Array<{ type?: string; value?: string }> | string, regulationMark?: string ): string { const parts: string[] = []; // Handle name with special cases if (name) { if (name.startsWith('!') || name.includes('*')) { parts.push(`name:${name}`); } else { parts.push(`name:"${name}"`); } } // Generic filter handler for arrays function addFilter( values: string[] | undefined, field: string, negative = false ) { if (!values?.length) return; const query = values .map(value => { if (value.includes('.')) return value; if (value.startsWith('!')) return `${field}:${value}`; if (negative) return `-${field}:${value}`; return `${field}:${value}`; }) .join(' OR '); parts.push(values.length === 1 ? query : `(${query})`); } // Generic nested filter handler function addNestedFilter(value: string | object | undefined, field: string) { if (!value) return; if (typeof value === 'string') { parts.push(value.includes('.') ? value : `${field}:${value}`); } else { Object.entries(value).forEach(([key, val]) => { if (val !== undefined) { parts.push(`${field}.${key}:${val}`); } }); } } // Generic range filter handler function addRangeFilter(value: string | number | undefined, field: string) { if (!value) return; const strValue = String(value); if ( strValue.startsWith('[') || strValue.startsWith('{') || strValue.startsWith('!') ) { parts.push(`${field}:${strValue}`); } else { parts.push(`${field}:${value}`); } } // Add all filters addFilter(subtypes, 'subtypes'); addNestedFilter(legalities, 'legalities'); addFilter(types, 'types'); addFilter(evolvesTo, 'evolvesTo'); addRangeFilter(hp, 'hp'); addRangeFilter(convertedRetreatCost, 'convertedRetreatCost'); addRangeFilter(nationalPokedexNumbers, 'nationalPokedexNumbers'); addRangeFilter(page, 'page'); addRangeFilter(pageSize, 'pageSize'); addNestedFilter(set, 'set'); addNestedFilter(attacks, 'attacks'); addNestedFilter(weaknesses, 'weaknesses'); // Add regulation mark filter if (regulationMark) { parts.push(`regulationMark:${regulationMark}`); } return parts.join(' '); }
- index.ts:531-536 (helper)Helper function ptcg_search that fetches card data from the Pokemon TCG API using the constructed query.async function ptcg_search(query: string): Promise<PtcgResponse> { const response = await fetch( `https://api.pokemontcg.io/v2/cards?q=${encodeURIComponent(query)}` ); return response.json() as Promise<PtcgResponse>; }