Skip to main content
Glama

For Five Coffee MCP Server

by Kong
cache.test.js6.53 kB
/** * @jest-environment node */ import { ForFiveCoffeeServer } from '../server.js'; import request from 'supertest'; describe('Menu Caching', () => { let server; let app; beforeEach(() => { server = new ForFiveCoffeeServer(); app = server.app; }); describe('Cache Functionality', () => { it('should start with empty cache', () => { expect(server.menuCache).toBeNull(); expect(server.cacheTimestamp).toBeNull(); expect(server.isCacheValid()).toBe(false); }); it('should cache menu data after first fetch', async () => { // First call should fetch and cache await server.getFullMenu(); expect(server.menuCache).not.toBeNull(); expect(server.cacheTimestamp).not.toBeNull(); expect(server.isCacheValid()).toBe(true); expect(server.menuCache.cached).toBe(true); expect(server.menuCache.items.length).toBeGreaterThan(0); }, 180000); it('should use cached data for subsequent requests', async () => { // First call to populate cache await server.getFullMenu(); const cacheTimestamp = server.cacheTimestamp; // Wait a small amount and make another call await new Promise(resolve => setTimeout(resolve, 100)); const result2 = await server.getFullMenu(); const menuData2 = JSON.parse(result2.content[0].text); // Cache timestamp should be the same (no new fetch) expect(server.cacheTimestamp).toBe(cacheTimestamp); expect(menuData2.cached).toBe(true); }, 180000); it('should clear cache when requested', async () => { // Populate cache await server.getFullMenu(); expect(server.menuCache).not.toBeNull(); // Clear cache const clearResult = await server.clearMenuCache(); const clearData = JSON.parse(clearResult.content[0].text); expect(clearData.message).toContain('cleared successfully'); expect(clearData.hadCache).toBe(true); expect(clearData.itemsCleared).toBeGreaterThan(0); expect(server.menuCache).toBeNull(); expect(server.cacheTimestamp).toBeNull(); }, 180000); it('should have configurable cache expiry', () => { expect(server.cacheExpiryMinutes).toBe(1440); // Default 24 hours (1440 minutes) // Should be able to change expiry server.cacheExpiryMinutes = 60; expect(server.cacheExpiryMinutes).toBe(60); }); }); describe('Cache HTTP Endpoints', () => { it('should provide cache status endpoint', async () => { const response = await request(app).get('/api/cache/status'); expect(response.status).toBe(200); expect(response.body).toHaveProperty('cached'); expect(response.body).toHaveProperty('cacheTimestamp'); expect(response.body).toHaveProperty('cacheAgeMinutes'); expect(response.body).toHaveProperty('expiryMinutes'); expect(response.body).toHaveProperty('valid'); expect(response.body).toHaveProperty('itemCount'); }); it('should provide cache clear endpoint', async () => { const response = await request(app).post('/api/cache/clear'); expect(response.status).toBe(200); expect(response.body).toHaveProperty('message'); expect(response.body.message).toContain('cleared successfully'); expect(response.body).toHaveProperty('timestamp'); }); it('should show cache status after menu fetch', async () => { // Fetch menu to populate cache await request(app).get('/api/menu'); // Check cache status const response = await request(app).get('/api/cache/status'); expect(response.body.cached).toBe(true); expect(response.body.valid).toBe(true); expect(response.body.itemCount).toBeGreaterThan(0); expect(response.body.cacheAgeMinutes).toBeGreaterThanOrEqual(0); }, 180000); it('should update API documentation with cache endpoints', async () => { const response = await request(app).get('/api'); expect(response.body.endpoints).toHaveProperty('GET /api/cache/status'); expect(response.body.endpoints).toHaveProperty('POST /api/cache/clear'); expect(response.body.examples).toHaveProperty('cacheStatus'); }); }); describe('Cache Performance', () => { it('should be faster on cached requests', async () => { // First request (uncached) const start1 = Date.now(); await server.getFullMenu(); const time1 = Date.now() - start1; // Second request (cached) const start2 = Date.now(); await server.getFullMenu(); const time2 = Date.now() - start2; // Cached request should be significantly faster expect(time2).toBeLessThan(time1 / 2); console.log(`Uncached: ${time1}ms, Cached: ${time2}ms`); }, 180000); it('should maintain cache across different tool calls', async () => { // First call to populate cache await server.getFullMenu(); const cacheTimestamp = server.cacheTimestamp; // Different tool calls should use same cache await server.searchMenuItems('coffee'); await server.getMenuCategories(); await server.getItemsByCategory('Espresso Drinks'); // Cache should not have been refreshed expect(server.cacheTimestamp).toBe(cacheTimestamp); }, 180000); }); describe('Cache Expiry', () => { it('should expire cache after configured time', () => { // Set very short expiry for testing server.cacheExpiryMinutes = 0.01; // 0.6 seconds // Manually set cache server.menuCache = { items: [], categories: [] }; server.cacheTimestamp = new Date(Date.now() - 70000); // 70 seconds ago expect(server.isCacheValid()).toBe(false); }); it('should use expired cache as fallback on fetch error', async () => { // Set expired cache server.menuCache = { items: [{ name: 'Test Item', price: '$1.00', category: 'Test' }], categories: ['Test'], }; server.cacheTimestamp = new Date(Date.now() - 3600000); // 1 hour ago // Mock fetch to fail const originalFetch = server.fetchFromAPI; server.fetchFromAPI = async () => { throw new Error('Network error'); }; try { const result = await server.getFullMenu(); const data = JSON.parse(result.content[0].text); // Should use expired cache expect(data.items.length).toBeGreaterThan(0); } finally { // Restore original method server.fetchFromAPI = originalFetch; } }, 180000); }); });

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/Kong/menu-mpc'

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