@codai/memorai-mcp
Version:
MemorAI CBD-based MCP Server - High-Performance Vector Memory System
939 lines (927 loc) • 157 kB
JavaScript
#!/usr/bin/env node
/**
* MemorAI MCP Unified Server - Production-Ready Implementation
*
* Consolidated server combining the best features from all implementations:
* - Correct tool names (*) for VS Code MCP compatibility
* - CBD backend for high-performance and reliability
* - HPKV-inspired architecture with structured keys
* - Advanced semantic search with OpenAI embeddings
* - Performance tracking and analytics
* - Hybrid storage with fallback mechanisms
* - Simplified configuration and startup
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
import { join, resolve } from 'path';
import { randomUUID, createHash } from 'crypto';
import { config } from 'dotenv';
import OpenAI from 'openai';
import packageJson from '../package.json' with { type: 'json' };
import { MemoryRelationshipEngine } from './relationship-engine.js';
import { AdvancedSearchEngine } from './search-intelligence.js';
import { MemoryAnalyticsEngine } from './analytics-engine.js';
import { MemoryRecommendationEngine } from './recommendation-engine.js';
import { MemoryEvolutionEngine } from './evolution-engine.js';
import { RealTimeLearningEngine } from './learning-engine.js';
import { EnhancedPredictiveMemoryEngine } from './enhanced-predictive-engine.js';
import { MemoryFederationEngine } from './federation-engine.js';
export class MemorAIUnifiedServer {
server;
config;
memories = new Map();
dataPath;
isStarted = false;
openai;
// Enhanced engines
relationshipEngine;
searchEngine;
analyticsEngine;
recommendationEngine;
evolutionEngine;
learningEngine;
enhancedPredictiveEngine;
federationEngine;
// Performance tracking
operationCount = 0;
operationTimes = [];
startTime = Date.now();
// Memory analytics
memoryStats = {
totalMemories: 0,
uniqueAgents: new Set(),
uniqueProjects: new Set(),
averageImportance: 0,
};
constructor(config) {
this.config = {
...config,
enableSemanticSearch: config.enableSemanticSearch ?? true,
enablePerformanceTracking: config.enablePerformanceTracking ?? true,
enableHybridStorage: config.enableHybridStorage ?? true,
fallbackStorage: config.fallbackStorage ?? 'json'
};
this.dataPath = this.config.cbdPath;
// Ensure data directory exists
if (!existsSync(this.dataPath)) {
mkdirSync(this.dataPath, { recursive: true });
}
// Initialize OpenAI client
if (this.config.azureOpenAI && this.config.enableSemanticSearch) {
this.openai = new OpenAI({
apiKey: this.config.azureOpenAI.apiKey,
baseURL: `${this.config.azureOpenAI.endpoint}/openai/deployments/${this.config.azureOpenAI.embeddingDeployment}`,
defaultQuery: { 'api-version': this.config.azureOpenAI.apiVersion },
defaultHeaders: {
'api-key': this.config.azureOpenAI.apiKey,
},
});
this.log('info', `🔗 Azure OpenAI initialized with deployment: ${this.config.azureOpenAI.embeddingDeployment}`);
}
else if (this.config.openaiApiKey && this.config.enableSemanticSearch) {
this.openai = new OpenAI({
apiKey: this.config.openaiApiKey,
});
this.log('info', '🔗 OpenAI initialized (fallback mode)');
}
// Initialize enhanced engines
this.relationshipEngine = new MemoryRelationshipEngine(this.openai);
this.searchEngine = new AdvancedSearchEngine(this.openai);
this.analyticsEngine = new MemoryAnalyticsEngine(this.openai, this.memories);
this.recommendationEngine = new MemoryRecommendationEngine(this.openai, this.memories);
this.evolutionEngine = new MemoryEvolutionEngine(this.openai, this.memories);
this.learningEngine = new RealTimeLearningEngine(this.openai, this.memories);
this.enhancedPredictiveEngine = new EnhancedPredictiveMemoryEngine(this.openai, this.memories);
this.federationEngine = new MemoryFederationEngine(this.openai, this.memories);
this.log('info', '🔗 Advanced engines initialized (Relationship + Search + Analytics + Recommendations + Evolution + Learning + Enhanced Prediction + Federation)');
// Initialize MCP Server
this.server = new Server({
name: this.config.serverName,
version: this.config.version,
}, {
capabilities: {
tools: {},
},
});
this.setupHandlers();
this.loadMemories();
this.log('info', `🚀 ${this.config.serverName} initialized`);
}
log(level, message, ...args) {
const timestamp = new Date().toISOString();
console.error(`[${timestamp}] [${level.toUpperCase()}] ${message}`, ...args);
}
/**
* Initialize CBD Service - Check for service availability and optionally start it
*/
async initializeCBDService() {
try {
// Check if CBD service is available
const serviceAvailable = await this.checkCBDService();
if (serviceAvailable) {
this.log('info', 'CBD service is available, will use hybrid mode (service + file fallback)');
return;
}
this.log('info', 'CBD service not available, checking if we can start it locally...');
// Try to start CBD service if possible
const serviceStarted = await this.startCBDService();
if (serviceStarted) {
this.log('info', 'Successfully started local CBD service');
// Wait for service to initialize
await this.sleep(3000);
// Verify it's working
const isWorking = await this.checkCBDService();
if (isWorking) {
this.log('info', 'CBD service is now running and available');
}
else {
this.log('warn', 'CBD service started but not responding, using file-based fallback');
}
}
else {
this.log('info', 'Could not start CBD service, using file-based storage only');
}
}
catch (error) {
this.log('warn', 'CBD service initialization failed, using file-based fallback:', error);
}
}
async checkCBDService() {
try {
const response = await fetch('http://localhost:4180/health', {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
signal: AbortSignal.timeout(3000) // 3 second timeout
});
return response.ok;
}
catch (error) {
return false;
}
}
async startCBDService() {
try {
const { spawn } = await import('child_process');
const { join } = await import('path');
// Look for CBD package in common locations
const cbdPackagePath = this.findCBDPackage();
if (!cbdPackagePath) {
this.log('info', 'CBD package not found locally, trying npx...');
return await this.startCBDViaNPX();
}
this.log('info', `Starting CBD service from: ${cbdPackagePath}`);
// Start CBD service
const cbdProcess = spawn('npm', ['run', 'service'], {
cwd: cbdPackagePath,
stdio: ['ignore', 'pipe', 'pipe'],
shell: true,
detached: false
});
if (cbdProcess.stdout) {
cbdProcess.stdout.on('data', (data) => {
this.log('info', `[CBD] ${data.toString().trim()}`);
});
}
if (cbdProcess.stderr) {
cbdProcess.stderr.on('data', (data) => {
this.log('warn', `[CBD] ${data.toString().trim()}`);
});
}
return true;
}
catch (error) {
this.log('error', 'Failed to start CBD service:', error);
return false;
}
}
async startCBDViaNPX() {
try {
const { spawn } = await import('child_process');
this.log('info', 'Starting CBD service via npx...');
const cbdProcess = spawn('npx', ['@codai/cbd', 'service'], {
stdio: ['ignore', 'pipe', 'pipe'],
shell: true,
detached: false
});
if (cbdProcess.stdout) {
cbdProcess.stdout.on('data', (data) => {
this.log('info', `[CBD-NPX] ${data.toString().trim()}`);
});
}
return true;
}
catch (error) {
this.log('error', 'Failed to start CBD via npx:', error);
return false;
}
}
findCBDPackage() {
try {
const { join } = require('path');
const { existsSync, readFileSync } = require('fs');
// Common paths where CBD package might be located
const possiblePaths = [
// Monorepo structure
join(process.cwd(), '..', '..', 'packages', 'cbd'),
join(process.cwd(), '..', 'packages', 'cbd'),
join(process.cwd(), 'packages', 'cbd'),
// Relative paths
join(__dirname, '..', '..', '..', 'cbd'),
join(__dirname, '..', '..', '..', '..', 'cbd'),
// Environment variable
process.env.CBD_PACKAGE_PATH
].filter(Boolean);
for (const path of possiblePaths) {
try {
const packageJsonPath = join(path, 'package.json');
if (existsSync(packageJsonPath)) {
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
if (packageJson.name === '@codai/cbd') {
this.log('info', `Found CBD package at: ${path}`);
return path;
}
}
}
catch (err) {
// Continue searching
}
}
return null;
}
catch (error) {
this.log('error', 'Error finding CBD package:', error);
return null;
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'remember',
description: 'Store a new memory with metadata',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
content: { type: 'string', description: 'Memory content to store' },
metadata: {
type: 'object',
properties: {
entityType: { type: 'string' },
priority: { type: 'string' },
project: { type: 'string' },
session: { type: 'string' },
tags: { type: 'array', items: { type: 'string' } }
}
}
},
required: ['agentId', 'content'],
},
},
{
name: 'recall',
description: 'Search and retrieve memories',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
query: { type: 'string', description: 'Search query' },
limit: { type: 'number', description: 'Maximum results', default: 10 },
minImportance: { type: 'number', description: 'Minimum importance score', default: 0 },
project: { type: 'string', description: 'Filter by project' },
session: { type: 'string', description: 'Filter by session' }
},
required: ['agentId', 'query'],
},
},
{
name: 'forget',
description: 'Delete a memory by structured key',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
structuredKey: { type: 'string', description: 'Structured key of memory to delete' }
},
required: ['agentId', 'structuredKey'],
},
},
{
name: 'context',
description: 'Get recent context for agent',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
contextSize: { type: 'number', description: 'Number of recent memories', default: 5 }
},
required: ['agentId'],
},
},
{
name: 'get_memory',
description: 'Get memory by exact structured key',
inputSchema: {
type: 'object',
properties: {
structuredKey: { type: 'string', description: 'Exact structured key' }
},
required: ['structuredKey'],
},
},
{
name: 'search_keys',
description: 'Vector similarity search for memory keys',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Query for finding similar memory keys' },
limit: { type: 'number', description: 'Maximum keys to return', default: 10 },
minScore: { type: 'number', description: 'Minimum similarity score', default: 0.7 }
},
required: ['query'],
},
},
{
name: 'link_memories',
description: 'Create a relationship between two memories',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
sourceMemoryKey: { type: 'string', description: 'Structured key of source memory' },
targetMemoryKey: { type: 'string', description: 'Structured key of target memory' },
relationshipType: {
type: 'string',
description: 'Type of relationship',
enum: ['related', 'references', 'follows', 'contradicts', 'updates', 'similar', 'contains', 'explains']
},
strength: { type: 'number', description: 'Relationship strength (0.0-1.0)', default: 0.5 },
context: { type: 'string', description: 'Optional context for the relationship' }
},
required: ['agentId', 'sourceMemoryKey', 'targetMemoryKey', 'relationshipType'],
},
},
{
name: 'get_relationships',
description: 'Get relationships for a memory',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
memoryKey: { type: 'string', description: 'Structured key of memory' },
maxDepth: { type: 'number', description: 'How many relationship hops to traverse', default: 1 },
relationshipTypes: {
type: 'array',
items: { type: 'string' },
description: 'Filter by relationship types'
}
},
required: ['agentId', 'memoryKey'],
},
},
{
name: 'explore_graph',
description: 'Explore the knowledge graph from a starting memory',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
startingMemoryKey: { type: 'string', description: 'Starting point for exploration' },
explorationRadius: { type: 'number', description: 'How far to explore', default: 2 },
includeWeakLinks: { type: 'boolean', description: 'Include weak relationships', default: false }
},
required: ['agentId', 'startingMemoryKey'],
},
},
{
name: 'get_analytics',
description: 'Generate comprehensive analytics and insights for memory usage',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
reportType: {
type: 'string',
description: 'Type of analytics report',
enum: ['usage', 'patterns', 'health', 'gaps', 'recommendations']
},
timeRange: {
type: 'object',
properties: {
start: { type: 'string', description: 'Start date (ISO string)' },
end: { type: 'string', description: 'End date (ISO string)' }
}
},
includeVisualizations: { type: 'boolean', description: 'Include visualization data', default: false }
},
required: ['agentId', 'reportType'],
},
},
{
name: 'get_recommendations',
description: 'Get intelligent recommendations for memory management optimization',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
recommendationType: {
type: 'string',
description: 'Type of recommendations',
enum: ['review', 'create', 'connect', 'cleanup', 'all']
},
maxRecommendations: { type: 'number', description: 'Maximum number of recommendations', default: 10 }
},
required: ['agentId'],
},
},
{
name: 'get_insights',
description: 'Get AI-powered insights about memory patterns and knowledge gaps',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
insightType: {
type: 'string',
description: 'Type of insights to generate',
enum: ['trending_topics', 'memory_clusters', 'knowledge_map', 'activity_heatmap', 'gap_analysis']
},
parameters: {
type: 'object',
description: 'Additional parameters for insight generation'
}
},
required: ['agentId', 'insightType'],
},
},
{
name: 'evolve_memory',
description: 'Automatically update memory based on new information',
inputSchema: {
type: 'object',
properties: {
memoryId: { type: 'string', description: 'Memory ID to evolve' },
newInformation: { type: 'string', description: 'New information to integrate' },
context: {
type: 'object',
properties: {
source: { type: 'string', description: 'Source of new information' },
confidence: { type: 'number', description: 'Confidence in new information (0-1)' },
timestamp: { type: 'string', description: 'Timestamp of new information' }
}
}
},
required: ['memoryId', 'newInformation'],
},
},
{
name: 'resolve_conflicts',
description: 'Detect and resolve conflicts between memories',
inputSchema: {
type: 'object',
properties: {
memoryIds: {
type: 'array',
items: { type: 'string' },
description: 'Memory IDs to check for conflicts'
},
resolutionStrategy: {
type: 'string',
enum: ['auto', 'conservative', 'aggressive'],
description: 'Strategy for conflict resolution'
}
},
required: ['memoryIds'],
},
},
{
name: 'consolidate_memories',
description: 'Consolidate related memories for better organization',
inputSchema: {
type: 'object',
properties: {
memoryIds: {
type: 'array',
items: { type: 'string' },
description: 'Memory IDs to consolidate'
},
consolidationType: {
type: 'string',
enum: ['merge', 'summarize', 'restructure', 'cross_reference'],
description: 'Type of consolidation to perform',
default: 'merge'
}
},
required: ['memoryIds'],
},
},
{
name: 'manage_lifecycle',
description: 'Automatically manage memory lifecycle (archive, promote, clean)',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' }
},
required: ['agentId'],
},
},
// Phase 4: Enhanced Predictive & Learning Tools
{
name: 'predict_enhanced',
description: 'Enhanced memory need prediction with learning integration',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
context: {
type: 'object',
properties: {
currentTask: { type: 'string' },
recentMemories: { type: 'array', items: { type: 'string' } },
timeOfDay: { type: 'string' },
urgency: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }
},
required: ['currentTask']
}
},
required: ['agentId', 'context'],
},
},
{
name: 'predict_structure',
description: 'Predict optimal memory structure based on usage patterns',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' }
},
required: ['agentId'],
},
},
{
name: 'predict_evolution',
description: 'Predict memory evolution with learning-enhanced accuracy',
inputSchema: {
type: 'object',
properties: {
memoryId: { type: 'string', description: 'Memory ID to analyze' },
timeHorizon: { type: 'string', description: 'Time horizon for prediction', default: '1 month' }
},
required: ['memoryId'],
},
},
{
name: 'learn_from_usage',
description: 'Learn from usage patterns to improve future predictions',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
usagePatterns: {
type: 'array',
items: {
type: 'object',
properties: {
memoryId: { type: 'string' },
accessFrequency: { type: 'number' },
successRate: { type: 'number' },
accessTiming: { type: 'array', items: { type: 'string' } },
contextPatterns: { type: 'array', items: { type: 'string' } }
},
required: ['memoryId', 'accessFrequency', 'successRate']
}
}
},
required: ['agentId', 'usagePatterns'],
},
},
{
name: 'adapt_organization',
description: 'Adapt memory organization based on effectiveness metrics',
inputSchema: {
type: 'object',
properties: {
agentId: { type: 'string', description: 'Agent identifier' },
effectivenessMetrics: {
type: 'object',
properties: {
retrievalSuccessRate: { type: 'number' },
averageRetrievalTime: { type: 'number' },
memoryUtilizationRate: { type: 'number' },
contextAccuracy: { type: 'number' },
collaborationEffectiveness: { type: 'number' },
overallSatisfaction: { type: 'number' }
},
required: ['retrievalSuccessRate', 'averageRetrievalTime']
}
},
required: ['agentId', 'effectivenessMetrics'],
},
},
{
name: 'optimize_retrieval',
description: 'Optimize memory retrieval based on query patterns and performance',
inputSchema: {
type: 'object',
properties: {
queryPatterns: {
type: 'array',
items: {
type: 'object',
properties: {
agentId: { type: 'string' },
query: { type: 'string' },
queryType: { type: 'string', enum: ['semantic', 'keyword', 'structured', 'hybrid'] },
frequency: { type: 'number' },
successRate: { type: 'number' }
},
required: ['agentId', 'query', 'frequency', 'successRate']
}
},
performanceMetrics: {
type: 'object',
properties: {
agentId: { type: 'string' },
totalQueries: { type: 'number' },
averageResponseTime: { type: 'number' },
successRate: { type: 'number' },
userSatisfactionScore: { type: 'number' }
},
required: ['agentId', 'totalQueries', 'averageResponseTime']
}
},
required: ['queryPatterns', 'performanceMetrics'],
},
},
{
name: 'share_memory',
description: 'Share a memory with another agent with specific permissions',
inputSchema: {
type: 'object',
properties: {
sourceAgentId: { type: 'string', description: 'Agent sharing the memory' },
targetAgentId: { type: 'string', description: 'Agent receiving the memory' },
memoryId: { type: 'string', description: 'ID of memory to share' },
permissions: {
type: 'object',
properties: {
accessLevel: { type: 'string', enum: ['read', 'read-write', 'admin'] },
expirationTime: { type: 'string' },
allowModification: { type: 'boolean' },
allowDeletion: { type: 'boolean' },
allowSharing: { type: 'boolean' },
contextRestrictions: { type: 'array', items: { type: 'string' } },
projectRestrictions: { type: 'array', items: { type: 'string' } }
},
required: ['accessLevel', 'allowModification', 'allowDeletion', 'allowSharing']
}
},
required: ['sourceAgentId', 'targetAgentId', 'memoryId', 'permissions'],
},
},
{
name: 'federated_query',
description: 'Perform a distributed query across multiple agents',
inputSchema: {
type: 'object',
properties: {
requestingAgentId: { type: 'string', description: 'Agent making the request' },
query: { type: 'string', description: 'Search query' },
targetAgents: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to query' },
queryType: { type: 'string', enum: ['search', 'recommendation', 'insight', 'verification'] },
priority: { type: 'string', enum: ['low', 'medium', 'high', 'urgent'] },
responseTimeout: { type: 'number', description: 'Timeout in seconds' },
aggregationMethod: { type: 'string', enum: ['union', 'intersection', 'weighted', 'consensus'] }
},
required: ['requestingAgentId', 'query', 'targetAgents', 'queryType', 'aggregationMethod'],
},
},
{
name: 'collective_insights',
description: 'Generate collective insights from multiple agents about a topic',
inputSchema: {
type: 'object',
properties: {
participatingAgents: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to include' },
topic: { type: 'string', description: 'Topic for collective analysis' }
},
required: ['participatingAgents', 'topic'],
},
},
{
name: 'collaborative_learning',
description: 'Enable real-time collaborative learning across agents',
inputSchema: {
type: 'object',
properties: {
participatingAgents: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to include' },
learningObjective: { type: 'string', description: 'Objective for collaborative learning' }
},
required: ['participatingAgents', 'learningObjective'],
},
},
{
name: 'synchronize_federation',
description: 'Synchronize memories across federated agents',
inputSchema: {
type: 'object',
properties: {
participatingAgents: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to synchronize' }
},
required: ['participatingAgents'],
},
}
],
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'remember':
return await this.handleRemember(args);
case 'recall':
return await this.handleRecall(args);
case 'forget':
return await this.handleForget(args);
case 'context':
return await this.handleContext(args);
case 'get_memory':
return await this.handleGetMemory(args);
case 'search_keys':
return await this.handleSearchKeys(args);
case 'link_memories':
return await this.handleLinkMemories(args);
case 'get_relationships':
return await this.handleGetRelationships(args);
case 'explore_graph':
return await this.handleExploreGraph(args);
case 'get_analytics':
this.log('info', '=== get_analytics tool called ===');
this.log('info', 'Arguments received:', JSON.stringify(args));
const agentId = args?.agentId || 'unknown';
const reportType = args?.reportType || 'usage';
const timeRange = args?.timeRange || 'week';
const includePatterns = args?.includePatterns !== false;
try {
// Comprehensive memory analysis with safe operations
let memoryCount = 0;
let totalRelationships = 0;
let totalImportance = 0;
const projects = new Set();
const entityTypes = new Set();
const priorities = new Map();
for (const [key, memory] of this.memories.entries()) {
if (memory?.metadata?.agentId === agentId) {
memoryCount++;
// Safe relationship counting
if (memory.relationships && Array.isArray(memory.relationships)) {
totalRelationships += memory.relationships.length;
}
// Safe importance accumulation
if (typeof memory.metadata?.importance === 'number') {
totalImportance += memory.metadata.importance;
}
else {
totalImportance += 0.5; // default importance
}
// Safe metadata extraction
if (memory.metadata?.project) {
projects.add(memory.metadata.project);
}
if (memory.metadata?.entityType) {
entityTypes.add(memory.metadata.entityType);
}
if (memory.metadata?.priority) {
const priority = memory.metadata.priority;
priorities.set(priority, (priorities.get(priority) || 0) + 1);
}
}
}
const avgImportance = memoryCount > 0 ? totalImportance / memoryCount : 0;
const avgRelationships = memoryCount > 0 ? totalRelationships / memoryCount : 0;
// Calculate health scores
const overallHealth = memoryCount > 0 ?
Math.min(100, Math.round((avgImportance * 40) + (avgRelationships * 30) + 30)) : 0;
const organizationScore = Math.min(100, projects.size * 20);
const contentQuality = Math.min(100, entityTypes.size * 25);
const result = {
content: [{
type: 'text',
text: `Memory Analytics Report for Agent: ${agentId}
CONFIGURATION:
• Report Type: ${reportType}
• Time Range: ${timeRange}
• Include Patterns: ${includePatterns}
• Timestamp: ${new Date().toISOString()}
USAGE METRICS:
• Total Memories: ${memoryCount}
• Average Importance: ${avgImportance.toFixed(2)}
• Total Relationships: ${totalRelationships}
• Avg Relationships per Memory: ${avgRelationships.toFixed(1)}
ORGANIZATION:
• Projects: ${projects.size} (${Array.from(projects).slice(0, 3).join(', ')}${projects.size > 3 ? `, +${projects.size - 3} more` : ''})
• Entity Types: ${entityTypes.size} (${Array.from(entityTypes).slice(0, 3).join(', ')}${entityTypes.size > 3 ? `, +${entityTypes.size - 3} more` : ''})
• Priority Distribution: ${Array.from(priorities.entries()).map(([p, c]) => `${p}(${c})`).join(', ') || 'None set'}
HEALTH SCORES:
• Overall Health: ${overallHealth}%
• Organization Score: ${organizationScore}%
• Content Quality: ${contentQuality}%
• Relationship Quality: ${totalRelationships > 0 ? Math.min(100, avgRelationships * 50) : 0}%
INSIGHTS:
• Memory Activity: ${memoryCount > 0 ? 'Active' : 'No memories found'}
• Data Quality: ${avgImportance > 0.7 ? 'Excellent' : avgImportance > 0.5 ? 'Good' : avgImportance > 0.3 ? 'Fair' : 'Needs improvement'}
• Organization Level: ${projects.size > 3 ? 'Well organized' : projects.size > 1 ? 'Moderate organization' : 'Basic organization'}
• Connectivity: ${avgRelationships > 2 ? 'Highly connected' : avgRelationships > 1 ? 'Well connected' : avgRelationships > 0 ? 'Some connections' : 'Isolated memories'}
Analytics completed successfully in ${Date.now() - Date.now()}ms.`
}]
};
this.log('info', '=== get_analytics completed successfully ===');
return result;
}
catch (error) {
this.log('error', '=== get_analytics failed ===', error);
return {
content: [{
type: 'text',
text: `Analytics Error for Agent: ${agentId}
Error: ${error?.message || 'Unknown error'}
Report Type: ${reportType}
Time Range: ${timeRange}
System Memory Count: ${this.memories.size}
Please check the server logs for more details.
Stack trace: ${error?.stack || 'Not available'}`
}]
};
}
case 'get_recommendations':
return await this.handleGetRecommendations(args);
case 'get_insights':
this.log('info', '=== get_insights tool called ===');
this.log('info', 'Arguments received:', JSON.stringify(args));
const insightsAgentId = args?.agentId || 'unknown';
const insightType = args?.insightType || 'trending_topics';
const includeParameters = args?.parameters || {};
try {
// Simple insights generation without complex analytics engine
let memoryCount = 0;
const topics = new Map();
const projects = new Set();
const entityTypes = new Set();
const importanceScores = [];
const recentMemories = [];
for (const [key, memory] of this.memories.entries()) {
if (memory?.metadata?.agentId === insightsAgentId) {
memoryCount++;
// Extract topics from content (simple word frequency)
if (memory.content) {
const words = memory.content.toLowerCase()
.split(/\s+/)
.filter(word => word.length > 4)
.slice(0, 10); // top 10 words
words.forEach(word => {
topics.set(word, (topics.get(word) || 0) + 1);
});
}
// Collect metadata
if (memory.metadata?.project)
projects.add(memory.metadata.project);
if (memory.metadata?.entityType)
entityTypes.add(memory.metadata.entityType);
if (typeof memory.metadata?.importance === 'number') {
importanceScores.push(memory.metadata.importance);
}
// Track recent memories (basic)
recentMemories.push({
key: memory.structuredKey,
content: memory.content.substring(0, 100) + '...',
importance: memory.metadata?.importance || 0.5
});
}
}
// Generate insights based on type
let insightContent = '';
switch (insightType) {
case 'trending_topics':
const topTopics = Array.from(topics.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 5);
insightContent = `Trending Topics Analysis for Agent: ${insightsAgentId}
TOP TRENDING TOPICS:
${topTopics.map((topic, i) => `${i + 1}. "${topic[0]}" (mentioned ${topic[1]} times)`).join('\n')}
TOPIC INSIGHTS:
• Most frequent topic: ${topTopics[0] ? topTopics[0][0] : 'No data'}
• Topic diversity: ${topics.size} unique topics identified
• Content richness: ${topics.size > 10 ? 'High' : topics.size > 5 ? 'Moderate' : 'Low'}`;
break;
case 'memory_clusters':