UNPKG

alphe-redis-mcp-server

Version:

The most comprehensive Redis MCP Server for Alphe.AI - Optimized for sub-5 second response times with multi-layer caching

520 lines (449 loc) • 17.3 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { createClient, RedisClientType } from 'redis'; import { createClient as createSupabaseClient, SupabaseClient } from '@supabase/supabase-js'; import { MilvusClient } from '@zilliz/milvus2-sdk-node'; import dotenv from 'dotenv'; dotenv.config(); interface CognitiveAgent { name: string; model: string; endpoint: string; status: 'idle' | 'busy' | 'error'; lastUsed: number; totalRequests: number; avgLatency: number; } class SimplifiedRedisMCP { private server: Server; private redisClient: RedisClientType | null = null; private supabaseClient: SupabaseClient | null = null; private milvusClient: MilvusClient | null = null; private cognitiveAgents: Map<string, CognitiveAgent> = new Map(); private cache = new Map<string, { data: any; expires: number }>(); constructor() { this.server = new Server( { name: '@alphe-ai/redis-mcp-server', version: '1.0.0' }, { capabilities: { tools: {}, resources: {} } } ); // Initialize cognitive agents const agents = [ { name: 'perception_agent', model: 'gemma2:9b', endpoint: 'http://localhost:11434/api/generate' }, { name: 'context_engineer', model: 'phi3:mini', endpoint: 'http://localhost:11434/api/generate' }, { name: 'planning_agent', model: 'qwq:32b', endpoint: 'http://localhost:11434/api/generate' }, { name: 'reasoning_agent', model: 'deepseek-r1', endpoint: 'http://localhost:11434/api/generate' }, { name: 'reflection_agent', model: 'llama3.3:70b', endpoint: 'http://localhost:11434/api/generate' }, { name: 'orchestrator_agent', model: 'mixtral:8x7b', endpoint: 'http://localhost:11434/api/generate' } ]; agents.forEach(agent => { this.cognitiveAgents.set(agent.name, { ...agent, status: 'idle', lastUsed: 0, totalRequests: 0, avgLatency: 0 }); }); } async initialize(): Promise<void> { try { // Initialize Redis if (process.env.REDIS_URL) { this.redisClient = createClient({ url: process.env.REDIS_URL }); await this.redisClient.connect(); console.log('āœ… Redis connected'); } // Initialize Supabase if (process.env.SUPABASE_URL && process.env.SUPABASE_SERVICE_ROLE_KEY) { this.supabaseClient = createSupabaseClient( process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY ); console.log('āœ… Supabase connected'); } // Initialize Milvus/Zilliz if (process.env.ZILLIZ_TOKEN && process.env.ZILLIZ_ENDPOINT) { this.milvusClient = new MilvusClient({ address: process.env.ZILLIZ_ENDPOINT, token: process.env.ZILLIZ_TOKEN, username: process.env.ZILLIZ_USERNAME, password: process.env.ZILLIZ_PASSWORD, ssl: true }); console.log('āœ… Zilliz connected'); } this.setupHandlers(); console.log('šŸš€ Simplified Redis MCP Server initialized'); // Start cognitive agents activation await this.activateCognitiveAgents(); } catch (error) { console.error('āŒ Failed to initialize:', error); throw error; } } private async activateCognitiveAgents(): Promise<void> { console.log('🧠 Activating cognitive agents...'); const activationPromises = Array.from(this.cognitiveAgents.entries()).map(async ([name, agent]) => { try { agent.status = 'busy'; const startTime = performance.now(); const response = await fetch(agent.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: agent.model, prompt: 'System activation test - respond with "ready"', stream: false, options: { max_tokens: 10, temperature: 0.1 } }), signal: AbortSignal.timeout(5000) }); const latency = performance.now() - startTime; if (response.ok) { const data = await response.json(); agent.status = 'idle'; agent.lastUsed = Date.now(); agent.totalRequests = 1; agent.avgLatency = latency; console.log(`āœ… ${name} (${agent.model}) activated - ${latency.toFixed(2)}ms`); } else { throw new Error(`HTTP ${response.status}`); } } catch (error) { agent.status = 'error'; console.error(`āŒ ${name} failed to activate:`, error); } }); await Promise.allSettled(activationPromises); const activeAgents = Array.from(this.cognitiveAgents.values()).filter(a => a.status !== 'error').length; console.log(`šŸŽÆ ${activeAgents}/6 cognitive agents activated successfully`); // Keep agents warm this.startAgentWarming(); } private startAgentWarming(): void { setInterval(async () => { const idleAgents = Array.from(this.cognitiveAgents.entries()) .filter(([_, agent]) => agent.status === 'idle' && Date.now() - agent.lastUsed > 30000); if (idleAgents.length === 0) return; const agent = idleAgents[Math.floor(Math.random() * idleAgents.length)]; const [name, agentInfo] = agent; try { agentInfo.status = 'busy'; await fetch(agentInfo.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: agentInfo.model, prompt: 'ping', stream: false, options: { max_tokens: 1 } }), signal: AbortSignal.timeout(2000) }); agentInfo.status = 'idle'; agentInfo.lastUsed = Date.now(); console.log(`šŸ”„ Warmed ${name}`); } catch (error) { agentInfo.status = 'error'; console.warn(`āš ļø ${name} warming failed`); } }, 15000); // Every 15 seconds } private async processWithCognition(query: string, context?: any): Promise<any> { console.log('🧠 Processing query through cognitive pipeline...'); const startTime = performance.now(); // Get available agents const availableAgents = Array.from(this.cognitiveAgents.entries()) .filter(([_, agent]) => agent.status === 'idle') .sort((a, b) => a[1].avgLatency - b[1].avgLatency); // Sort by fastest first if (availableAgents.length === 0) { return { response: 'All cognitive agents are busy, using fallback response', latency: performance.now() - startTime, agentsUsed: [], fallback: true }; } // Use top 3 fastest available agents in parallel const selectedAgents = availableAgents.slice(0, Math.min(3, availableAgents.length)); console.log(`šŸš€ Using ${selectedAgents.length} agents in parallel`); const cognitiveResults = await Promise.allSettled( selectedAgents.map(async ([name, agent]) => { agent.status = 'busy'; const taskStart = performance.now(); try { const prompt = this.generatePrompt(name, query, context); const response = await fetch(agent.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: agent.model, prompt, stream: false, options: { max_tokens: 300, temperature: 0.3, top_p: 0.9 } }), signal: AbortSignal.timeout(3000) }); const taskLatency = performance.now() - taskStart; if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); // Update agent metrics agent.totalRequests++; agent.avgLatency = (agent.avgLatency * (agent.totalRequests - 1) + taskLatency) / agent.totalRequests; agent.lastUsed = Date.now(); agent.status = 'idle'; console.log(`āœ… ${name} completed in ${taskLatency.toFixed(2)}ms`); return { agent: name, result: data.response || '', latency: taskLatency, tokens: data.eval_count || 0 }; } catch (error) { agent.status = 'idle'; console.error(`āŒ ${name} failed:`, error); return { agent: name, error: error instanceof Error ? error.message : 'Unknown error' }; } }) ); const successfulResults = cognitiveResults .filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled') .map(result => result.value) .filter(value => !value.error); const totalLatency = performance.now() - startTime; // Generate final response const finalResponse = successfulResults.length > 0 ? `Enhanced Response (${successfulResults.length} agents): ${successfulResults[0].result}` : 'Cognitive processing completed with limited results'; console.log(`šŸŽÆ Cognitive processing completed in ${totalLatency.toFixed(2)}ms`); return { response: finalResponse, latency: totalLatency, agentsUsed: successfulResults.map(r => r.agent), details: successfulResults, fallback: false }; } private generatePrompt(agentName: string, query: string, context?: any): string { const basePrompt = `Query: "${query}"\nContext: ${JSON.stringify(context || {})}\n\n`; switch (agentName) { case 'perception_agent': return basePrompt + 'Extract key intent and entities. Be concise.'; case 'context_engineer': return basePrompt + 'Optimize this query for better understanding. Be concise.'; case 'planning_agent': return basePrompt + 'Create a brief execution plan. Be concise.'; case 'reasoning_agent': return basePrompt + 'Apply logical reasoning. Be concise.'; case 'reflection_agent': return basePrompt + 'Reflect on potential improvements. Be concise.'; case 'orchestrator_agent': return basePrompt + 'Provide a comprehensive response. Be helpful.'; default: return basePrompt + 'Process this query helpfully.'; } } private setupHandlers(): void { // List tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'cognitive_query', description: 'Process queries using parallel cognitive agents for enhanced responses with sub-second latency', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Query to process' }, context: { type: 'object', description: 'Optional context' }, useCache: { type: 'boolean', default: true } }, required: ['query'] } }, { name: 'redis_set', description: 'Set Redis key with multi-layer caching', inputSchema: { type: 'object', properties: { key: { type: 'string' }, value: { type: 'string' }, ttl: { type: 'number', description: 'TTL in seconds' } }, required: ['key', 'value'] } }, { name: 'redis_get', description: 'Get Redis key with intelligent caching', inputSchema: { type: 'object', properties: { key: { type: 'string' } }, required: ['key'] } }, { name: 'get_agent_status', description: 'Get status of all cognitive agents', inputSchema: { type: 'object', properties: {} } } ] })); // List resources this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [ { uri: 'redis://agent-status', name: 'Cognitive Agents Status', mimeType: 'application/json' }, { uri: 'redis://performance', name: 'System Performance', mimeType: 'application/json' } ] })); // Read resource this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; if (uri === 'redis://agent-status') { const agentStatus = Object.fromEntries( Array.from(this.cognitiveAgents.entries()).map(([name, agent]) => [ name, { model: agent.model, status: agent.status, totalRequests: agent.totalRequests, avgLatency: `${agent.avgLatency.toFixed(2)}ms`, lastUsed: agent.lastUsed ? new Date(agent.lastUsed).toISOString() : 'never' } ]) ); return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(agentStatus, null, 2) }] }; } throw new Error(`Resource not found: ${uri}`); }); // Call tool this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { let result; switch (name) { case 'cognitive_query': result = await this.processWithCognition(args?.query, args?.context); break; case 'redis_set': if (this.redisClient && args?.key && args?.value !== undefined) { if (args.ttl) { await this.redisClient.setEx(args.key, args.ttl, String(args.value)); } else { await this.redisClient.set(args.key, String(args.value)); } // Also cache locally this.cache.set(args.key, { data: args.value, expires: Date.now() + (args.ttl || 3600) * 1000 }); result = { success: true, key: args.key, cached: true }; } else { throw new Error('Redis not connected or missing parameters'); } break; case 'redis_get': if (!args?.key) throw new Error('Key required'); // Check local cache first const cached = this.cache.get(args.key); if (cached && cached.expires > Date.now()) { result = { value: cached.data, cached: true, source: 'memory' }; break; } // Check Redis if (this.redisClient) { const value = await this.redisClient.get(args.key); if (value !== null) { // Cache locally this.cache.set(args.key, { data: value, expires: Date.now() + 300000 // 5 minutes }); result = { value, cached: false, source: 'redis' }; } else { result = { value: null, cached: false, source: 'redis' }; } } else { result = { error: 'Redis not connected' }; } break; case 'get_agent_status': const agents = Object.fromEntries( Array.from(this.cognitiveAgents.entries()).map(([name, agent]) => [ name, { model: agent.model, status: agent.status, requests: agent.totalRequests, latency: `${agent.avgLatency.toFixed(2)}ms` } ]) ); result = { agents, timestamp: new Date().toISOString() }; break; default: throw new Error(`Unknown tool: ${name}`); } return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error', tool: name }, null, 2) }], isError: true }; } }); } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.log('šŸŽÆ Redis MCP Server running with active cognitive agents!'); } } async function main() { const server = new SimplifiedRedisMCP(); process.on('SIGINT', () => { console.log('\nšŸ‘‹ Shutting down gracefully...'); process.exit(0); }); await server.initialize(); await server.run(); } if (import.meta.url === `file://${process.argv[1]}`) { main().catch(console.error); }