@sofianedjerbi/knowledge-tree-mcp
Version:
MCP server for hierarchical project knowledge management
30 lines • 11.5 kB
JSON
{
"title": "TypeScript Best Practices and Patterns",
"priority": "COMMON",
"problem": "Effective TypeScript usage in Knowledge Tree MCP requires understanding specific patterns, type safety practices, and common pitfalls to maintain code quality and developer productivity.",
"solution": "## Type Definition Patterns\n\n### 1. Interface Design\n```typescript\n// ✅ GOOD - Comprehensive interface with documentation\ninterface KnowledgeEntry {\n /** Short descriptive title for indexing and display */\n title: string;\n \n /** Priority level affecting search and display order */\n priority: Priority;\n \n /** Main category for organization (auto-detected if not provided) */\n category?: string;\n \n /** Tags for better search and filtering */\n tags?: string[];\n \n /** The core issue this knowledge entry addresses */\n problem: string;\n \n /** Optional context explaining when/why this is relevant */\n context?: string;\n \n /** Recommended solution or best practice */\n solution: string;\n \n /** Code examples illustrating the solution */\n examples?: KnowledgeExample[];\n \n /** Relationships to other entries */\n related_to?: KnowledgeRelation[];\n}\n```\n\n### 2. Union Types and Discriminated Unions\n```typescript\n// ✅ GOOD - Strict union types\ntype Priority = \"CRITICAL\" | \"REQUIRED\" | \"COMMON\" | \"EDGE-CASE\";\ntype RelationshipType = \"related\" | \"supersedes\" | \"superseded_by\" | \"conflicts_with\" | \"implements\" | \"implemented_by\";\n\n// ✅ GOOD - Discriminated union for different response types\ntype MCPResponse = \n | { type: 'success'; content: MCPContent[] }\n | { type: 'error'; error: string; code?: number };\n```\n\n### 3. Generic Constraints\n```typescript\n// ✅ GOOD - Constrained generics for type safety\ninterface SearchResult<T extends KnowledgeEntry = KnowledgeEntry> {\n path: string;\n entry: T;\n relevance_score: number;\n matched_fields: (keyof T)[];\n}\n\n// Usage with specific constraints\nfunction searchEntries<T extends KnowledgeEntry>(\n entries: T[],\n query: string\n): SearchResult<T>[] {\n // Implementation with full type safety\n}\n```\n\n## Type Guard Patterns\n\n### 1. Runtime Type Validation\n```typescript\n// ✅ GOOD - Comprehensive type guard\nfunction isKnowledgeEntry(obj: unknown): obj is KnowledgeEntry {\n if (!obj || typeof obj !== 'object') return false;\n \n const entry = obj as Record<string, unknown>;\n \n return (\n typeof entry.title === 'string' &&\n typeof entry.priority === 'string' &&\n ['CRITICAL', 'REQUIRED', 'COMMON', 'EDGE-CASE'].includes(entry.priority) &&\n typeof entry.problem === 'string' &&\n typeof entry.solution === 'string' &&\n (!entry.tags || Array.isArray(entry.tags)) &&\n (!entry.related_to || Array.isArray(entry.related_to))\n );\n}\n\n// ✅ GOOD - Narrow type guard for specific cases\nfunction isCriticalEntry(entry: KnowledgeEntry): entry is KnowledgeEntry & { priority: 'CRITICAL' } {\n return entry.priority === 'CRITICAL';\n}\n```\n\n### 2. Error Type Guards\n```typescript\n// ✅ GOOD - Node.js error type guards\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\n// Usage\ntry {\n await fs.readFile(path);\n} catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n throw new Error(`File not found: ${path}`);\n }\n throw error;\n}\n```\n\n## Async/Await Patterns\n\n### 1. Proper Error Handling\n```typescript\n// ✅ GOOD - Comprehensive async error handling\nasync function safeKnowledgeOperation<T>(\n operation: () => Promise<T>,\n context: string\n): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (isNodeError(error)) {\n switch (error.code) {\n case 'ENOENT':\n throw new Error(`${context}: File not found - ${error.path}`);\n case 'EACCES':\n throw new Error(`${context}: Permission denied - ${error.path}`);\n case 'EMFILE':\n throw new Error(`${context}: Too many open files`);\n default:\n throw new Error(`${context}: File system error - ${error.message}`);\n }\n }\n throw new Error(`${context}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n}\n```\n\n### 2. Concurrent Operations with Type Safety\n```typescript\n// ✅ GOOD - Type-safe concurrent operations\nasync function processEntriesInParallel(\n paths: string[],\n processor: (path: string) => Promise<KnowledgeEntry>\n): Promise<{ successful: KnowledgeEntry[]; failed: Array<{ path: string; error: string }> }> {\n const results = await Promise.allSettled(\n paths.map(async (path) => ({ path, entry: await processor(path) }))\n );\n \n const successful: KnowledgeEntry[] = [];\n const failed: Array<{ path: string; error: string }> = [];\n \n results.forEach((result, index) => {\n if (result.status === 'fulfilled') {\n successful.push(result.value.entry);\n } else {\n failed.push({\n path: paths[index],\n error: result.reason instanceof Error ? result.reason.message : 'Unknown error'\n });\n }\n });\n \n return { successful, failed };\n}\n```\n\n## Module and Import Patterns\n\n### 1. ES Module Best Practices\n```typescript\n// ✅ GOOD - Explicit .js extensions for ES modules\nimport { KnowledgeEntry, Priority } from '../types/KnowledgeEntry.js';\nimport { readKnowledgeEntry, writeKnowledgeEntry } from '../utils/fileSystem.js';\n\n// ✅ GOOD - Barrel exports with re-exports\n// In types/index.ts\nexport type { KnowledgeEntry, Priority, RelationshipType } from './KnowledgeEntry.js';\nexport type { ServerContext, ToolHandler } from './ServerTypes.js';\nexport type { ProjectConfig } from './ProjectConfig.js';\n```\n\n### 2. Namespace vs Named Imports\n```typescript\n// ✅ GOOD - Named imports for specific functions\nimport { join, dirname, basename } from 'path';\nimport { readFile, writeFile } from 'fs/promises';\n\n// ✅ GOOD - Namespace import for large APIs\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\n// ❌ AVOID - Default imports for non-default exports\nimport path from 'path'; // Wrong if path doesn't have default export\n```\n\n## Configuration and Environment Types\n\n### 1. Environment-Aware Types\n```typescript\n// ✅ GOOD - Environment-specific configuration\ninterface ServerConfig {\n docsPath: string;\n port?: number;\n logLevel: 'debug' | 'info' | 'warn' | 'error';\n maxFileSize: number;\n}\n\ninterface DevelopmentConfig extends ServerConfig {\n hotReload: boolean;\n debugMode: true;\n}\n\ninterface ProductionConfig extends ServerConfig {\n debugMode: false;\n compression: boolean;\n rateLimiting: {\n windowMs: number;\n maxRequests: number;\n };\n}\n\ntype EnvironmentConfig = DevelopmentConfig | ProductionConfig;\n```\n\n### 2. JSON Schema Integration\n```typescript\n// ✅ GOOD - Runtime validation with TypeScript types\nimport { JSONSchema7 } from 'json-schema';\n\nconst knowledgeEntrySchema: JSONSchema7 = {\n type: 'object',\n required: ['title', 'priority', 'problem', 'solution'],\n properties: {\n title: { type: 'string', minLength: 1, maxLength: 200 },\n priority: { enum: ['CRITICAL', 'REQUIRED', 'COMMON', 'EDGE-CASE'] },\n problem: { type: 'string', minLength: 1 },\n solution: { type: 'string', minLength: 1 },\n tags: { type: 'array', items: { type: 'string' } }\n }\n};\n\nfunction validateKnowledgeEntry(data: unknown): KnowledgeEntry {\n // Runtime validation using schema\n if (!isValidAgainstSchema(data, knowledgeEntrySchema)) {\n throw new Error('Invalid knowledge entry format');\n }\n return data as KnowledgeEntry;\n}\n```\n\n## Common Anti-Patterns to Avoid\n\n### 1. Type Assertions Without Validation\n```typescript\n// ❌ BAD - Unsafe type assertion\nconst entry = JSON.parse(content) as KnowledgeEntry;\n\n// ✅ GOOD - Validated type assertion\nconst parsed = JSON.parse(content);\nif (!isKnowledgeEntry(parsed)) {\n throw new Error('Invalid knowledge entry format');\n}\nconst entry = parsed; // TypeScript knows this is KnowledgeEntry\n```\n\n### 2. Any Types in Public APIs\n```typescript\n// ❌ BAD - Using any in public interface\ninterface ToolHandler {\n (args: any, context: ServerContext): Promise<any>;\n}\n\n// ✅ GOOD - Properly typed interface\ninterface ToolHandler<TArgs = unknown, TResult = MCPResponse> {\n (args: TArgs, context: ServerContext): Promise<TResult>;\n}\n```\n\n### 3. Missing Error Types\n```typescript\n// ❌ BAD - Throwing strings or untyped objects\nthrow 'Something went wrong';\nthrow { message: 'Error', code: 500 };\n\n// ✅ GOOD - Proper Error objects with types\nclass KnowledgeTreeError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly path?: string\n ) {\n super(message);\n this.name = 'KnowledgeTreeError';\n }\n}\n\nthrow new KnowledgeTreeError('Entry not found', 'ENTRY_NOT_FOUND', path);\n```",
"tags": [
"typescript",
"best-practices",
"types",
"patterns",
"development"
],
"context": "Knowledge Tree MCP is built with strict TypeScript settings and follows ES modules. The codebase uses advanced TypeScript features like discriminated unions, type guards, and generic constraints that require careful handling.",
"examples": [
{
"title": "Complete Type-Safe Tool Handler",
"code": "interface SearchKnowledgeArgs {\n query?: string;\n priority?: Priority[];\n category?: string;\n limit?: number;\n caseSensitive?: boolean;\n}\n\ninterface SearchKnowledgeResult {\n total_found: number;\n results: Array<{\n path: string;\n title: string;\n priority: Priority;\n relevance_score: number;\n matched_fields: string[];\n preview: string;\n }>;\n}\n\nexport const searchKnowledgeHandler: ToolHandler<SearchKnowledgeArgs, MCPResponse> = async (\n args,\n context\n) => {\n // Input validation with type narrowing\n const {\n query = '',\n priority = ['CRITICAL', 'REQUIRED', 'COMMON', 'EDGE-CASE'],\n category,\n limit = 50,\n caseSensitive = false\n } = args || {};\n\n // Validate priority values\n const validPriorities = priority.filter((p): p is Priority => \n ['CRITICAL', 'REQUIRED', 'COMMON', 'EDGE-CASE'].includes(p)\n );\n\n if (validPriorities.length === 0) {\n throw new KnowledgeTreeError(\n 'At least one valid priority must be specified',\n 'INVALID_PRIORITY'\n );\n }\n\n try {\n const results = await performSearch({\n query,\n priority: validPriorities,\n category,\n limit: Math.min(Math.max(1, limit), 100), // Clamp between 1-100\n caseSensitive\n }, context);\n\n return {\n content: [{\n type: \"text\",\n text: formatSearchResults(results)\n }]\n };\n } catch (error) {\n throw new KnowledgeTreeError(\n `Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'SEARCH_ERROR'\n );\n }\n};",
"language": "typescript"
}
],
"created_at": "2025-08-03T16:56:37.639Z",
"updated_at": "2025-08-04T11:15:10.506Z",
"related_to": [
{
"path": "backend/patterns/common-development-patterns-anti-patterns.json",
"relationship": "related",
"description": "TypeScript patterns complement the general development patterns for type-safe code"
}
]
}