Skip to main content
Glama
discovery.ts10.6 kB
import { z } from 'zod'; import { AudiusClient } from '../sdk-client.js'; import { createTextResponse } from '../utils/response.js'; // Schema for get-recommendations tool export const getRecommendationsSchema = { type: 'object', properties: { userId: { type: 'string', description: 'The ID of the user to get recommendations for', }, type: { type: 'string', description: 'Type of recommendations (tracks, users, playlists)', enum: ['tracks', 'users', 'playlists'] }, limit: { type: 'number', description: 'Maximum number of recommendations to return (default: 10)', }, }, required: ['userId'], }; // Schema for get-user-history tool export const getUserHistorySchema = { type: 'object', properties: { userId: { type: 'string', description: 'The ID of the user to get history for', }, type: { type: 'string', description: 'Type of history (plays, likes, reposts, follows)', enum: ['plays', 'likes', 'reposts', 'follows'] }, limit: { type: 'number', description: 'Maximum number of history items to return (default: 20)', }, }, required: ['userId'], }; // Schema for get-trending-by-genre tool export const getTrendingByGenreSchema = { type: 'object', properties: { genre: { type: 'string', description: 'Genre to filter trending content by', }, type: { type: 'string', description: 'Type of content (tracks, playlists, users)', enum: ['tracks', 'playlists', 'users'] }, timeRange: { type: 'string', description: 'Time range for trending (week, month, year, all)', enum: ['week', 'month', 'year', 'all'] }, limit: { type: 'number', description: 'Maximum number of results to return (default: 10)', }, }, required: ['genre'], }; // Implementation of get-recommendations tool export const getRecommendations = async (args: { userId: string, type?: string, limit?: number }) => { try { const type = args.type || 'tracks'; const limit = args.limit || 10; // Construct the API URL for recommendations const baseUrl = 'https://discoveryprovider.audius.co/v1'; const apiUrl = `${baseUrl}/users/${encodeURIComponent(args.userId)}/recommendations/${type}?limit=${limit}`; const response = await fetch(apiUrl, { method: 'GET', headers: { 'Accept': 'application/json' } }); if (!response.ok) { if (response.status === 404) { return createTextResponse(`User with ID '${args.userId}' not found`, true); } return createTextResponse(`Error fetching recommendations: HTTP ${response.status}`, true); } const data = await response.json(); if (!data.data || data.data.length === 0) { return createTextResponse(`No ${type} recommendations found for user ID ${args.userId}`, true); } const recommendations = data.data; // Format recommendations based on type let formattedRecommendations; if (type === 'tracks') { formattedRecommendations = recommendations.map((track: any, index: number) => ( `${index + 1}. "${track.title}" by ${track.user.name}\n` + ` ID: ${track.id} | Duration: ${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}\n` + ` Plays: ${track.playCount || 0} | Likes: ${track.favoriteCount || 0}\n` + ` Reason: ${track.recommendationReason || 'Based on your listening history'}` )).join('\n\n'); } else if (type === 'users') { formattedRecommendations = recommendations.map((user: any, index: number) => ( `${index + 1}. ${user.name} (@${user.handle})\n` + ` ID: ${user.id} | Followers: ${user.followerCount || 0}\n` + ` Tracks: ${user.trackCount || 0} | Genre: ${user.primaryGenre || 'Various'}\n` + ` Reason: ${user.recommendationReason || 'Similar music taste'}` )).join('\n\n'); } else { formattedRecommendations = recommendations.map((playlist: any, index: number) => ( `${index + 1}. "${playlist.playlistName}" by ${playlist.user.name}\n` + ` ID: ${playlist.id} | Tracks: ${playlist.trackCount || 0}\n` + ` Followers: ${playlist.followerCount || 0}\n` + ` Reason: ${playlist.recommendationReason || 'Based on your preferences'}` )).join('\n\n'); } return createTextResponse( `🎯 ${type.charAt(0).toUpperCase() + type.slice(1)} Recommendations for User ID ${args.userId}:\n\n${formattedRecommendations}` ); } catch (error) { console.error('Error in get-recommendations tool:', error); return createTextResponse( `Error fetching recommendations: ${error instanceof Error ? error.message : 'Unknown error'}`, true ); } }; // Implementation of get-user-history tool export const getUserHistory = async (args: { userId: string, type?: string, limit?: number }) => { try { const type = args.type || 'plays'; const limit = args.limit || 20; // Construct the API URL for user history const baseUrl = 'https://discoveryprovider.audius.co/v1'; const apiUrl = `${baseUrl}/users/${encodeURIComponent(args.userId)}/history/${type}?limit=${limit}`; const response = await fetch(apiUrl, { method: 'GET', headers: { 'Accept': 'application/json' } }); if (!response.ok) { if (response.status === 404) { return createTextResponse(`User with ID '${args.userId}' not found`, true); } return createTextResponse(`Error fetching user history: HTTP ${response.status}`, true); } const data = await response.json(); if (!data.data || data.data.length === 0) { return createTextResponse(`No ${type} history found for user ID ${args.userId}`, true); } const history = data.data; // Format history based on type let formattedHistory; const emoji = { plays: '▶️', likes: '❤️', reposts: '🔁', follows: '👥' }[type] || '📝'; if (type === 'plays') { formattedHistory = history.map((item: any, index: number) => ( `${index + 1}. "${item.track.title}" by ${item.track.user.name}\n` + ` Played: ${new Date(item.timestamp).toLocaleString()}\n` + ` Duration: ${Math.floor(item.track.duration / 60)}:${String(item.track.duration % 60).padStart(2, '0')}\n` + ` Play Count: ${item.playCount || 1}` )).join('\n\n'); } else if (type === 'follows') { formattedHistory = history.map((item: any, index: number) => ( `${index + 1}. ${item.user.name} (@${item.user.handle})\n` + ` Followed: ${new Date(item.timestamp).toLocaleString()}\n` + ` Followers: ${item.user.followerCount || 0} | Tracks: ${item.user.trackCount || 0}` )).join('\n\n'); } else { formattedHistory = history.map((item: any, index: number) => ( `${index + 1}. "${item.track.title}" by ${item.track.user.name}\n` + ` ${type.charAt(0).toUpperCase() + type.slice(1, -1)}ed: ${new Date(item.timestamp).toLocaleString()}\n` + ` Track ID: ${item.track.id}` )).join('\n\n'); } return createTextResponse( `${emoji} User ${type.charAt(0).toUpperCase() + type.slice(1)} History for User ID ${args.userId}:\n\n${formattedHistory}` ); } catch (error) { console.error('Error in get-user-history tool:', error); return createTextResponse( `Error fetching user history: ${error instanceof Error ? error.message : 'Unknown error'}`, true ); } }; // Implementation of get-trending-by-genre tool export const getTrendingByGenre = async (args: { genre: string, type?: string, timeRange?: string, limit?: number }) => { try { const type = args.type || 'tracks'; const timeRange = args.timeRange || 'week'; const limit = args.limit || 10; // Construct the API URL for trending by genre const baseUrl = 'https://discoveryprovider.audius.co/v1'; const apiUrl = `${baseUrl}/trending/${type}?genre=${encodeURIComponent(args.genre)}&time=${timeRange}&limit=${limit}`; const response = await fetch(apiUrl, { method: 'GET', headers: { 'Accept': 'application/json' } }); if (!response.ok) { return createTextResponse(`Error fetching trending ${type} for genre ${args.genre}: HTTP ${response.status}`, true); } const data = await response.json(); if (!data.data || data.data.length === 0) { return createTextResponse(`No trending ${type} found for genre "${args.genre}" in the ${timeRange}`, true); } const trending = data.data; // Format trending content based on type let formattedTrending; if (type === 'tracks') { formattedTrending = trending.map((track: any, index: number) => ( `${index + 1}. "${track.title}" by ${track.user.name}\n` + ` ID: ${track.id} | Plays: ${track.playCount || 0} | Likes: ${track.favoriteCount || 0}\n` + ` Duration: ${Math.floor(track.duration / 60)}:${String(track.duration % 60).padStart(2, '0')}\n` + ` Trending Score: ${track.trendingScore || 'N/A'}` )).join('\n\n'); } else if (type === 'users') { formattedTrending = trending.map((user: any, index: number) => ( `${index + 1}. ${user.name} (@${user.handle})\n` + ` ID: ${user.id} | Followers: ${user.followerCount || 0}\n` + ` Tracks: ${user.trackCount || 0} | Playlists: ${user.playlistCount || 0}\n` + ` Growth Score: ${user.growthScore || 'N/A'}` )).join('\n\n'); } else { formattedTrending = trending.map((playlist: any, index: number) => ( `${index + 1}. "${playlist.playlistName}" by ${playlist.user.name}\n` + ` ID: ${playlist.id} | Tracks: ${playlist.trackCount || 0}\n` + ` Followers: ${playlist.followerCount || 0}\n` + ` Trending Score: ${playlist.trendingScore || 'N/A'}` )).join('\n\n'); } return createTextResponse( `🔥 Trending ${type.charAt(0).toUpperCase() + type.slice(1)} in "${args.genre}" (${timeRange}):\n\n${formattedTrending}` ); } catch (error) { console.error('Error in get-trending-by-genre tool:', error); return createTextResponse( `Error fetching trending content: ${error instanceof Error ? error.message : 'Unknown error'}`, true ); } };

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/glassBead-tc/audius-mcp-atris'

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