Skip to main content
Glama

MCP Memory Service

/** * Integration Tests for HTTP-MCP Bridge * * These tests verify the bridge works correctly with a real server * or a mock server that accurately simulates real behavior. */ const assert = require('assert'); const http = require('http'); const https = require('https'); const path = require('path'); const HTTPMCPBridge = require(path.join(__dirname, '../../examples/http-mcp-bridge.js')); const { mockResponses, createMockResponse } = require(path.join(__dirname, '../bridge/mock_responses.js')); describe('Bridge-Server Integration', () => { let bridge; let testServer; let serverPort; before(async () => { // Create a test server that mimics real API behavior await startTestServer(); }); after(async () => { if (testServer) { await new Promise(resolve => testServer.close(resolve)); } }); beforeEach(() => { bridge = new HTTPMCPBridge(); bridge.endpoint = `http://localhost:${serverPort}/api`; bridge.apiKey = 'test-api-key'; }); async function startTestServer() { return new Promise((resolve) => { testServer = http.createServer((req, res) => { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { handleRequest(req, res, body); }); }); testServer.listen(0, 'localhost', () => { serverPort = testServer.address().port; console.log(`Test server started on port ${serverPort}`); resolve(); }); }); } function handleRequest(req, res, body) { const url = req.url; const method = req.method; // Verify API key if (req.headers.authorization !== 'Bearer test-api-key') { res.writeHead(401, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ detail: 'Unauthorized' })); return; } // Route requests if (url === '/api/health' && method === 'GET') { const response = mockResponses.health.healthy; res.writeHead(response.status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response.body)); } else if (url === '/api/memories' && method === 'POST') { try { const data = JSON.parse(body); // Simulate duplicate detection if (data.content === 'duplicate-content') { const response = mockResponses.memories.duplicate; res.writeHead(response.status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response.body)); } else { const response = mockResponses.memories.createSuccess; res.writeHead(response.status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response.body)); } } catch (e) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ detail: 'Invalid JSON' })); } } else if (url.startsWith('/api/search') && method === 'GET') { const response = mockResponses.search.withResults; res.writeHead(response.status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response.body)); } else if (url === '/health' && method === 'GET') { // This is the WRONG endpoint - should return 404 res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ detail: 'Not Found' })); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ detail: 'Not Found' })); } } describe('Critical Bug Scenarios', () => { it('should use /api/health not /health for health checks', async () => { const result = await bridge.checkHealth(); assert.strictEqual(result.status, 'healthy'); assert.strictEqual(result.backend, 'sqlite_vec'); }); it('should handle HTTP 200 with success field for memory storage', async () => { const result = await bridge.storeMemory({ content: 'Test memory content', metadata: { tags: ['test'] } }); assert.strictEqual(result.success, true); assert.strictEqual(result.message, 'Memory stored successfully'); }); it('should handle duplicate detection with HTTP 200 and success=false', async () => { const result = await bridge.storeMemory({ content: 'duplicate-content', metadata: { tags: ['test'] } }); assert.strictEqual(result.success, false); assert.strictEqual(result.message, 'Duplicate content detected'); }); it('should construct URLs correctly with /api base path', async () => { // This would have failed with the old URL construction bug const result = await bridge.retrieveMemory({ query: 'test', n_results: 5 }); assert(Array.isArray(result.memories)); assert(result.memories.length > 0); }); }); describe('End-to-End MCP Protocol Flow', () => { it('should handle complete MCP session', async () => { // 1. Initialize let response = await bridge.processRequest({ method: 'initialize', params: {}, id: 1 }); assert.strictEqual(response.result.protocolVersion, '2024-11-05'); // 2. Get tools list response = await bridge.processRequest({ method: 'tools/list', params: {}, id: 2 }); assert(response.result.tools.length > 0); // 3. Store a memory response = await bridge.processRequest({ method: 'tools/call', params: { name: 'store_memory', arguments: { content: 'Integration test memory', metadata: { tags: ['test', 'integration'] } } }, id: 3 }); const result = JSON.parse(response.result.content[0].text); assert.strictEqual(result.success, true); // 4. Check health response = await bridge.processRequest({ method: 'tools/call', params: { name: 'check_database_health', arguments: {} }, id: 4 }); const health = JSON.parse(response.result.content[0].text); assert.strictEqual(health.status, 'healthy'); }); }); describe('Error Recovery', () => { it('should handle server unavailability gracefully', async () => { // Point to non-existent server bridge.endpoint = 'http://localhost:99999/api'; const result = await bridge.checkHealth(); assert.strictEqual(result.status, 'error'); assert(result.error.includes('ECONNREFUSED')); }); it('should handle malformed responses', async () => { // Create a server that returns invalid JSON const badServer = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('This is not JSON'); }); await new Promise(resolve => { badServer.listen(0, 'localhost', resolve); }); const badPort = badServer.address().port; bridge.endpoint = `http://localhost:${badPort}/api`; const result = await bridge.checkHealth(); assert.strictEqual(result.status, 'error'); await new Promise(resolve => badServer.close(resolve)); }); }); describe('Authentication', () => { it('should include API key in requests', async () => { bridge.apiKey = 'test-api-key'; const result = await bridge.checkHealth(); assert.strictEqual(result.status, 'healthy'); }); it('should handle authentication failures', async () => { bridge.apiKey = 'wrong-api-key'; const result = await bridge.checkHealth(); assert.strictEqual(result.status, 'unhealthy'); }); }); }); // Run tests if this file is executed directly if (require.main === module) { // Simple test runner for development const Mocha = require('mocha'); const mocha = new Mocha(); mocha.addFile(__filename); mocha.run(failures => { process.exit(failures ? 1 : 0); }); }

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/doobidoo/mcp-memory-service'

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