Skip to main content
Glama
danielsimonjr

Enhanced Knowledge Graph Memory Server

REFACTORING_PLAN.md48.5 kB
# Index.ts Refactoring Plan ## Executive Summary This document outlines a comprehensive plan to refactor the monolithic `src/memory/index.ts` file (4,187 lines) into a modular, maintainable architecture. The refactoring will improve code organization, testability, maintainability, and developer experience while preserving all existing functionality. **Current State**: Single 4,187-line file containing: - 13 TypeScript interfaces and types - 1 massive KnowledgeGraphManager class with 59 methods - 45 MCP tool definitions - 41 tool request handlers - Server initialization and bootstrapping code **Target State**: Modular architecture with 15-20 focused files organized by functional domain. --- ## Current State Analysis ### File Statistics - **Total Lines**: 4,187 - **Interfaces/Types**: 13 - **Class Methods**: 59 async methods - **MCP Tools**: 45 tools (309% more than official MCP memory server) - **Code Complexity**: Very High - **Maintainability**: Low - **Test Coverage**: Limited (only 2 test files) ### Pain Points 1. **Navigation Difficulty**: Finding specific functionality requires extensive scrolling 2. **Merge Conflicts**: High probability in team environments 3. **Testing Challenges**: Difficult to isolate and test individual components 4. **Code Reuse**: Hard to extract and reuse utility functions 5. **Onboarding**: New developers face steep learning curve 6. **IDE Performance**: Large files can slow down IntelliSense and linting 7. **Circular Dependencies**: Risk increases with monolithic structure 8. **Version Control**: Difficult to track changes to specific features ### Functional Breakdown The file contains the following functional domains: | Domain | Methods | Complexity | Lines (est) | |--------|---------|------------|-------------| | Core CRUD | 8 | Medium | 400 | | Search Operations | 6 | High | 800 | | Tag Management | 9 | Medium | 500 | | Hierarchy Operations | 9 | High | 600 | | Analytics & Validation | 2 | Medium | 300 | | Saved Searches | 6 | Medium | 300 | | Compression & Deduplication | 3 | High | 400 | | Archiving | 1 | Medium | 150 | | Import/Export | 2 | Very High | 850 | | Search Utilities | 10+ | High | 500 | | Server & Tools | - | Medium | 1200 | | Types & Interfaces | - | Low | 187 | --- ## Proposed Architecture ### Design Principles 1. **Single Responsibility**: Each module handles one functional domain 2. **Separation of Concerns**: Types, business logic, and API layer separated 3. **Dependency Injection**: Manager classes receive dependencies via constructor 4. **Testability**: Pure functions and mockable dependencies 5. **Gradual Migration**: Refactor incrementally without breaking changes 6. **Backward Compatibility**: Maintain all existing APIs 7. **File Size Constraint**: **ALL files MUST be under 500 lines** (including tests) ### Module Organization Strategy ``` src/memory/ ├── index.ts # Entry point - server initialization (<50 lines) ├── types/ # TypeScript types and interfaces │ ├── index.ts # Re-exports all types (<50 lines) │ ├── entity.types.ts # Entity, Relation, KnowledgeGraph (<100 lines) │ ├── search.types.ts # SearchResult, SavedSearch, BooleanQueryNode (<100 lines) │ ├── analytics.types.ts # GraphStats, ValidationReport, ValidationError (<150 lines) │ ├── import-export.types.ts # ImportResult, CompressionResult (<50 lines) │ └── tag.types.ts # TagAlias (<50 lines) ├── core/ # Core business logic │ ├── KnowledgeGraphManager.ts # Main manager - facade pattern (<350 lines) │ ├── GraphStorage.ts # File I/O operations (<150 lines) │ ├── EntityManager.ts # CRUD for entities (<200 lines) │ ├── RelationManager.ts # CRUD for relations (<150 lines) │ └── ObservationManager.ts # CRUD for observations (<100 lines) ├── search/ # Search functionality │ ├── SearchManager.ts # Orchestrates all search operations (<200 lines) │ ├── BasicSearch.ts # searchNodes, openNodes (<200 lines) │ ├── RankedSearch.ts # TF-IDF ranking algorithm (<300 lines) │ ├── BooleanSearch.ts # Boolean query parsing and evaluation (<350 lines) │ ├── FuzzySearch.ts # Fuzzy matching with Levenshtein (<150 lines) │ ├── SearchSuggestions.ts # Auto-complete suggestions (<150 lines) │ └── SavedSearchManager.ts # Saved search operations (<200 lines) ├── features/ # Feature-specific managers │ ├── TagManager.ts # Tag operations and aliases (<400 lines) │ ├── ImportanceManager.ts # Importance level operations (<50 lines) │ ├── HierarchyManager.ts # Parent-child relationships (<450 lines) │ ├── AnalyticsManager.ts # Statistics and validation (<300 lines) │ ├── CompressionManager.ts # Deduplication and merging (<400 lines) │ ├── ArchiveManager.ts # Archiving operations (<150 lines) │ └── import-export/ # Multi-format import/export (subdivided) │ ├── ImportExportManager.ts # Orchestrator (<150 lines) │ ├── ExportManager.ts # Export orchestration (<200 lines) │ ├── ImportManager.ts # Import orchestration (<200 lines) │ └── formats/ # Format-specific handlers │ ├── JSONExporter.ts # (<100 lines) │ ├── JSONImporter.ts # (<100 lines) │ ├── CSVExporter.ts # (<150 lines) │ ├── CSVImporter.ts # (<200 lines) │ ├── GraphMLExporter.ts # (<200 lines) │ ├── GraphMLImporter.ts # (<200 lines) │ ├── GEXFExporter.ts # (<200 lines) │ ├── DOTExporter.ts # (<150 lines) │ ├── MarkdownExporter.ts # (<150 lines) │ └── MermaidExporter.ts # (<150 lines) ├── utils/ # Utility functions │ ├── levenshtein.ts # String distance calculations (<50 lines) │ ├── tfidf.ts # TF-IDF algorithms (<150 lines) │ ├── dateUtils.ts # Date range filtering (<100 lines) │ ├── validationUtils.ts # Data validation helpers (<150 lines) │ └── pathUtils.ts # File path management (<100 lines) ├── mcp/ # MCP Server setup │ ├── server.ts # Server initialization (<100 lines) │ ├── tools/ # Tool definitions (each <200 lines) │ │ ├── index.ts # Tool registry (<100 lines) │ │ ├── entity.tools.ts # Entity CRUD tool definitions (<150 lines) │ │ ├── search.tools.ts # Search tool definitions (<250 lines) │ │ ├── tag.tools.ts # Tag tool definitions (<300 lines) │ │ ├── hierarchy.tools.ts # Hierarchy tool definitions (<250 lines) │ │ ├── analytics.tools.ts # Analytics tool definitions (<100 lines) │ │ └── import-export.tools.ts # Import/Export tool definitions (<250 lines) │ └── handlers/ # Tool request handlers (each <250 lines) │ ├── index.ts # Handler registry (<150 lines) │ ├── entity.handlers.ts # Entity tool handlers (<150 lines) │ ├── search.handlers.ts # Search tool handlers (<250 lines) │ ├── tag.handlers.ts # Tag tool handlers (<250 lines) │ ├── hierarchy.handlers.ts # Hierarchy tool handlers (<200 lines) │ ├── analytics.handlers.ts # Analytics tool handlers (<100 lines) │ └── import-export.handlers.ts # Import/Export tool handlers (<200 lines) ├── __tests__/ # Tests (each test file <400 lines) │ ├── unit/ # Unit tests │ │ ├── core/ │ │ │ ├── EntityManager.test.ts # (<300 lines) │ │ │ ├── RelationManager.test.ts # (<250 lines) │ │ │ ├── ObservationManager.test.ts # (<200 lines) │ │ │ └── GraphStorage.test.ts # (<250 lines) │ │ ├── search/ │ │ │ ├── BasicSearch.test.ts # (<300 lines) │ │ │ ├── RankedSearch.test.ts # (<350 lines) │ │ │ ├── BooleanSearch.test.ts # (<400 lines) │ │ │ └── FuzzySearch.test.ts # (<250 lines) │ │ ├── features/ │ │ │ ├── TagManager.test.ts # (<400 lines) │ │ │ ├── HierarchyManager.test.ts # (<400 lines) │ │ │ ├── CompressionManager.test.ts # (<350 lines) │ │ │ └── ArchiveManager.test.ts # (<250 lines) │ │ └── utils/ │ │ ├── levenshtein.test.ts # (<100 lines) │ │ ├── tfidf.test.ts # (<150 lines) │ │ └── dateUtils.test.ts # (<100 lines) │ ├── integration/ # Integration tests (each <400 lines) │ │ ├── entity-operations.test.ts # (<350 lines) │ │ ├── search-operations.test.ts # (<400 lines) │ │ ├── hierarchy-operations.test.ts # (<350 lines) │ │ └── import-export.test.ts # (<400 lines) │ └── performance/ # Performance tests (each <300 lines) │ ├── search-benchmark.test.ts # (<300 lines) │ └── large-graph.test.ts # (<250 lines) └── config/ # Configuration └── constants.ts # Constants and defaults (<100 lines) ``` **File Size Guarantee**: ALL files will be under 500 lines. Large modules are subdivided further. --- ## Detailed Module Breakdown ### 1. Types Module (`src/memory/types/`) **Purpose**: Centralize all TypeScript type definitions **Files**: #### `entity.types.ts` ```typescript export interface Entity { name: string; entityType: string; observations: string[]; createdAt?: string; lastModified?: string; tags?: string[]; importance?: number; parentId?: string; } export interface Relation { from: string; to: string; relationType: string; createdAt?: string; lastModified?: string; } export interface KnowledgeGraph { entities: Entity[]; relations: Relation[]; } ``` #### `search.types.ts` ```typescript export interface SearchResult { entity: Entity; score: number; matchedFields: { name?: boolean; entityType?: boolean; observations?: string[]; }; } export interface SavedSearch { name: string; description?: string; query: string; tags?: string[]; minImportance?: number; maxImportance?: number; entityType?: string; createdAt: string; lastUsed?: string; useCount: number; } export type BooleanQueryNode = | { type: 'AND'; children: BooleanQueryNode[] } | { type: 'OR'; children: BooleanQueryNode[] } | { type: 'NOT'; child: BooleanQueryNode } | { type: 'TERM'; field?: string; value: string }; ``` #### `analytics.types.ts` ```typescript export interface GraphStats { totalEntities: number; totalRelations: number; entityTypesCounts: Record<string, number>; relationTypesCounts: Record<string, number>; oldestEntity?: { name: string; date: string }; newestEntity?: { name: string; date: string }; oldestRelation?: { from: string; to: string; relationType: string; date: string }; newestRelation?: { from: string; to: string; relationType: string; date: string }; entityDateRange?: { earliest: string; latest: string }; relationDateRange?: { earliest: string; latest: string }; } export interface ValidationReport { isValid: boolean; errors: ValidationError[]; warnings: ValidationWarning[]; summary: { totalErrors: number; totalWarnings: number; orphanedRelationsCount: number; entitiesWithoutRelationsCount: number; }; } export interface ValidationError { type: 'orphaned_relation' | 'duplicate_entity' | 'invalid_data'; message: string; details?: any; } export interface ValidationWarning { type: 'isolated_entity' | 'empty_observations' | 'missing_metadata'; message: string; details?: any; } ``` #### `import-export.types.ts` ```typescript export interface ImportResult { entitiesAdded: number; entitiesSkipped: number; entitiesUpdated: number; relationsAdded: number; relationsSkipped: number; errors: string[]; } export interface CompressionResult { duplicatesFound: number; entitiesMerged: number; observationsCompressed: number; relationsConsolidated: number; spaceFreed: number; mergedEntities: Array<{ kept: string; merged: string[] }>; } ``` #### `tag.types.ts` ```typescript export interface TagAlias { alias: string; canonical: string; description?: string; createdAt: string; } ``` **Benefits**: - Single source of truth for types - Easy to import and reuse - Better IDE autocomplete - Simpler type refactoring --- ### 2. Core Module (`src/memory/core/`) **Purpose**: Handle core business logic and data persistence #### `GraphStorage.ts` **Responsibility**: File I/O operations, backward compatibility **Methods**: - `loadGraph(): Promise<KnowledgeGraph>` - `saveGraph(graph: KnowledgeGraph): Promise<void>` - `ensureMemoryFilePath(): Promise<string>` **Size**: ~150 lines **Dependencies**: fs, path, types #### `EntityManager.ts` **Responsibility**: Entity CRUD operations **Methods**: - `createEntities(entities: Entity[]): Promise<Entity[]>` - `deleteEntities(entityNames: string[]): Promise<void>` - `getEntity(name: string): Promise<Entity | null>` - `updateEntity(name: string, updates: Partial<Entity>): Promise<Entity>` **Size**: ~200 lines **Dependencies**: GraphStorage, types #### `RelationManager.ts` **Responsibility**: Relation CRUD operations **Methods**: - `createRelations(relations: Relation[]): Promise<Relation[]>` - `deleteRelations(relations: Relation[]): Promise<void>` - `getRelations(entityName: string): Promise<Relation[]>` **Size**: ~150 lines **Dependencies**: GraphStorage, types #### `ObservationManager.ts` **Responsibility**: Observation CRUD operations **Methods**: - `addObservations(observations: {...}[]): Promise<{...}[]>` - `deleteObservations(deletions: {...}[]): Promise<void>` **Size**: ~100 lines **Dependencies**: GraphStorage, types #### `KnowledgeGraphManager.ts` **Responsibility**: Facade pattern - orchestrates all managers **Methods**: Delegates to specialized managers **Size**: ~300 lines (much smaller than current 3000+) **Dependencies**: All managers **Pattern**: Composition over inheritance ```typescript export class KnowledgeGraphManager { private storage: GraphStorage; private entityManager: EntityManager; private relationManager: RelationManager; private observationManager: ObservationManager; private searchManager: SearchManager; private tagManager: TagManager; private hierarchyManager: HierarchyManager; // ... other managers constructor(memoryFilePath: string) { this.storage = new GraphStorage(memoryFilePath); this.entityManager = new EntityManager(this.storage); this.relationManager = new RelationManager(this.storage); // ... initialize other managers } // Delegate methods to appropriate managers async createEntities(entities: Entity[]): Promise<Entity[]> { return this.entityManager.createEntities(entities); } async searchNodes(query: string, ...): Promise<KnowledgeGraph> { return this.searchManager.searchNodes(query, ...); } // ... etc } ``` --- ### 3. Search Module (`src/memory/search/`) **Purpose**: All search-related functionality #### `SearchManager.ts` **Responsibility**: Orchestrate search operations **Methods**: - `searchNodes(query, tags?, ...): Promise<KnowledgeGraph>` - `openNodes(names: string[]): Promise<KnowledgeGraph>` - `searchByDateRange(...): Promise<KnowledgeGraph>` **Size**: ~200 lines #### `RankedSearch.ts` **Responsibility**: TF-IDF ranking algorithm **Methods**: - `searchNodesRanked(query, ...): Promise<SearchResult[]>` - `calculateTFIDF(query: string, entities: Entity[]): Map<Entity, number>` - `calculateIDF(term: string, entities: Entity[]): number` - `calculateTF(term: string, entity: Entity): number` **Size**: ~300 lines #### `BooleanSearch.ts` **Responsibility**: Boolean query parsing and evaluation **Methods**: - `booleanSearch(query: string, ...): Promise<KnowledgeGraph>` - `parseBooleanQuery(query: string): BooleanQueryNode` - `evaluateBooleanQuery(node: BooleanQueryNode, entity: Entity): boolean` - `tokenize(query: string): Token[]` **Size**: ~350 lines #### `FuzzySearch.ts` **Responsibility**: Fuzzy matching with Levenshtein distance **Methods**: - `fuzzySearch(query: string, threshold?: number, ...): Promise<KnowledgeGraph>` - `isFuzzyMatch(str1: string, str2: string, threshold: number): boolean` **Size**: ~150 lines **Dependencies**: utils/levenshtein.ts #### `SearchSuggestions.ts` **Responsibility**: Auto-complete and search suggestions **Methods**: - `getSearchSuggestions(query: string, maxSuggestions?: number): Promise<string[]>` - `generateTriGrams(text: string): Set<string>` - `triGramSimilarity(text1: string, text2: string): number` **Size**: ~150 lines #### `SavedSearchManager.ts` **Responsibility**: Saved search operations **Methods**: - `saveSearch(search: Omit<SavedSearch, ...>): Promise<SavedSearch>` - `listSavedSearches(): Promise<SavedSearch[]>` - `getSavedSearch(name: string): Promise<SavedSearch | null>` - `executeSavedSearch(name: string): Promise<KnowledgeGraph>` - `deleteSavedSearch(name: string): Promise<boolean>` - `updateSavedSearch(name: string, updates: ...): Promise<SavedSearch>` **Size**: ~200 lines --- ### 4. Features Module (`src/memory/features/`) **Purpose**: Feature-specific managers for advanced functionality #### `TagManager.ts` **Responsibility**: Tag operations and aliases **Methods**: - `addTags(entityName: string, tags: string[]): Promise<{...}>` - `removeTags(entityName: string, tags: string[]): Promise<{...}>` - `addTagsToMultipleEntities(entityNames: string[], tags: string[]): Promise<{...}[]>` - `replaceTag(oldTag: string, newTag: string): Promise<{...}>` - `mergeTags(tag1: string, tag2: string, targetTag: string): Promise<{...}>` - `resolveTag(tag: string): Promise<string>` - `addTagAlias(alias: string, canonical: string, description?: string): Promise<TagAlias>` - `listTagAliases(): Promise<TagAlias[]>` - `removeTagAlias(alias: string): Promise<boolean>` - `getAliasesForTag(canonicalTag: string): Promise<string[]>` **Size**: ~400 lines #### `ImportanceManager.ts` **Responsibility**: Importance level operations **Methods**: - `setImportance(entityName: string, importance: number): Promise<{...}>` **Size**: ~50 lines #### `HierarchyManager.ts` **Responsibility**: Parent-child relationships **Methods**: - `setEntityParent(entityName: string, parentName: string | null): Promise<Entity>` - `getChildren(entityName: string): Promise<Entity[]>` - `getParent(entityName: string): Promise<Entity | null>` - `getAncestors(entityName: string): Promise<Entity[]>` - `getDescendants(entityName: string): Promise<Entity[]>` - `getSubtree(entityName: string): Promise<KnowledgeGraph>` - `getRootEntities(): Promise<Entity[]>` - `getEntityDepth(entityName: string): Promise<number>` - `moveEntity(entityName: string, newParentName: string | null): Promise<Entity>` **Size**: ~500 lines #### `AnalyticsManager.ts` **Responsibility**: Statistics and validation **Methods**: - `getGraphStats(): Promise<GraphStats>` - `validateGraph(): Promise<ValidationReport>` **Size**: ~300 lines #### `CompressionManager.ts` **Responsibility**: Deduplication and merging **Methods**: - `findDuplicates(threshold?: number): Promise<string[][]>` - `mergeEntities(entityNames: string[], targetName?: string): Promise<Entity>` - `compressGraph(threshold?: number, dryRun?: boolean): Promise<CompressionResult>` - `calculateSimilarity(e1: Entity, e2: Entity): number` **Size**: ~400 lines **Dependencies**: utils/levenshtein.ts #### `ArchiveManager.ts` **Responsibility**: Archiving operations **Methods**: - `archiveEntities(criteria: {...}, dryRun?: boolean): Promise<ImportResult>` **Size**: ~150 lines #### `ImportExportManager.ts` **Responsibility**: Multi-format import/export orchestration **Methods**: - `exportGraph(format: '...', filter?: {...}): Promise<string>` - `importGraph(format: '...', data: string, mergeStrategy?: '...', dryRun?: boolean): Promise<ImportResult>` **Size**: ~150 lines (delegates to format-specific modules) **Note**: This is split into multiple submodules to stay under 500 lines: ##### `features/import-export/ExportManager.ts` (~200 lines) - Orchestrates all export formats - Applies filters before export - Delegates to format-specific exporters ##### `features/import-export/ImportManager.ts` (~200 lines) - Orchestrates all import formats - Handles merge strategies - Validates imported data ##### `features/import-export/formats/JSONExporter.ts` (~100 lines) - `exportJSON(graph: KnowledgeGraph): string` ##### `features/import-export/formats/CSVExporter.ts` (~150 lines) - `exportCSV(graph: KnowledgeGraph): string` ##### `features/import-export/formats/GraphMLExporter.ts` (~200 lines) - `exportGraphML(graph: KnowledgeGraph): string` ##### `features/import-export/formats/GEXFExporter.ts` (~200 lines) - `exportGEXF(graph: KnowledgeGraph): string` ##### `features/import-export/formats/DOTExporter.ts` (~150 lines) - `exportDOT(graph: KnowledgeGraph): string` ##### `features/import-export/formats/MarkdownExporter.ts` (~150 lines) - `exportMarkdown(graph: KnowledgeGraph): string` ##### `features/import-export/formats/MermaidExporter.ts` (~150 lines) - `exportMermaid(graph: KnowledgeGraph): string` ##### `features/import-export/formats/JSONImporter.ts` (~100 lines) - `importJSON(data: string): KnowledgeGraph` ##### `features/import-export/formats/CSVImporter.ts` (~200 lines) - `importCSV(data: string): KnowledgeGraph` ##### `features/import-export/formats/GraphMLImporter.ts` (~200 lines) - `importGraphML(data: string): KnowledgeGraph` --- ### 5. Utils Module (`src/memory/utils/`) **Purpose**: Reusable utility functions #### `levenshtein.ts` ```typescript export function levenshteinDistance(str1: string, str2: string): number { // Implementation } ``` **Size**: ~30 lines #### `tfidf.ts` ```typescript export function calculateTF(term: string, document: string): number { // Implementation } export function calculateIDF(term: string, documents: string[]): number { // Implementation } export function calculateTFIDF(term: string, document: string, documents: string[]): number { // Implementation } ``` **Size**: ~100 lines #### `dateUtils.ts` ```typescript export function isWithinDateRange(date: string, start?: string, end?: string): boolean { // Implementation } export function parseDateRange(startDate?: string, endDate?: string): { start: Date | null; end: Date | null } { // Implementation } ``` **Size**: ~50 lines #### `validationUtils.ts` ```typescript export function validateEntity(entity: Entity): { valid: boolean; errors: string[] } { // Implementation } export function validateImportance(importance: number): boolean { // Implementation } ``` **Size**: ~100 lines #### `pathUtils.ts` ```typescript export async function ensureMemoryFilePath(): Promise<string> { // Current implementation from index.ts } export const defaultMemoryPath: string; ``` **Size**: ~80 lines --- ### 6. MCP Module (`src/memory/mcp/`) **Purpose**: MCP Server configuration, tool definitions, and handlers #### `server.ts` **Responsibility**: Server initialization and lifecycle ```typescript import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { toolRegistry } from './tools/index.js'; import { handlerRegistry } from './handlers/index.js'; export async function createServer(knowledgeGraphManager: KnowledgeGraphManager): Promise<Server> { const server = new Server({ name: "memory-server", version: "0.8.0", }, { capabilities: { tools: {}, }, }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: toolRegistry.getAllTools() }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { return handlerRegistry.handleRequest(request, knowledgeGraphManager); }); return server; } ``` **Size**: ~50 lines #### `tools/index.ts` **Responsibility**: Tool registry ```typescript import { entityTools } from './entity.tools.js'; import { searchTools } from './search.tools.js'; import { tagTools } from './tag.tools.js'; // ... other tool imports export class ToolRegistry { getAllTools() { return [ ...entityTools, ...searchTools, ...tagTools, // ... other tools ]; } } export const toolRegistry = new ToolRegistry(); ``` **Size**: ~50 lines #### `tools/entity.tools.ts` **Responsibility**: Entity CRUD tool definitions **Tools**: create_entities, delete_entities, delete_observations **Size**: ~150 lines #### `tools/search.tools.ts` **Responsibility**: Search tool definitions **Tools**: search_nodes, search_nodes_ranked, open_nodes, search_by_date_range, boolean_search, fuzzy_search, get_search_suggestions **Size**: ~250 lines #### `tools/tag.tools.ts` **Responsibility**: Tag tool definitions **Tools**: add_tags, remove_tags, add_tags_to_multiple_entities, replace_tag, merge_tags, add_tag_alias, list_tag_aliases, remove_tag_alias, get_aliases_for_tag, resolve_tag **Size**: ~300 lines #### `tools/hierarchy.tools.ts` **Responsibility**: Hierarchy tool definitions **Tools**: set_entity_parent, get_children, get_parent, get_ancestors, get_descendants, get_subtree, get_root_entities, get_entity_depth **Size**: ~250 lines #### `tools/analytics.tools.ts` **Responsibility**: Analytics tool definitions **Tools**: get_graph_stats, validate_graph **Size**: ~80 lines #### `tools/import-export.tools.ts` **Responsibility**: Import/Export tool definitions **Tools**: import_graph, export_graph, find_duplicates, merge_entities, compress_graph, archive_entities **Size**: ~250 lines #### `handlers/index.ts` **Responsibility**: Handler registry and routing ```typescript import { entityHandlers } from './entity.handlers.js'; import { searchHandlers } from './search.handlers.js'; // ... other handler imports export class HandlerRegistry { async handleRequest(request: any, manager: KnowledgeGraphManager) { const { name, arguments: args } = request.params; // Simple tools without args if (name === "read_graph") { return { content: [{ type: "text", text: JSON.stringify(await manager.readGraph(), null, 2) }] }; } if (!args) { throw new Error(`No arguments provided for tool: ${name}`); } // Route to appropriate handler if (entityHandlers[name]) { return entityHandlers[name](args, manager); } if (searchHandlers[name]) { return searchHandlers[name](args, manager); } // ... other handler routing throw new Error(`Unknown tool: ${name}`); } } export const handlerRegistry = new HandlerRegistry(); ``` **Size**: ~100 lines #### `handlers/entity.handlers.ts` **Responsibility**: Entity tool handlers ```typescript export const entityHandlers = { create_entities: async (args: any, manager: KnowledgeGraphManager) => { return { content: [{ type: "text", text: JSON.stringify(await manager.createEntities(args.entities), null, 2) }] }; }, delete_entities: async (args: any, manager: KnowledgeGraphManager) => { await manager.deleteEntities(args.entityNames); return { content: [{ type: "text", text: "Entities deleted successfully" }] }; }, // ... other entity handlers }; ``` **Size**: ~150 lines #### `handlers/search.handlers.ts` **Responsibility**: Search tool handlers **Size**: ~250 lines #### `handlers/tag.handlers.ts` **Responsibility**: Tag tool handlers **Size**: ~250 lines #### `handlers/hierarchy.handlers.ts` **Responsibility**: Hierarchy tool handlers **Size**: ~200 lines #### `handlers/analytics.handlers.ts` **Responsibility**: Analytics tool handlers **Size**: ~80 lines #### `handlers/import-export.handlers.ts` **Responsibility**: Import/Export tool handlers **Size**: ~150 lines --- ### 7. Main Entry Point (`src/memory/index.ts`) **Responsibility**: Application bootstrapping and initialization ```typescript #!/usr/bin/env node import { KnowledgeGraphManager } from './core/KnowledgeGraphManager.js'; import { ensureMemoryFilePath } from './utils/pathUtils.js'; import { createServer } from './mcp/server.js'; async function main() { // Initialize memory file path with backward compatibility const memoryFilePath = await ensureMemoryFilePath(); // Initialize knowledge graph manager const knowledgeGraphManager = new KnowledgeGraphManager(memoryFilePath); // Create and start MCP server const server = await createServer(knowledgeGraphManager); const transport = new StdioServerTransport(); await server.connect(transport); console.error("Knowledge Graph MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); }); ``` **Size**: ~30 lines (down from 4,187!) --- ## Implementation Strategy ### Phase 1: Foundation (Week 1) **Goal**: Establish new structure without breaking existing code 1. **Create Directory Structure** - Create all new directories: types/, core/, search/, features/, utils/, mcp/ - Keep existing index.ts untouched 2. **Extract Types** - Create all type files in types/ directory - Export from types/index.ts - No code changes to index.ts yet 3. **Setup Tests** - Create test files for each new module - Copy existing tests as baseline **Deliverables**: - ✅ New directory structure - ✅ Types extracted and organized - ✅ Test infrastructure ready **Risk**: Low - No existing code modified --- ### Phase 2: Extract Utilities (Week 1-2) **Goal**: Move pure utility functions to separate files 1. **Extract String Utilities** - Move Levenshtein distance to utils/levenshtein.ts - Move TF-IDF functions to utils/tfidf.ts - Add comprehensive tests 2. **Extract Validation Utilities** - Move validation logic to utils/validationUtils.ts - Move date utilities to utils/dateUtils.ts 3. **Extract Path Utilities** - Move ensureMemoryFilePath to utils/pathUtils.ts 4. **Update index.ts** - Import utilities from new locations - Verify all tests pass **Deliverables**: - ✅ All utilities extracted - ✅ 100% test coverage for utils - ✅ index.ts imports from utils/ **Risk**: Low - Pure functions, easy to test --- ### Phase 3: Extract Storage Layer (Week 2) **Goal**: Separate file I/O from business logic 1. **Create GraphStorage.ts** - Extract loadGraph() method - Extract saveGraph() method - Add file path management 2. **Update KnowledgeGraphManager** - Replace direct file I/O with GraphStorage - Inject GraphStorage via constructor 3. **Test Storage Layer** - Mock file system operations - Test backward compatibility - Test JSONL format handling **Deliverables**: - ✅ GraphStorage.ts with tests - ✅ KnowledgeGraphManager uses GraphStorage - ✅ All existing tests pass **Risk**: Medium - Core functionality, needs careful testing --- ### Phase 4: Extract Core Managers (Week 3) **Goal**: Separate CRUD operations by domain 1. **Create EntityManager.ts** - Extract entity CRUD methods - Inject GraphStorage dependency 2. **Create RelationManager.ts** - Extract relation CRUD methods - Inject GraphStorage dependency 3. **Create ObservationManager.ts** - Extract observation CRUD methods - Inject GraphStorage dependency 4. **Update KnowledgeGraphManager** - Use composition pattern - Delegate to specialized managers - Maintain existing public API **Deliverables**: - ✅ EntityManager.ts with tests - ✅ RelationManager.ts with tests - ✅ ObservationManager.ts with tests - ✅ KnowledgeGraphManager delegates correctly **Risk**: Medium - Business logic changes, thorough testing needed --- ### Phase 5: Extract Search Module (Week 4) **Goal**: Modularize complex search functionality 1. **Create Search Managers** - SearchManager.ts (basic search) - RankedSearch.ts (TF-IDF) - BooleanSearch.ts (query parsing) - FuzzySearch.ts (Levenshtein-based) - SearchSuggestions.ts (trigrams) - SavedSearchManager.ts (saved searches) 2. **Test Search Functionality** - Unit tests for each search type - Integration tests for SearchManager - Performance benchmarks **Deliverables**: - ✅ All search modules extracted - ✅ Comprehensive test coverage - ✅ Search performance maintained or improved **Risk**: High - Complex algorithms, needs extensive testing --- ### Phase 6: Extract Feature Managers (Week 5) **Goal**: Separate advanced features 1. **Create Feature Managers** - TagManager.ts - ImportanceManager.ts - HierarchyManager.ts - AnalyticsManager.ts - CompressionManager.ts - ArchiveManager.ts - ImportExportManager.ts 2. **Test Features** - Unit tests for each manager - Integration tests - Edge case testing **Deliverables**: - ✅ All feature managers extracted - ✅ Test coverage > 80% - ✅ All features working correctly **Risk**: Medium-High - Many interdependencies --- ### Phase 7: Extract MCP Layer (Week 6) **Goal**: Separate API definitions from business logic 1. **Create MCP Structure** - server.ts - tools/ directory with tool definitions - handlers/ directory with request handlers 2. **Extract Tool Definitions** - Split into domain-specific files - Create tool registry 3. **Extract Handlers** - Split into domain-specific files - Create handler registry - Implement routing logic 4. **Update index.ts** - Simplify to just bootstrapping - Import and wire up components **Deliverables**: - ✅ MCP layer fully modularized - ✅ Clean separation of concerns - ✅ index.ts < 50 lines **Risk**: Medium - API layer, needs compatibility testing --- ### Phase 8: Final Integration & Testing (Week 7) **Goal**: Ensure everything works together 1. **Integration Testing** - End-to-end tests - All 45 tools tested - Performance testing 2. **Documentation** - Update README with new structure - Add architecture documentation - Create migration guide 3. **Code Review** - Review all changes - Check for code smells - Ensure consistency 4. **Release Preparation** - Version bump - Changelog update - Release notes **Deliverables**: - ✅ All tests passing - ✅ Documentation updated - ✅ Ready for release **Risk**: Low - Final validation phase --- ## Migration Path ### Backward Compatibility **Guarantee**: All existing code using the current API will continue to work without changes. **Strategy**: 1. Keep KnowledgeGraphManager as the main public API 2. Maintain all existing method signatures 3. Use composition pattern internally 4. Export all public types from main index.ts ### Example Migration **Before** (current): ```typescript import { KnowledgeGraphManager } from '@danielsimonjr/memory-mcp'; const manager = new KnowledgeGraphManager('/path/to/memory.jsonl'); await manager.createEntities([{ name: 'Alice', entityType: 'person', observations: [] }]); ``` **After** (refactored): ```typescript import { KnowledgeGraphManager } from '@danielsimonjr/memory-mcp'; const manager = new KnowledgeGraphManager('/path/to/memory.jsonl'); await manager.createEntities([{ name: 'Alice', entityType: 'person', observations: [] }]); ``` **No changes required!** The internal implementation uses managers, but the public API remains identical. ### Advanced Usage (Optional) For users who want finer-grained control: ```typescript import { EntityManager, GraphStorage } from '@danielsimonjr/memory-mcp/core'; import { RankedSearch } from '@danielsimonjr/memory-mcp/search'; const storage = new GraphStorage('/path/to/memory.jsonl'); const entityManager = new EntityManager(storage); const rankedSearch = new RankedSearch(storage); // Use specific managers directly ``` --- ## Testing Strategy ### Current Test Coverage - Only 2 test files exist - Limited coverage of core functionality - No coverage of advanced features ### Target Test Coverage - **Overall**: > 85% - **Core Modules**: > 95% - **Search Modules**: > 90% - **Feature Modules**: > 80% - **Utils**: 100% ### Test Types 1. **Unit Tests** - Test each module in isolation - Mock dependencies - Fast execution (< 100ms per test) 2. **Integration Tests** - Test module interactions - Use real file system (temp directories) - Verify end-to-end workflows 3. **Performance Tests** - Benchmark search operations - Test with large graphs (10k+ entities) - Ensure no regressions 4. **Compatibility Tests** - Test backward compatibility - Verify JSONL format handling - Test migration scenarios ### Test Organization ``` src/memory/__tests__/ ├── unit/ │ ├── core/ │ │ ├── EntityManager.test.ts │ │ ├── RelationManager.test.ts │ │ └── GraphStorage.test.ts │ ├── search/ │ │ ├── RankedSearch.test.ts │ │ ├── BooleanSearch.test.ts │ │ └── FuzzySearch.test.ts │ ├── features/ │ │ ├── TagManager.test.ts │ │ ├── HierarchyManager.test.ts │ │ └── CompressionManager.test.ts │ └── utils/ │ ├── levenshtein.test.ts │ └── tfidf.test.ts ├── integration/ │ ├── entity-operations.test.ts │ ├── search-operations.test.ts │ ├── hierarchy-operations.test.ts │ └── import-export.test.ts ├── performance/ │ ├── search-benchmark.test.ts │ └── large-graph.test.ts └── compatibility/ ├── backward-compat.test.ts └── migration.test.ts ``` --- ## Benefits ### 1. Maintainability - **Easier Navigation**: Find code faster with logical organization - **Smaller Files**: Each file < 500 lines (vs 4,187) - **Clear Responsibilities**: Each module has one job - **Reduced Cognitive Load**: Understand one module at a time ### 2. Testability - **Unit Testing**: Test modules in isolation - **Mocking**: Easy to mock dependencies - **Test Coverage**: Achieve > 85% coverage - **TDD**: Enable test-driven development ### 3. Team Collaboration - **Reduced Merge Conflicts**: Changes isolated to specific files - **Parallel Development**: Multiple developers work simultaneously - **Code Reviews**: Smaller, focused PRs - **Onboarding**: New developers understand structure faster ### 4. Performance - **Better Tree Shaking**: Import only needed modules - **Faster Builds**: Incremental compilation - **Optimized Loading**: Lazy loading potential - **IDE Performance**: Faster IntelliSense and linting ### 5. Extensibility - **Easy to Add Features**: Create new manager in features/ - **Plugin Architecture**: Potential for plugin system - **Custom Implementations**: Override specific managers - **Third-party Integration**: Export individual modules ### 6. Code Quality - **Single Responsibility Principle**: Each module has one job - **Dependency Injection**: Testable and flexible - **Separation of Concerns**: Clear boundaries - **DRY**: Shared utilities in utils/ --- ## Risks and Mitigation ### Risk 1: Breaking Changes **Probability**: Medium **Impact**: High **Mitigation**: - Maintain backward compatibility in KnowledgeGraphManager - Comprehensive integration tests - Beta release with deprecation warnings - Clear migration documentation ### Risk 2: Performance Regression **Probability**: Low **Impact**: Medium **Mitigation**: - Performance benchmarks before/after - Profile critical paths - Optimize hot paths - Monitor in production ### Risk 3: Increased Complexity **Probability**: Medium **Impact**: Low **Mitigation**: - Clear documentation - Architecture diagrams - Code examples - Developer guide ### Risk 4: Test Coverage Gaps **Probability**: Medium **Impact**: Medium **Mitigation**: - Test-driven development - Code coverage reports - Mandatory review of test coverage - Integration test suite ### Risk 5: Migration Effort **Probability**: Low **Impact**: Medium **Mitigation**: - Maintain public API compatibility - Provide migration guide - Support both old/new patterns temporarily - Clear deprecation timeline --- ## Success Criteria ### Code Quality Metrics - ✅ **STRICT: ALL files < 500 lines** (no exceptions) - ✅ Average file size < 250 lines - ✅ Test coverage > 85% - ✅ Cyclomatic complexity < 10 per function - ✅ Zero ESLint errors - ✅ Zero TypeScript errors - ✅ Each test file < 400 lines (split into multiple files if needed) ### Functional Metrics - ✅ All 45 tools working - ✅ All existing tests passing - ✅ New tests for all modules - ✅ Backward compatibility maintained - ✅ Performance within 5% of baseline ### Developer Experience Metrics - ✅ Onboarding time reduced by 50% - ✅ Code review time reduced by 30% - ✅ Feature development time reduced by 20% - ✅ Build time < 10 seconds - ✅ Test suite runs in < 30 seconds --- ## Timeline | Phase | Duration | Deliverables | |-------|----------|--------------| | Phase 1: Foundation | Week 1 | Directory structure, types extracted | | Phase 2: Utilities | Week 1-2 | All utils extracted and tested | | Phase 3: Storage | Week 2 | GraphStorage module | | Phase 4: Core Managers | Week 3 | Entity, Relation, Observation managers | | Phase 5: Search | Week 4 | All search modules | | Phase 6: Features | Week 5 | All feature managers | | Phase 7: MCP Layer | Week 6 | Server, tools, handlers | | Phase 8: Integration | Week 7 | Testing, docs, release | **Total Duration**: 7 weeks **Effort**: ~140-175 hours --- ## Next Steps 1. **Review and Approve Plan** - Get stakeholder feedback - Adjust timeline if needed - Assign resources 2. **Create Tracking Issues** - One issue per phase - Break down into tasks - Set up project board 3. **Setup Branch** - Create `refactor/modular-architecture` branch - Setup CI/CD for branch - Configure test coverage reporting 4. **Begin Phase 1** - Create directory structure - Extract types - Setup test infrastructure 5. **Regular Check-ins** - Weekly progress reviews - Address blockers - Adjust plan as needed --- ## Conclusion This refactoring plan transforms the monolithic 4,187-line `index.ts` into a modular, maintainable architecture with 15-20 focused modules. The phased approach ensures minimal risk while delivering significant improvements in code quality, testability, and developer experience. The refactoring maintains 100% backward compatibility while positioning the codebase for future enhancements. With clear phases, success criteria, and risk mitigation strategies, this plan provides a roadmap for sustainable growth of the memory MCP server. **Recommendation**: Proceed with Phase 1 to establish the foundation and validate the approach before committing to the full refactoring. --- ## Appendix A: File Size Comparison ### Core Implementation Files | Module | Current (lines) | Target (lines) | Files | Max per file | |--------|----------------|----------------|-------|--------------| | index.ts | 4,187 | 50 | 1 | 50 | | Types | (in index.ts) | 500 | 6 | 150 | | Core Managers | (in index.ts) | 950 | 5 | 350 | | Search Modules | (in index.ts) | 1,550 | 7 | 350 | | Feature Managers | (in index.ts) | 2,650 | 17 | 450 | | Utils | (in index.ts) | 550 | 5 | 150 | | MCP Layer | (in index.ts) | 2,600 | 14 | 300 | | **Total Implementation** | **4,187** | **8,850** | **55** | **<500** | ### Test Files | Test Type | Files | Total Lines | Max per file | |-----------|-------|-------------|--------------| | Unit Tests | 15 | 4,500 | 400 | | Integration Tests | 4 | 1,400 | 400 | | Performance Tests | 2 | 550 | 300 | | **Total Tests** | **21** | **6,450** | **<400** | ### Overall Statistics | Metric | Value | |--------|-------| | Total Files (implementation) | 55 | | Total Files (tests) | 21 | | **Total Files** | **76** | | **Total Lines (all)** | **~15,300** | | **Largest File** | **<500 lines** | | **Average File Size** | **~201 lines** | **Note**: Total line count increases due to: - Module boundaries (imports/exports) - Better separation of concerns - More comprehensive error handling - Additional documentation - More extensive tests - **Aggressive file splitting to stay under 500-line limit** This is a **positive trade-off** - we exchange raw line count for dramatically improved maintainability, testability, and code organization. Every file is easily reviewable and testable. --- ## Appendix B: Dependency Graph ``` index.ts (entry point) ├─> utils/pathUtils.ts ├─> core/KnowledgeGraphManager.ts │ ├─> core/GraphStorage.ts │ │ ├─> types/entity.types.ts │ │ └─> utils/pathUtils.ts │ ├─> core/EntityManager.ts │ │ ├─> core/GraphStorage.ts │ │ └─> types/entity.types.ts │ ├─> core/RelationManager.ts │ │ ├─> core/GraphStorage.ts │ │ └─> types/entity.types.ts │ ├─> core/ObservationManager.ts │ │ ├─> core/GraphStorage.ts │ │ └─> types/entity.types.ts │ ├─> search/SearchManager.ts │ │ ├─> search/BasicSearch.ts │ │ ├─> search/RankedSearch.ts │ │ │ └─> utils/tfidf.ts │ │ ├─> search/BooleanSearch.ts │ │ ├─> search/FuzzySearch.ts │ │ │ └─> utils/levenshtein.ts │ │ └─> search/SearchSuggestions.ts │ ├─> features/TagManager.ts │ ├─> features/HierarchyManager.ts │ ├─> features/CompressionManager.ts │ │ └─> utils/levenshtein.ts │ ├─> features/AnalyticsManager.ts │ └─> features/ImportExportManager.ts └─> mcp/server.ts ├─> mcp/tools/*.ts └─> mcp/handlers/*.ts ``` --- ## Appendix C: Example PR Sequence ### PR #1: Extract Types (Phase 1) **Files Changed**: 6 files added **Lines Changed**: +200, -0 **Risk**: Very Low **Review Time**: 30 minutes ### PR #2: Extract Utilities (Phase 2) **Files Changed**: 6 files added, 1 modified **Lines Changed**: +400, -300 **Risk**: Low **Review Time**: 1 hour ### PR #3: Extract Storage Layer (Phase 3) **Files Changed**: 2 files added, 1 modified **Lines Changed**: +200, -150 **Risk**: Medium **Review Time**: 1.5 hours ### PR #4: Extract Core Managers (Phase 4) **Files Changed**: 4 files added, 1 modified **Lines Changed**: +900, -700 **Risk**: Medium **Review Time**: 2 hours ### PR #5: Extract Search Module (Phase 5) **Files Changed**: 7 files added, 1 modified **Lines Changed**: +1400, -1200 **Risk**: High **Review Time**: 3 hours ### PR #6: Extract Feature Managers (Phase 6) **Files Changed**: 8 files added, 1 modified **Lines Changed**: +2400, -2100 **Risk**: Medium-High **Review Time**: 4 hours ### PR #7: Extract MCP Layer (Phase 7) **Files Changed**: 15 files added, 1 modified **Lines Changed**: +2100, -2000 **Risk**: Medium **Review Time**: 2 hours ### PR #8: Final Integration (Phase 8) **Files Changed**: 30+ files modified (tests, docs) **Lines Changed**: +1500, -100 **Risk**: Low **Review Time**: 2 hours --- **Document Version**: 1.0 **Last Updated**: 2025-11-23 **Author**: Claude (AI Assistant) **Status**: Draft - Awaiting Review

Latest Blog Posts

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/danielsimonjr/memory-mcp'

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