Skip to main content
Glama
kurdin

GitHub Repos Manager MCP Server

analytics.cjs10.4 kB
// src/handlers/analytics.cjs const { getRepoOwnerAndName } = require("../utils/shared-utils.cjs"); const { formatTrafficData, formatLanguagesData, } = require("../utils/formatters.cjs"); const CacheService = require("../services/cache-service.cjs"); // Helper function to handle API calls with caching for data that doesn't need special formatting before returning async function fetchAndCacheGeneric(apiCallBound, cacheKey, ttl, ...apiParams) { let data = CacheService.getFromCache(cacheKey); if (data) { return { success: true, data, source: "cache" }; } data = await apiCallBound(...apiParams); CacheService.setToCache(cacheKey, data, ttl); return { success: true, data, source: "api" }; } module.exports = { get_repo_stats: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const statType = args.type || "traffic"; const cacheTTL = 1600; // Cache for 10 minutes try { let result; let cacheKey; const per = args.per || "day"; switch (statType) { case "clones": cacheKey = CacheService.generateRepoCacheKey( owner, repo, `stats_clones_${per}` ); result = await fetchAndCacheGeneric( apiService.getRepositoryTrafficClones.bind(apiService), cacheKey, cacheTTL, owner, repo, per ); break; case "views": cacheKey = CacheService.generateRepoCacheKey( owner, repo, `stats_views_${per}` ); result = await fetchAndCacheGeneric( apiService.getRepositoryTrafficViews.bind(apiService), cacheKey, cacheTTL, owner, repo, per ); break; case "popular_content": // maps to popular paths cacheKey = CacheService.generateRepoCacheKey( owner, repo, "stats_popular_paths" ); result = await fetchAndCacheGeneric( apiService.getRepositoryPopularPaths.bind(apiService), cacheKey, cacheTTL, owner, repo ); break; case "traffic": default: cacheKey = CacheService.generateRepoCacheKey( owner, repo, `stats_traffic_default_views_${per}` ); result = await fetchAndCacheGeneric( apiService.getRepositoryTrafficViews.bind(apiService), cacheKey, cacheTTL, owner, repo, per ); result.message = result.message ? result.message + " Displaying 'views' data for 'traffic' stat type." : "Displaying 'views' data for 'traffic' stat type."; break; } return result; } catch (error) { return { success: false, message: `Error in get_repo_stats (${statType}): ${error.message}`, error: error.toString(), }; } }, list_repo_topics: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const cacheKey = CacheService.generateRepoCacheKey(owner, repo, "topics"); const cacheTTL = 3600; // 1 hour try { const result = await fetchAndCacheGeneric( apiService.listRepositoryTopics.bind(apiService), cacheKey, cacheTTL, owner, repo ); return result; } catch (error) { return { success: false, message: `Error listing repository topics: ${error.message}`, error: error.toString(), }; } }, update_repo_topics: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const { names } = args; if (!Array.isArray(names)) { return { success: false, message: "Input 'names' must be an array of topics.", }; } try { const data = await apiService.updateRepositoryTopics(owner, repo, names); const cacheKey = CacheService.generateRepoCacheKey(owner, repo, "topics"); CacheService.deleteFromCache(cacheKey); return { success: true, data, message: "Repository topics updated successfully.", }; } catch (error) { return { success: false, message: `Error updating repository topics: ${error.message}`, error: error.toString(), }; } }, get_repo_languages: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const cacheKey = CacheService.generateRepoCacheKey( owner, repo, "languages" ); const cacheTTL = 3600 * 6; // 6 hours try { let rawData = CacheService.getFromCache(cacheKey); if (rawData) { return { success: true, data: formatLanguagesData(rawData), source: "cache", }; } rawData = await apiService.getRepositoryLanguages(owner, repo); CacheService.setToCache(cacheKey, rawData, cacheTTL); return { success: true, data: formatLanguagesData(rawData), source: "api", }; } catch (error) { return { success: false, message: `Error getting repository languages: ${error.message}`, error: error.toString(), }; } }, list_stargazers: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const per_page = args.per_page || 30; const page = args.page || 1; const cacheKey = CacheService.generateRepoCacheKey( owner, repo, `stargazers_p${page}_pp${per_page}` ); const cacheTTL = 3600; // 1 hour try { const result = await fetchAndCacheGeneric( apiService.listStargazers.bind(apiService), cacheKey, cacheTTL, owner, repo, per_page, page ); return result; } catch (error) { return { success: false, message: `Error listing stargazers: ${error.message}`, error: error.toString(), }; } }, list_watchers: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const per_page = args.per_page || 30; const page = args.page || 1; const cacheKey = CacheService.generateRepoCacheKey( owner, repo, `watchers_p${page}_pp${per_page}` ); const cacheTTL = 3600; // 1 hour try { const result = await fetchAndCacheGeneric( apiService.listWatchers.bind(apiService), cacheKey, cacheTTL, owner, repo, per_page, page ); return result; } catch (error) { return { success: false, message: `Error listing watchers: ${error.message}`, error: error.toString(), }; } }, list_forks: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const sort = args.sort || "newest"; const per_page = args.per_page || 30; const page = args.page || 1; const cacheKey = CacheService.generateRepoCacheKey( owner, repo, `forks_s${sort}_p${page}_pp${per_page}` ); const cacheTTL = 3600; // 1 hour try { const result = await fetchAndCacheGeneric( apiService.listForks.bind(apiService), cacheKey, cacheTTL, owner, repo, sort, per_page, page ); return result; } catch (error) { return { success: false, message: `Error listing forks: ${error.message}`, error: error.toString(), }; } }, get_repo_traffic: async (args, defaultRepoDetails, apiService) => { const { owner, repo } = getRepoOwnerAndName(args, defaultRepoDetails); const dataType = args.data_type || "views"; const cacheTTL = 3600; // 1 hour let cacheKeySuffix; const per = args.per || "day"; try { let apiMethodBound; let apiParams = [owner, repo]; switch (dataType) { case "views": cacheKeySuffix = `traffic_views_${per}`; apiMethodBound = apiService.getRepositoryTrafficViews.bind(apiService); apiParams.push(per); break; case "clones": cacheKeySuffix = `traffic_clones_${per}`; apiMethodBound = apiService.getRepositoryTrafficClones.bind(apiService); apiParams.push(per); break; case "popular_referrers": cacheKeySuffix = "traffic_popular_referrers"; apiMethodBound = apiService.getRepositoryPopularReferrers.bind(apiService); break; case "popular_paths": cacheKeySuffix = "traffic_popular_paths"; apiMethodBound = apiService.getRepositoryPopularPaths.bind(apiService); break; default: return { success: false, message: `Invalid data_type for get_repo_traffic: ${dataType}`, }; } const cacheKey = CacheService.generateRepoCacheKey( owner, repo, cacheKeySuffix ); if (dataType === "views") { let rawData = CacheService.getFromCache(cacheKey); if (rawData) { return { success: true, data: formatTrafficData(rawData), source: "cache", }; } rawData = await apiMethodBound(...apiParams); CacheService.setToCache(cacheKey, rawData, cacheTTL); return { success: true, data: formatTrafficData(rawData), source: "api", }; } else { return await fetchAndCacheGeneric( apiMethodBound, cacheKey, cacheTTL, ...apiParams ); } } catch (error) { return { success: false, message: `Error in get_repo_traffic (${dataType}): ${error.message}`, error: error.toString(), }; } }, };

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/kurdin/github-repos-manager-mcp'

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