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
text/typescript
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);
}