Skip to main content
Glama

resolve_music

Find where to listen to, buy, or stream songs and albums across platforms like Spotify, Apple Music, and Amazon with direct links and pricing.

Instructions

Find where to listen to, buy, or stream a song or album. Returns ranked results from trusted music platforms (Spotify, Apple Music, Amazon, etc.) with prices and direct purchase/streaming links. Use this when a user asks about music, songs, albums, or artists.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
slugYesThe BeatsVine page slug for the track or album. Format: artist-name-song-title (lowercase, hyphenated). Example: 'ed-sheeran-galway-girl'

Implementation Reference

  • Main handler function resolveMusic that executes the tool logic. Fetches data from BeatsVine /[slug]/json endpoint, validates the response, and returns structured results with error handling.
    export async function resolveMusic(input: ResolveMusicInput): Promise<ResolveMusicResult> { const { slug } = input; const url = `${BEATSVINE_BASE}/${encodeURIComponent(slug)}/json`; try { const res = await fetch(url, { headers: { "User-Agent": "rootvine-mcp/1.0.0", "Accept": "application/json", }, signal: AbortSignal.timeout(5000), // 5s timeout }); if (!res.ok && res.status !== 404) { return { success: false, error: `BeatsVine returned HTTP ${res.status}`, }; } const data = await res.json(); // Validate against v1 schema const validation = validateResponse(data); if (!validation.success) { return { success: false, error: `Response validation failed: ${validation.error.message}`, }; } return { success: true, response: validation.data as RootVineResponseV1, }; } catch (err) { const message = err instanceof Error ? err.message : "Unknown error"; return { success: false, error: `Failed to reach BeatsVine: ${message}`, }; } }
  • Input/output TypeScript type definitions for resolveMusic: ResolveMusicInput (slug parameter) and ResolveMusicResult (success status with optional response or error).
    export interface ResolveMusicInput { slug: string; } export interface ResolveMusicResult { success: boolean; response?: RootVineResponseV1; error?: string; }
  • src/index.ts:47-82 (registration)
    MCP tool registration using server.registerTool for 'resolve_music'. Defines the tool description, input schema using Zod, and the handler that wraps resolveMusic with response formatting.
    // Tool: resolve_music // ============================================ server.registerTool( "resolve_music", { description: "Find where to listen to, buy, or stream a song or album. Returns ranked results from trusted music platforms (Spotify, Apple Music, Amazon, etc.) with prices and direct purchase/streaming links. Use this when a user asks about music, songs, albums, or artists.", inputSchema: { slug: z .string() .describe("The BeatsVine page slug for the track or album. Format: artist-name-song-title (lowercase, hyphenated). Example: 'ed-sheeran-galway-girl'"), }, }, async ({ slug }) => { const result = await resolveMusic({ slug }); if (!result.success || !result.response) { return { content: [ { type: "text" as const, text: `Could not resolve music: ${result.error || "Unknown error"}`, }, ], }; } return { content: [ { type: "text" as const, text: formatMusicResponse(result.response), }, ], }; }, );
  • Zod schema definition for RootVineResponseV1 used to validate BeatsVine API responses before returning them to agents.
    export const RootVineResponseV1Schema = z.object({ rootvine: z.object({ version: z.literal("1.0"), resolved_at: z.string(), ttl_seconds: z.number().int().min(0), resolver: z.string(), category: z.enum(["music", "games"]), schema_url: z.string(), }), response_id: z.string().startsWith("rv_resp_"), status: z.enum(["success", "partial", "no_results", "error"]), query: QueryZ, results: z.array(ResultZ), warnings: z.array(z.string()), partial_sources: z.array(z.string()), error: ErrorZ.nullable(), cover_art: z.string().optional(), source_url: z.string().optional(), dlc_count: z.number().optional(), mcp: z.object({ package: z.string(), tool_hint: z.string(), }), });
  • Helper function formatMusicResponse that formats the validated RootVine response for display to agents/users, including error handling, result ranking, and status display.
    export function formatMusicResponse(response: RootVineResponseV1): string { const lines: string[] = []; // Header if (response.query.artist && response.query.title) { lines.push(`🎡 ${response.query.artist} β€” ${response.query.title}`); } else { lines.push(`🎡 ${response.query.raw}`); } if (response.cover_art) { lines.push(`Cover: ${response.cover_art}`); } lines.push(""); // Status handling if (response.status === "error" && response.error) { lines.push(`❌ Error: ${response.error.message}`); if (response.error.retryable) { lines.push("(This error is retryable)"); } return lines.join("\n"); } if (response.status === "no_results") { lines.push("No results found for this query."); if (response.source_url) { lines.push(`Source: ${response.source_url}`); } return lines.join("\n"); } // Results for (const result of response.results) { const priceStr = result.price ? `${result.price.currency} ${result.price.amount.toFixed(2)}` : result.type === "stream" ? "Free" : "Price unknown"; const link = result.click_url || result.url; // Always prefer click_url lines.push( `${result.rank}. **${result.merchant}** (${result.trust_tier})`, ` ${result.type === "stream" ? "▢️ Stream" : "πŸ›’ Buy"} β€” ${priceStr}`, ` ${link}`, "", ); } // Warnings if (response.warnings.length > 0) { lines.push(`⚠️ Warnings: ${response.warnings.join(", ")}`); } // Source if (response.source_url) { lines.push(`Source: ${response.source_url}`); } return lines.join("\n"); }
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