UNPKG

@shirokuma-library/mcp-knowledge-base

Version:

MCP server for AI-powered knowledge management with semantic search, graph analysis, and automatic enrichment

78 lines (77 loc) 2.93 kB
import { ClaudeInterface } from './ai/claude-interface.js'; import { EmbeddingManager } from './ai/embedding-manager.js'; import { DataStorage } from './ai/data-storage.js'; import { Item } from '../entities/Item.js'; export class EnhancedAIService { dataSource; claudeInterface; embeddingManager; dataStorage; constructor(dataSource) { this.dataSource = dataSource; this.claudeInterface = new ClaudeInterface(); this.embeddingManager = new EmbeddingManager(); this.dataStorage = new DataStorage(dataSource); } async generateEnrichments(params) { const weightedTexts = []; if (params.title) { weightedTexts.push(params.title); } if (params.description) { weightedTexts.push(params.description); } if (params.content) { weightedTexts.push(params.content); } const combinedContent = { title: params.title || '', description: params.description || '', content: weightedTexts.join(' ') }; return this.claudeInterface.extractWeightedKeywords(combinedContent); } async enrichItem(item) { const enrichments = await this.generateEnrichments({ title: item.title, description: item.description, content: item.content }); const itemRepo = this.dataSource.getRepository(Item); await itemRepo.update(item.id, { aiSummary: enrichments.summary, searchIndex: enrichments.keywords.map(k => k.keyword).join(' '), embedding: enrichments.embedding }); if (enrichments.keywords.length > 0) { await this.dataStorage.storeKeywordsForItem(item.id, enrichments.keywords); } if (enrichments.concepts.length > 0) { await this.dataStorage.storeConceptsForItem(item.id, enrichments.concepts); } } async findSimilarItems(itemId, limit = 10) { const itemRepo = this.dataSource.getRepository(Item); const item = await itemRepo.findOne({ where: { id: itemId } }); if (!item || !item.embedding) { return []; } const items = await itemRepo .createQueryBuilder('item') .select(['item.id', 'item.embedding']) .where('item.embedding IS NOT NULL') .andWhere('item.id != :itemId', { itemId }) .getMany(); const similarities = items .map(other => { if (!other.embedding) return null; const similarity = this.embeddingManager.calculateSimilarity(item.embedding, other.embedding); return { id: other.id, similarity }; }) .filter((s) => s !== null) .sort((a, b) => b.similarity - a.similarity) .slice(0, limit); return similarities; } }