find_product
Resolves product queries to the best streaming, purchase, or collection source. Automatically detects category and routes to the right provider for music, games, and more.
Instructions
Smart router — finds the best place to stream, buy, or collect any supported product. Automatically detects the product category and routes to the right resolver. Music is live (stream, digital purchase, vinyl, CD, collector editions). Games, books, films, podcasts, and live event tickets are rolling out. Use this when the query is ambiguous or when music could be streamed, purchased digitally, or found on physical media.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | A natural language product query. Examples: 'Aphex Twin Windowlicker', 'Elden Ring DLC', 'where can I stream Bad Guy by Billie Eilish' | |
| category | No | Product category. Use 'auto' (default) to let RootVine detect the category automatically. |
Implementation Reference
- src/tools/findProduct.ts:75-115 (handler)Main handler for the find_product tool. Routes queries by category (music/game) by calling resolveMusic or resolveGame, and returns a formatted result string.
export async function findProduct(input: FindProductInput): Promise<FindProductResult> { const { query } = input; const category = input.category === "auto" || !input.category ? detectCategory(query) : input.category; const slug = queryToSlug(query); if (category === "music") { const result = await resolveMusic({ slug }); return { success: result.success, category: "music", response: result.response, formatted: result.response ? formatMusicResponse(result.response) : `❌ ${result.error || "Unknown error"}`, error: result.error, }; } if (category === "game") { const result = await resolveGame({ slug }); return { success: result.success, category: "game", response: result.response, formatted: result.response ? formatGameResponse(result.response) : `❌ ${result.error || "Unknown error"}`, error: result.error, }; } return { success: false, category: "music", formatted: `❌ Unknown category: ${category}`, error: `Unknown category: ${category}`, }; } - src/tools/findProduct.ts:17-28 (schema)Input/output type definitions for find_product: FindProductInput (query string + optional category enum) and FindProductResult (success, category, response, formatted string, error).
export interface FindProductInput { query: string; category?: "music" | "game" | "auto"; } export interface FindProductResult { success: boolean; category: "music" | "game"; response?: RootVineResponseV1; formatted: string; error?: string; } - src/index.ts:126-155 (registration)MCP registration of the 'find_product' tool with description, input schema (query string + optional category enum), and async handler that delegates to the findProduct function.
server.registerTool( "find_product", { description: "Smart router — finds the best place to stream, buy, or collect any supported product. Automatically detects the product category and routes to the right resolver. Music is live (stream, digital purchase, vinyl, CD, collector editions). Games, books, films, podcasts, and live event tickets are rolling out. Use this when the query is ambiguous or when music could be streamed, purchased digitally, or found on physical media.", inputSchema: { query: z .string() .describe("A natural language product query. Examples: 'Aphex Twin Windowlicker', 'Elden Ring DLC', 'where can I stream Bad Guy by Billie Eilish'"), category: z .enum(["music", "game", "auto"]) .optional() .describe("Product category. Use 'auto' (default) to let RootVine detect the category automatically."), }, }, async ({ query, category }) => { const result = await findProduct({ query, category: category || "auto", }); return { content: [ { type: "text" as const, text: result.formatted, }, ], }; }, ); - src/tools/findProduct.ts:34-59 (helper)Category detection helper: scans query text for game-related keywords (game, steam, xbox, etc.) or music keywords (song, album, stream, etc.) to auto-classify products.
function detectCategory(query: string): "music" | "game" { const q = query.toLowerCase(); // Game indicators const gameKeywords = [ "game", "dlc", "expansion", "steam", "xbox", "playstation", "ps5", "ps4", "nintendo", "switch", "pc game", "goty", "edition", "gameplay", ]; for (const kw of gameKeywords) { if (q.includes(kw)) return "game"; } // Music indicators (default — music is more common for now) const musicKeywords = [ "song", "album", "track", "listen", "stream", "spotify", "apple music", "vinyl", "single", "ep ", "lp ", "feat", "ft.", "remix", "acoustic", ]; for (const kw of musicKeywords) { if (q.includes(kw)) return "music"; } // Default to music (BeatsVine is the first tree) return "music"; } - src/tools/findProduct.ts:65-73 (helper)Query-to-slug normalization helper: lowercases, trims, removes special chars, converts spaces to hyphens.
function queryToSlug(query: string): string { return query .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, "") // Remove special chars .replace(/\s+/g, "-") // Spaces to hyphens .replace(/-+/g, "-") // Collapse multiple hyphens .replace(/^-|-$/g, ""); // Trim leading/trailing hyphens }