Skip to main content
Glama

Self-Improving Memory MCP

by SuperPiTT
graph.js5.59 kB
/** * Knowledge Graph Builder * Creates graph representations of knowledge relationships */ /** * Build knowledge graph from entries * @param {Array} entries - Knowledge entries * @returns {Object} Graph structure with nodes and edges */ export function buildKnowledgeGraph(entries) { const nodes = []; const edges = []; const nodeMap = new Map(); // Create nodes entries.forEach(entry => { const node = { id: entry.id, label: truncateText(entry.content, 50), type: entry.type, confidence: entry.confidence, verified: entry.verified, accessCount: entry.accessCount || 0, tags: entry.tags || [], // Metadata for visualization size: calculateNodeSize(entry), color: getNodeColor(entry.type), shape: getNodeShape(entry.type) }; nodes.push(node); nodeMap.set(entry.id, node); }); // Create edges from relationships entries.forEach(entry => { if (entry.relatedIds && entry.relatedIds.length > 0) { entry.relatedIds.forEach(targetId => { if (nodeMap.has(targetId)) { edges.push({ from: entry.id, to: targetId, label: 'relates_to', arrows: 'to', color: { color: '#999999', opacity: 0.6 } }); } }); } }); return { nodes, edges, stats: { totalNodes: nodes.length, totalEdges: edges.length, nodesByType: countByType(entries), isolatedNodes: nodes.filter(n => !edges.some(e => e.from === n.id || e.to === n.id) ).length } }; } /** * Export graph to various formats */ export function exportGraph(graph, format = 'json') { switch (format) { case 'json': return JSON.stringify(graph, null, 2); case 'cytoscape': return JSON.stringify({ elements: { nodes: graph.nodes.map(n => ({ data: n })), edges: graph.edges.map(e => ({ data: e })) } }, null, 2); case 'dot': return exportToDot(graph); case 'd3': return JSON.stringify({ nodes: graph.nodes, links: graph.edges.map(e => ({ source: e.from, target: e.to, label: e.label })) }, null, 2); default: throw new Error(`Unsupported format: ${format}`); } } /** * Export to Graphviz DOT format */ function exportToDot(graph) { let dot = 'digraph KnowledgeGraph {\n'; dot += ' node [style=filled];\n'; // Add nodes graph.nodes.forEach(node => { const label = node.label.replace(/"/g, '\\"'); const color = node.color; const shape = node.shape; dot += ` "${node.id}" [label="${label}", fillcolor="${color}", shape=${shape}];\n`; }); // Add edges graph.edges.forEach(edge => { dot += ` "${edge.from}" -> "${edge.to}" [label="${edge.label}"];\n`; }); dot += '}\n'; return dot; } /** * Calculate node size based on importance */ function calculateNodeSize(entry) { const baseSize = 20; const confidenceBonus = entry.confidence * 20; const accessBonus = Math.min(entry.accessCount || 0, 10) * 2; const verifiedBonus = entry.verified ? 10 : 0; return baseSize + confidenceBonus + accessBonus + verifiedBonus; } /** * Get node color by type */ function getNodeColor(type) { const colors = { decision: '#4A90E2', // Blue error: '#E74C3C', // Red solution: '#27AE60', // Green pattern: '#9B59B6', // Purple insight: '#F39C12' // Orange }; return colors[type] || '#95A5A6'; // Gray default } /** * Get node shape by type */ function getNodeShape(type) { const shapes = { decision: 'diamond', error: 'box', solution: 'ellipse', pattern: 'hexagon', insight: 'star' }; return shapes[type] || 'dot'; } /** * Truncate text for labels */ function truncateText(text, maxLength) { if (text.length <= maxLength) return text; return text.substring(0, maxLength - 3) + '...'; } /** * Count entries by type */ function countByType(entries) { const counts = {}; entries.forEach(entry => { counts[entry.type] = (counts[entry.type] || 0) + 1; }); return counts; } /** * Find clusters in graph using simple connected components */ export function findClusters(graph) { const visited = new Set(); const clusters = []; graph.nodes.forEach(node => { if (!visited.has(node.id)) { const cluster = []; exploreCluster(node.id, graph, visited, cluster); if (cluster.length > 0) { clusters.push(cluster); } } }); return clusters; } /** * DFS to explore connected component */ function exploreCluster(nodeId, graph, visited, cluster) { if (visited.has(nodeId)) return; visited.add(nodeId); cluster.push(nodeId); // Find all connected nodes graph.edges.forEach(edge => { if (edge.from === nodeId && !visited.has(edge.to)) { exploreCluster(edge.to, graph, visited, cluster); } if (edge.to === nodeId && !visited.has(edge.from)) { exploreCluster(edge.from, graph, visited, cluster); } }); } /** * Get graph statistics */ export function getGraphStats(graph) { const clusters = findClusters(graph); return { ...graph.stats, clusters: clusters.length, largestCluster: Math.max(...clusters.map(c => c.length), 0), avgClusterSize: clusters.length > 0 ? clusters.reduce((sum, c) => sum + c.length, 0) / clusters.length : 0, density: graph.nodes.length > 1 ? graph.edges.length / (graph.nodes.length * (graph.nodes.length - 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/SuperPiTT/self-improving-memory-mcp'

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