csb_find_combos_by_names
Find Magic: The Gathering card combos by providing card names. Maps names to card IDs using Scryfall, then searches for combinations involving those cards.
Instructions
Resolve names via Scryfall → oracle_id, map to CSB IDs via cached index, then call find-my-combos.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| fuzzy | No | Use Scryfall fuzzy name matching; default true | |
| limit | No | ||
| names | Yes | ||
| offset | No |
Implementation Reference
- src/mcp-server.ts:556-561 (schema)Input schema (Zod shape) for the csb_find_combos_by_names tool.const csbFindByNamesInput = { names: z.array(z.string()).min(1), fuzzy: z.boolean().optional().describe("Use Scryfall fuzzy name matching; default true"), limit: z.number().int().min(1).max(100).optional(), offset: z.number().int().min(0).optional() } as const;
- src/mcp-server.ts:562-568 (registration)Registration of the csb_find_combos_by_names tool in the MCP server, referencing the input schema.server.registerTool( "csb_find_combos_by_names", { title: "CSB: Find combos by card names", description: "Resolve names via Scryfall → oracle_id, map to CSB IDs via cached index, then call find-my-combos.", inputSchema: csbFindByNamesInput },
- src/mcp-server.ts:569-591 (handler)The handler function implementing the core logic: resolves card names to unique oracle IDs using Scryfall, maps to CSB card IDs using local index, fetches combos using CSB API.async ({ names, fuzzy = true, limit, offset }: { names: string[]; fuzzy?: boolean; limit?: number; offset?: number }) => { // Resolve names to oracle_ids via Scryfall const oracleIds: string[] = []; for (const name of names) { try { const card: any = await Scryfall.getCardNamed(name, fuzzy); const oid = (card as any)?.oracle_id || (card as any)?.oracleId || (card as any)?.oracleID; if (typeof oid === "string") oracleIds.push(oid); } catch { // ignore individual failures } } const uniqOids = Array.from(new Set(oracleIds)); if (uniqOids.length === 0) return { content: [{ type: "text", text: "No oracle IDs resolved from names" }] } as any; const mapRes = await lookupCsbIdsByOracle(uniqOids); const ids = Object.values(mapRes.found); if (ids.length === 0) { return { structuredContent: { mapping: mapRes, results: null } } as any; } const combos = await CSB.findMyCombos(ids, limit, offset); return { structuredContent: { mapping: mapRes, results: combos } } as any; }
- src/csb-index.ts:79-89 (helper)Helper function to map Scryfall oracle_ids to CSB numeric card IDs using a cached index (builds index if missing/stale). Called within the tool handler.export async function lookupCsbIdsByOracle(oracleIds: string[], options?: { ttlMs?: number; force?: boolean; cachePath?: string }): Promise<{ found: Record<string, number>; missing: string[] }> { const idx = await loadCsbIndex(options); const found: Record<string, number> = {}; const missing: string[] = []; for (const oid of oracleIds) { const id = idx.oracleToId[oid]; if (typeof id === "number") found[oid] = id; else missing.push(oid); } return { found, missing }; }
- src/csb.ts:111-112 (helper)CSB.findMyCombos wrapper that calls the remote Commander Spellbook API endpoint /find-my-combos. Invoked in the tool handler after ID mapping.findMyCombos: (ids: number[], limit?: number, offset?: number) => getJson("/find-my-combos", { ids: ids.join(","), limit, offset }),