search_champions
Find TFT champions by name, cost, trait, or role to access accurate game data and prevent AI hallucinations.
Instructions
Search for TFT champions by name, cost, trait, or role. Returns a summary list — use get_champion for full details on a specific champion.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Free-text search across champion name and ability (uses FTS5) | |
| cost | No | Filter by champion cost (1-5) | |
| trait | No | Filter by trait name (e.g. Warrior, Bruiser) | |
| role | No | Filter by role (e.g. damage, support, tank) | |
| limit | No | Max results to return, 1-50 (default: 20) |
Implementation Reference
- src/tools/search-champions.ts:52-146 (handler)The handler function `searchChampions` performs the logic for searching champions, building dynamic SQL queries based on provided input filters (cost, role, trait) and performing database queries to return matching champions.
export function searchChampions( db: Database.Database, input: SearchChampionsInputType, ): SearchChampionsResult { const params: unknown[] = []; const conditions: string[] = []; const joins: string[] = []; const useFts = !!input.query; // Cost filter if (input.cost != null) { conditions.push('c.cost = ?'); params.push(input.cost); } // Role filter if (input.role) { conditions.push('LOWER(c.role) = LOWER(?)'); params.push(input.role); } // Trait filter (JOIN champion_traits) if (input.trait) { joins.push('JOIN champion_traits ct ON ct.champion_name = c.name'); conditions.push('LOWER(ct.trait_name) = LOWER(?)'); params.push(input.trait); } const limit = input.limit ?? 20; let sql: string; const allParams: unknown[] = []; if (useFts) { allParams.push(input.query); allParams.push(...params); allParams.push(limit); const whereClause = conditions.length > 0 ? ' AND ' + conditions.join(' AND ') : ''; const joinClause = joins.join(' '); sql = ` SELECT DISTINCT c.name, c.cost, c.role, c.hp, c.ad, (SELECT GROUP_CONCAT(ct2.trait_name, ', ') FROM champion_traits ct2 WHERE ct2.champion_name = c.name) AS traits FROM champions_fts fts JOIN champions c ON c.rowid = fts.rowid ${joinClause} WHERE champions_fts MATCH ?${whereClause} ORDER BY fts.rank LIMIT ? `; } else { allParams.push(...params); allParams.push(limit); const whereClause = conditions.length > 0 ? 'WHERE ' + conditions.join(' AND ') : ''; const joinClause = joins.join(' '); sql = ` SELECT DISTINCT c.name, c.cost, c.role, c.hp, c.ad, (SELECT GROUP_CONCAT(ct2.trait_name, ', ') FROM champion_traits ct2 WHERE ct2.champion_name = c.name) AS traits FROM champions c ${joinClause} ${whereClause} ORDER BY c.name LIMIT ? `; } const rows = db.prepare(sql).all(...allParams) as Array<{ name: string; cost: number; role: string | null; traits: string | null; hp: number | null; ad: number | null; }>; const champions: ChampionSummary[] = rows.map((row) => ({ name: row.name, cost: row.cost, role: row.role, traits: row.traits ?? '', hp: row.hp, ad: row.ad, })); return { champions, total: champions.length }; } - src/tools/search-champions.ts:6-30 (schema)The `SearchChampionsInput` Zod schema defines the input parameters for the `search_champions` tool, including optional filters for query, cost, trait, role, and a limit.
export const SearchChampionsInput = z.object({ query: z .string() .optional() .describe('Free-text search across champion name and ability (uses FTS5)'), cost: z .number() .optional() .describe('Filter by champion cost (1-5)'), trait: z .string() .optional() .describe('Filter by trait name (e.g. Warrior, Bruiser)'), role: z .string() .optional() .describe('Filter by role (e.g. damage, support, tank)'), limit: z .number() .min(1) .max(50) .optional() .default(20) .describe('Max results to return, 1-50 (default: 20)'), }); - src/server.ts:47-65 (registration)The `search_champions` tool is registered on the `McpServer` instance in `src/server.ts`, which maps the tool name to the handler function and utilizes the schema for parameter validation.
// 1. search_champions server.tool( 'search_champions', 'Search for TFT champions by name, cost, trait, or role. Returns a summary list — use get_champion for full details on a specific champion.', SearchChampionsInput.shape, async (params) => { try { const result = searchChampions(db, params); return { content: [{ type: 'text' as const, text: formatSearchChampions(result) }], }; } catch (err) { return { content: [{ type: 'text' as const, text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true, }; } }, );