discover_music
Browse curated music collections by genre, mood, charts, era, or artist spotlights. Discover trending tracks, playlists, and featured artists.
Instructions
Browse curated music collections — charts, genre walls, moods, editorial playlists, and artist spotlights. Use when a user wants to EXPLORE music rather than look up a specific song or album. Examples: 'what's trending this week', 'find electronic music charts', 'show me focus playlists', 'who are the featured artists this week'. Returns walls (collections) with their slugs, which can then be passed back as the wall argument to expand into individual tracks/albums. Each entry includes a BeatsVine page URL whose streaming and purchase links can be fetched via resolve_music. Ranked by editorial pinning and refresh freshness, never by commission.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| chamber | No | Chamber to browse. Omit for a top-level overview of all chambers and featured walls. 'by-genre' = genre corridors (house, hip-hop, jazz, etc.). 'for-this-moment' = mood and activity walls (chill, focus, workout). 'charts' = live streaming charts. 'by-era' = decades and golden eras. 'spotlights' = editor-led artist features. | |
| wall | No | Wall slug to drill into. If set, returns the wall's track/album/artist entries. Takes priority over `chamber`. Example: 'lastfm-top-electronic-tracks', 'deezer-90s-hits'. Slugs are returned in the foyer and chamber responses. | |
| limit | No | Max items to return. Default 10, max 30. Applies to walls (foyer/chamber mode) or entries (wall mode). |
Implementation Reference
- src/tools/discoverMusic.ts:187-207 (handler)Main handler function for discover_music. Uses three modes: wall (drill into a specific collection), chamber (browse walls within a chamber), and foyer (top-level overview of all chambers/featured walls). Fetches from BeatsVine discovery API.
export async function discoverMusic(input: DiscoverMusicInput): Promise<DiscoverMusicResult> { // Mode 3: Specific wall — most specific, wins over chamber if (input.wall) { const slug = input.wall.trim().toLowerCase(); const result = await fetchJson<WallResponse>(`/walls/${encodeURIComponent(slug)}/json`); if (!result.ok) return { success: false, error: result.error }; return { success: true, mode: "wall", wall: result.data }; } // Mode 2: Chamber browse if (input.chamber) { const result = await fetchJson<ChamberResponse>(`/discovery/${input.chamber}/json`); if (!result.ok) return { success: false, error: result.error }; return { success: true, mode: "chamber", chamber: result.data }; } // Mode 1: Foyer (top-level discovery) const result = await fetchJson<FoyerResponse>(`/discovery/json`); if (!result.ok) return { success: false, error: result.error }; return { success: true, mode: "foyer", foyer: result.data }; } - src/tools/discoverMusic.ts:320-337 (handler)Top-level formatter that dispatches to mode-specific formatters (formatFoyerResponse, formatChamberResponse, formatWallResponse) based on the mode returned by discoverMusic.
export function formatDiscoverResponse(result: DiscoverMusicResult, requestedLimit?: number): string { if (!result.success) { return `❌ Discovery failed: ${result.error ?? "Unknown error"}`; } const limit = clampLimit(requestedLimit, 10, 30); if (result.mode === "wall" && result.wall) { return formatWallResponse(result.wall, limit); } if (result.mode === "chamber" && result.chamber) { return formatChamberResponse(result.chamber, limit); } if (result.mode === "foyer" && result.foyer) { return formatFoyerResponse(result.foyer, limit); } return "❌ Discovery returned no data."; } - src/tools/discoverMusic.ts:137-141 (schema)Input schema for discover_music: optional chamber (enum of 5 slugs), optional wall string, optional limit number.
export interface DiscoverMusicInput { chamber?: ChamberSlug; wall?: string; limit?: number; } - src/tools/discoverMusic.ts:143-150 (schema)Result interface for discover_music: success flag, mode enum, and optional foyer/chamber/wall response objects.
export interface DiscoverMusicResult { success: boolean; mode?: "foyer" | "chamber" | "wall"; foyer?: FoyerResponse; chamber?: ChamberResponse; wall?: WallResponse; error?: string; } - src/index.ts:160-200 (registration)Tool registration in server.registerTool("discover_music", ...) with Zod input schema, description, and the async handler that calls discoverMusic() and formatDiscoverResponse().
server.registerTool( "discover_music", { description: "Browse curated music collections — charts, genre walls, moods, editorial playlists, and artist spotlights. Use when a user wants to EXPLORE music rather than look up a specific song or album. Examples: 'what's trending this week', 'find electronic music charts', 'show me focus playlists', 'who are the featured artists this week'. Returns walls (collections) with their slugs, which can then be passed back as the `wall` argument to expand into individual tracks/albums. Each entry includes a BeatsVine page URL whose streaming and purchase links can be fetched via `resolve_music`. Ranked by editorial pinning and refresh freshness, never by commission.", inputSchema: { chamber: z .enum(["by-genre", "for-this-moment", "charts", "by-era", "spotlights"]) .optional() .describe( "Chamber to browse. Omit for a top-level overview of all chambers and featured walls. 'by-genre' = genre corridors (house, hip-hop, jazz, etc.). 'for-this-moment' = mood and activity walls (chill, focus, workout). 'charts' = live streaming charts. 'by-era' = decades and golden eras. 'spotlights' = editor-led artist features.", ), wall: z .string() .optional() .describe( "Wall slug to drill into. If set, returns the wall's track/album/artist entries. Takes priority over `chamber`. Example: 'lastfm-top-electronic-tracks', 'deezer-90s-hits'. Slugs are returned in the foyer and chamber responses.", ), limit: z .number() .int() .positive() .max(30) .optional() .describe( "Max items to return. Default 10, max 30. Applies to walls (foyer/chamber mode) or entries (wall mode).", ), }, }, async ({ chamber, wall, limit }) => { const result = await discoverMusic({ chamber, wall, limit }); return { content: [ { type: "text" as const, text: formatDiscoverResponse(result, limit), }, ], }; }, );