search_stratagems
Search Warhammer 40,000 stratagems by name, faction, phase, or detachment to find relevant rules quickly.
Instructions
Search Warhammer 40,000 stratagems by name, faction, phase, or detachment. Returns a compact list (max 10). For Kill Team ploys, use lookup_ploy instead.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query — matches against name, faction, phase, and effect | |
| faction | No | Optional faction filter (e.g. 'Core', 'Adeptus Astartes') | |
| phase | No | Optional phase filter (e.g. 'Fight phase', 'Shooting') | |
| detachment | No | Optional detachment filter (e.g. 'Gladius Task Force') |
Implementation Reference
- src/tools/search-stratagems.ts:31-76 (handler)The async handler function that executes the search_stratagems tool logic: filters stratagems by optional faction/phase/detachment, fuzzy-searches by query on name/effect/phase fields, returns up to 10 results as compact Markdown.
async ({ query, faction, phase, detachment }) => { let candidates: Stratagem[] = [...STRATAGEMS]; if (faction) { candidates = fuzzySearch(candidates, faction, ["faction"]); } if (phase) { candidates = fuzzySearch(candidates, phase, ["phase"]); } if (detachment) { candidates = candidates.filter( (s) => s.detachment && s.detachment.toLowerCase().includes(detachment.toLowerCase()), ); } const matches = fuzzySearch(candidates, query, ["name", "effect", "phase"]); const limited = matches.slice(0, 10); if (limited.length === 0) { return { content: [ { type: "text" as const, text: `No Warhammer 40,000 stratagems found matching "${query}".${faction ? ` (faction: "${faction}")` : ""}\n\nNote: For Kill Team ploys, use the lookup_ploy tool instead.`, }, ], }; } const header = "**Game:** Warhammer 40,000\n\n"; const lines = limited.map(formatCompact); const footer = matches.length > 10 ? `\n\n_Showing 10 of ${matches.length} results. Narrow your search for more specific results._` : ""; return { content: [ { type: "text" as const, text: header + lines.join("\n") + footer, }, ], }; }, ); - src/tools/search-stratagems.ts:16-30 (schema)Zod schema defining the input parameters for search_stratagems: query (required string), faction, phase, detachment (all optional strings).
{ query: z.string().describe("Search query — matches against name, faction, phase, and effect"), faction: z .string() .optional() .describe("Optional faction filter (e.g. 'Core', 'Adeptus Astartes')"), phase: z .string() .optional() .describe("Optional phase filter (e.g. 'Fight phase', 'Shooting')"), detachment: z .string() .optional() .describe("Optional detachment filter (e.g. 'Gladius Task Force')"), }, - src/tools/search-stratagems.ts:12-77 (registration)The registerSearchStratagems function that calls server.tool() to register the 'search_stratagems' tool with description and schema.
export function registerSearchStratagems(server: McpServer): void { server.tool( "search_stratagems", "Search Warhammer 40,000 stratagems by name, faction, phase, or detachment. Returns a compact list (max 10). For Kill Team ploys, use lookup_ploy instead.", { query: z.string().describe("Search query — matches against name, faction, phase, and effect"), faction: z .string() .optional() .describe("Optional faction filter (e.g. 'Core', 'Adeptus Astartes')"), phase: z .string() .optional() .describe("Optional phase filter (e.g. 'Fight phase', 'Shooting')"), detachment: z .string() .optional() .describe("Optional detachment filter (e.g. 'Gladius Task Force')"), }, async ({ query, faction, phase, detachment }) => { let candidates: Stratagem[] = [...STRATAGEMS]; if (faction) { candidates = fuzzySearch(candidates, faction, ["faction"]); } if (phase) { candidates = fuzzySearch(candidates, phase, ["phase"]); } if (detachment) { candidates = candidates.filter( (s) => s.detachment && s.detachment.toLowerCase().includes(detachment.toLowerCase()), ); } const matches = fuzzySearch(candidates, query, ["name", "effect", "phase"]); const limited = matches.slice(0, 10); if (limited.length === 0) { return { content: [ { type: "text" as const, text: `No Warhammer 40,000 stratagems found matching "${query}".${faction ? ` (faction: "${faction}")` : ""}\n\nNote: For Kill Team ploys, use the lookup_ploy tool instead.`, }, ], }; } const header = "**Game:** Warhammer 40,000\n\n"; const lines = limited.map(formatCompact); const footer = matches.length > 10 ? `\n\n_Showing 10 of ${matches.length} results. Narrow your search for more specific results._` : ""; return { content: [ { type: "text" as const, text: header + lines.join("\n") + footer, }, ], }; }, ); } - src/register-tools.ts:24-27 (registration)Registration call to registerSearchStratagems(server) within the central registerTools function.
registerSearchStratagems(server); registerLookupDetachment(server); registerLookupEnhancement(server); registerLookupPloy(server); - src/tools/search-stratagems.ts:7-10 (helper)The formatCompact helper function that renders a Stratagem object into a compact Markdown string for display.
function formatCompact(strat: Stratagem): string { const detStr = strat.detachment ? ` [${strat.detachment}]` : ""; return `**${strat.name}** (${strat.faction}${detStr}) — ${strat.cpCost} CP | ${strat.phase} | ${strat.type.replace("_", " ")}`; }