Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
chamberNoChamber 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.
wallNoWall 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.
limitNoMax items to return. Default 10, max 30. Applies to walls (foyer/chamber mode) or entries (wall mode).

Implementation Reference

  • 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 };
    }
  • 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.";
    }
  • 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;
    }
  • 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),
                    },
                ],
            };
        },
    );
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so the description carries full burden. It discloses ranking criteria ('Ranked by editorial pinning and refresh freshness, never by commission'), the structure of responses (foyer/chamber/wall), and mentions further resolution via resolve_music. This adds valuable behavioral context beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured, starting with the main purpose and then providing examples and details. It is a bit lengthy (6 sentences) but every sentence adds value, so conciseness is good but not perfect.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, but the description explains what is returned: walls with slugs and entries with BeatsVine page URLs. It covers the main use cases and the flow of drilling down. For a browsing tool with 3 optional params, this is fairly complete. Could mention pagination or error cases, but not necessary.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description enriches the parameter meanings by explaining the chambers ('by-genre' = genre corridors, etc.), how wall slugs are obtained and used, and the limit applies to different modes. This adds practical context beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses specific verbs and resources ('Browse curated music collections') and includes concrete examples like 'what's trending this week' and 'show me focus playlists'. It clearly differentiates from sibling tools like resolve_music, which handles URL resolution, and find_product/resolve_game.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use ('when a user wants to EXPLORE music rather than look up a specific song or album'). It explains the flow of using returned slugs with the `wall` argument. However, it does not explicitly state when not to use it, though the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RagingOrangutan/rootvine-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server