Skip to main content
Glama

Self-Improving Memory MCP

by SuperPiTT
mcp-server.js18.8 kB
/** * MCP Server Setup * Configures and exports the MCP server with all tool handlers */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { sanitize } from './schemas/validation.js'; /** * Create and configure MCP server with knowledge store * @param {KnowledgeStore} store - The knowledge store instance * @returns {Server} Configured MCP server */ export function createMCPServer(store) { const server = new Server( { name: 'self-improving-memory', version: '2.0.0', }, { capabilities: { tools: {}, }, } ); // Tool definitions server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'save_knowledge', description: 'Save a piece of knowledge (decision, error, solution, pattern, insight) with confidence score', inputSchema: { type: 'object', properties: { type: { type: 'string', enum: ['decision', 'error', 'solution', 'pattern', 'insight'], description: 'Type of knowledge', }, content: { type: 'string', description: 'The knowledge content', }, context: { type: 'string', description: 'Optional context or reasoning', }, confidence: { type: 'number', minimum: 0, maximum: 1, description: 'Confidence level (0-1)', }, verified: { type: 'boolean', description: 'Has this been verified?', default: false, }, tags: { type: 'array', items: { type: 'string' }, description: 'Searchable tags', }, }, required: ['type', 'content', 'confidence', 'tags'], }, }, { name: 'search_knowledge', description: 'Search knowledge base using semantic vector search', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query', }, type: { type: 'string', enum: ['decision', 'error', 'solution', 'pattern', 'insight'], description: 'Filter by type (optional)', }, minConfidence: { type: 'number', minimum: 0, maximum: 1, description: 'Minimum confidence threshold (optional)', }, }, required: ['query'], }, }, { name: 'link_knowledge', description: 'Link related knowledge entries', inputSchema: { type: 'object', properties: { sourceId: { type: 'string' }, targetId: { type: 'string' }, relationship: { type: 'string', default: 'relates_to', }, }, required: ['sourceId', 'targetId'], }, }, { name: 'get_stats', description: 'Get statistics about the knowledge base', inputSchema: { type: 'object', properties: {}, }, }, { name: 'export_markdown', description: 'Export knowledge base to markdown', inputSchema: { type: 'object', properties: {}, }, }, { name: 'export_graph', description: 'Export knowledge graph visualization', inputSchema: { type: 'object', properties: { format: { type: 'string', enum: ['html', 'json', 'dot', 'd3', 'cytoscape'], description: 'Export format (default: html)', default: 'html' }, }, }, }, { name: 'detect_contradictions', description: 'Detect semantic contradictions in knowledge base', inputSchema: { type: 'object', properties: { similarityThreshold: { type: 'number', minimum: 0, maximum: 1, description: 'Similarity threshold for contradiction detection (default: 0.85)', default: 0.85 }, minConfidenceDelta: { type: 'number', minimum: 0, maximum: 1, description: 'Minimum confidence difference to flag (default: 0.1)', default: 0.1 }, sameTypeOnly: { type: 'boolean', description: 'Only check within same type (default: false)', default: false } }, }, }, { name: 'auto_resolve_contradictions', description: 'Automatically resolve all detected contradictions based on confidence', inputSchema: { type: 'object', properties: { similarityThreshold: { type: 'number', minimum: 0, maximum: 1, description: 'Similarity threshold (default: 0.85)', default: 0.85 }, }, }, }, { name: 'get_superseded_history', description: 'Get history of superseded knowledge entries', inputSchema: { type: 'object', properties: {}, }, }, { name: 'analyze_patterns', description: 'Analyze frequency patterns in knowledge base', inputSchema: { type: 'object', properties: {}, }, }, { name: 'generate_insights', description: 'Generate insights and recommendations from knowledge base', inputSchema: { type: 'object', properties: { similarityThreshold: { type: 'number', minimum: 0, maximum: 1, description: 'Clustering similarity threshold (default: 0.75)', default: 0.75 }, minClusterSize: { type: 'number', minimum: 1, description: 'Minimum cluster size (default: 2)', default: 2 } }, }, }, { name: 'detect_antipatterns', description: 'Detect anti-patterns in knowledge base', inputSchema: { type: 'object', properties: {}, }, }, { name: 'suggest_tags', description: 'Get tag suggestions based on content clustering', inputSchema: { type: 'object', properties: { similarityThreshold: { type: 'number', minimum: 0, maximum: 1, description: 'Clustering similarity threshold (default: 0.75)', default: 0.75 } }, }, }, { name: 'cluster_knowledge', description: 'Cluster knowledge entries by semantic similarity', inputSchema: { type: 'object', properties: { similarityThreshold: { type: 'number', minimum: 0, maximum: 1, description: 'Similarity threshold (default: 0.75)', default: 0.75 }, minClusterSize: { type: 'number', minimum: 1, description: 'Minimum cluster size (default: 2)', default: 2 }, maxClusters: { type: 'number', minimum: 1, description: 'Maximum clusters to return (default: 10)', default: 10 } }, }, }, { name: 'get_cache_stats', description: 'Get embedding cache statistics', inputSchema: { type: 'object', properties: {}, }, }, { name: 'clear_cache', description: 'Clear embedding cache', inputSchema: { type: 'object', properties: {}, }, }, { name: 'persist_cache', description: 'Persist embedding cache to disk', inputSchema: { type: 'object', properties: {}, }, }, ], }; }); // Tool handlers server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'save_knowledge': { // Input validation and sanitization const sanitizedContent = sanitize.string(args.content); const sanitizedContext = args.context ? sanitize.string(args.context) : undefined; const sanitizedTags = sanitize.stringArray(args.tags || []); // Validate confidence range const confidence = Number(args.confidence); if (isNaN(confidence) || confidence < 0 || confidence > 1) { throw new Error('Confidence must be a number between 0 and 1'); } // Validate required fields if (!sanitizedContent || sanitizedContent.length === 0) { throw new Error('Content cannot be empty'); } if (!args.type || !['decision', 'error', 'solution', 'pattern', 'insight'].includes(args.type)) { throw new Error('Invalid type. Must be one of: decision, error, solution, pattern, insight'); } const id = await store.addEntry({ type: args.type, content: sanitizedContent, context: sanitizedContext, confidence, verified: args.verified || false, tags: sanitizedTags, }); return { content: [ { type: 'text', text: `Knowledge saved with ID: ${id}`, }, ], }; } case 'search_knowledge': { // Input validation and sanitization const sanitizedQuery = sanitize.string(args.query); if (!sanitizedQuery || sanitizedQuery.length === 0) { throw new Error('Search query cannot be empty'); } if (sanitizedQuery.length > 500) { throw new Error('Search query too long (max 500 characters)'); } // Validate minConfidence if provided if (args.minConfidence !== undefined) { const minConf = Number(args.minConfidence); if (isNaN(minConf) || minConf < 0 || minConf > 1) { throw new Error('minConfidence must be a number between 0 and 1'); } } const results = await store.search(sanitizedQuery, { type: args.type, minConfidence: args.minConfidence, }); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } case 'link_knowledge': { await store.linkEntries( args.sourceId, args.targetId, args.relationship ); return { content: [ { type: 'text', text: `Linked ${args.sourceId} -> ${args.targetId}`, }, ], }; } case 'get_stats': { const stats = await store.getStats(); return { content: [ { type: 'text', text: JSON.stringify(stats, null, 2), }, ], }; } case 'export_markdown': { const exportPath = await store.exportMarkdown(); return { content: [ { type: 'text', text: `Exported to: ${exportPath}`, }, ], }; } case 'export_graph': { const format = args.format || 'html'; if (format === 'html') { const htmlPath = await store.exportGraphVisualization(); return { content: [ { type: 'text', text: `Graph visualization exported to: ${htmlPath}\nOpen this file in your browser to view the interactive graph.`, }, ], }; } else { const graphData = await store.exportGraph(format); return { content: [ { type: 'text', text: graphData, }, ], }; } } case 'detect_contradictions': { const options = { similarityThreshold: args.similarityThreshold || 0.85, minConfidenceDelta: args.minConfidenceDelta || 0.1, sameTypeOnly: args.sameTypeOnly || false }; const contradictions = await store.detectContradictions(options); return { content: [ { type: 'text', text: JSON.stringify({ detected: contradictions.length, contradictions }, null, 2), }, ], }; } case 'auto_resolve_contradictions': { const options = { similarityThreshold: args.similarityThreshold || 0.85 }; const result = await store.autoResolveContradictions(options); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } case 'get_superseded_history': { const history = await store.getSupersededHistory(); return { content: [ { type: 'text', text: JSON.stringify({ superseded: history.length, entries: history }, null, 2), }, ], }; } case 'analyze_patterns': { const analysis = await store.analyzePatterns(); return { content: [ { type: 'text', text: JSON.stringify(analysis, null, 2), }, ], }; } case 'generate_insights': { const options = { similarityThreshold: args.similarityThreshold || 0.75, minClusterSize: args.minClusterSize || 2 }; const result = await store.generateInsights(options); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } case 'detect_antipatterns': { const antiPatterns = await store.detectAntiPatterns(); return { content: [ { type: 'text', text: JSON.stringify({ found: antiPatterns.length, antiPatterns }, null, 2), }, ], }; } case 'suggest_tags': { const options = { similarityThreshold: args.similarityThreshold || 0.75 }; const suggestions = await store.suggestTags(options); return { content: [ { type: 'text', text: JSON.stringify({ suggestions: suggestions.length, tags: suggestions }, null, 2), }, ], }; } case 'cluster_knowledge': { const options = { similarityThreshold: args.similarityThreshold || 0.75, minClusterSize: args.minClusterSize || 2, maxClusters: args.maxClusters || 10 }; const clusters = await store.clusterKnowledge(options); return { content: [ { type: 'text', text: JSON.stringify({ clustersFound: clusters.length, clusters: clusters.map(c => ({ size: c.size, avgConfidence: c.avgConfidence, types: c.types, tags: c.tags, centroid: { id: c.centroid.id, content: c.centroid.content.substring(0, 100) + '...' } })) }, null, 2), }, ], }; } case 'get_cache_stats': { const stats = store.vectorStore.getCacheStats(); return { content: [ { type: 'text', text: JSON.stringify(stats, null, 2), }, ], }; } case 'clear_cache': { store.vectorStore.clearCache(); return { content: [ { type: 'text', text: 'Cache cleared successfully', }, ], }; } case 'persist_cache': { await store.vectorStore.persistCache(); return { content: [ { type: 'text', text: 'Cache persisted to disk successfully', }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error.message}`, }, ], isError: true, }; } }); return server; }

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/SuperPiTT/self-improving-memory-mcp'

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