Skip to main content
Glama

mcp-youtube

by kirbah
cache.service.ts4.57 kB
import { Collection } from "mongodb"; import { createHash } from "crypto"; import { omitPaths } from "../utils/objectUtils.js"; import { getDb } from "./database.service.js"; // Import the lazy loader /** * A generic structure for entries in our new caching collections. * The data type is templated to allow storing any kind of object. * @template T The type of the data being stored. */ interface GenericCacheEntry<T> { _id: string; // The cache key (can be a direct ID like a videoId, or a hash). data: T; expiresAt: Date; params?: object; // Optional: The arguments used to generate this cache entry (for hashed keys). } export class CacheService { private readonly CACHE_COLLECTION_PREFIX = "yt_cache_"; /** * The core generic caching method. It attempts to retrieve data from the cache using a key. * If the data is not found or is expired, it executes the provided `operation` function, * stores the result back in the cache, and then returns it. * * @template T The type of data being cached. * @param key The unique key for this cache entry (e.g., a 'videoId' or a generated hash). * @param operation An async function that returns the fresh data (type T) to be cached on a miss. * @param ttlSeconds The Time-To-Live for this cache entry, in seconds. * @param collectionName A descriptive name for the MongoDB collection where this data will be stored (e.g., "video_details"). * @param params Optional: Parameters used to generate the hashed keys and stored in cache as params. * @param pathsToExclude Optional: An array of string paths (e.g., "snippet.thumbnails") to exclude from the cached data. * @returns A promise that resolves to the data, either from the cache or freshly generated. */ public async getOrSet<T extends object | null | undefined>( key: string, operation: () => Promise<T>, ttlSeconds: number, collectionName: string, params?: object, pathsToExclude?: string[] ): Promise<T> { if (!process.env.MDB_MCP_CONNECTION_STRING) { // If no DB is configured, bypass caching and execute the operation directly. return operation(); } // Lazily get the database connection here, on first use. const db = await getDb(); const collection: Collection<GenericCacheEntry<T>> = db.collection( `${this.CACHE_COLLECTION_PREFIX}${collectionName}` ); const cachedResult = await collection.findOne({ _id: key, expiresAt: { $gt: new Date() }, }); if (cachedResult) { return cachedResult.data; } const freshData = await operation(); if (freshData === null || freshData === undefined) { return freshData; } // Use your own utility to create the object that will be cached. const dataToCache = pathsToExclude && pathsToExclude.length > 0 ? omitPaths(freshData, pathsToExclude) : freshData; const expiresAt = new Date(Date.now() + ttlSeconds * 1000); const cacheDocument: GenericCacheEntry<T> = { _id: key, data: dataToCache, // Storing the (potentially) smaller object expiresAt, }; if (params) { cacheDocument.params = params; } await collection.updateOne( { _id: key }, { $set: cacheDocument }, { upsert: true } ); return dataToCache; } /** * A helper utility to create a consistent, unique hash key from a function's name and its arguments. * This is ideal for caching the results of complex queries (like video searches) where the * combination of all parameters determines the result. * * @param operationName A unique name for the operation being cached (e.g., "searchVideos"). * @param args An object containing all the arguments for the operation. * @returns A cryptographic SHA256 hash string to be used as a cache key. */ public createOperationKey(operationName: string, args: object): string { // Sort keys of the arguments object to ensure that {a:1, b:2} and {b:2, a:1} produce the same hash. const sortedArgs = Object.keys(args) .sort() .reduce( (obj, key) => { const value = args[key as keyof typeof args]; // Exclude undefined values from the key to prevent ambiguity. if (value !== undefined) { obj[key as keyof typeof args] = value; } return obj; }, {} as typeof args ); const keyString = `${operationName}:${JSON.stringify(sortedArgs)}`; return createHash("sha256").update(keyString).digest("hex"); } }

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/kirbah/mcp-youtube'

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