UNPKG

mcp-framework

Version:

Framework for building Model Context Protocol (MCP) servers in Typescript

103 lines (102 loc) 4.35 kB
import { join, dirname } from 'path'; import { pathToFileURL } from 'url'; import { existsSync } from 'fs'; import { logger } from '../core/Logger.js'; import { discoverFilesRecursively, hasValidFiles } from '../utils/fileDiscovery.js'; export class BaseLoader { directory; config; constructor(config, basePath) { this.config = config; this.directory = this.resolveDirectory(config.subdirectory, basePath); } resolveDirectory(subdirectory, basePath) { if (basePath) { const dir = join(basePath, subdirectory); logger.debug(`Using provided base path for ${subdirectory}: ${dir}`); return dir; } const projectRoot = process.cwd(); const distPath = join(projectRoot, 'dist', subdirectory); if (existsSync(distPath)) { logger.debug(`Using project's dist/${subdirectory} directory: ${distPath}`); return distPath; } const mainModulePath = process.argv[1]; const moduleDir = dirname(mainModulePath); const dir = moduleDir.endsWith('dist') ? join(moduleDir, subdirectory) : join(moduleDir, 'dist', subdirectory); logger.debug(`Using module path for ${subdirectory}: ${dir}`); return dir; } async hasItems() { try { return await hasValidFiles(this.directory, { extensions: this.config.extensions, excludePatterns: this.config.excludedFiles, }); } catch (error) { logger.debug(`No ${this.config.subdirectory} directory found: ${error.message}`); return false; } } async loadItems() { try { logger.debug(`Attempting to load ${this.config.subdirectory} from: ${this.directory}`); const files = await discoverFilesRecursively(this.directory, { extensions: this.config.extensions, excludePatterns: this.config.excludedFiles, }); if (files.length === 0) { logger.debug(`No ${this.config.subdirectory} files found`); return []; } logger.debug(`Found ${this.config.subdirectory} files: ${files.join(', ')}`); const items = []; for (const file of files) { try { const fullPath = join(this.directory, file); logger.debug(`Attempting to load ${this.config.subdirectory.slice(0, -1)} from: ${fullPath}`); const importPath = pathToFileURL(fullPath).href; const module = await import(importPath); let ItemClass = null; if (module.default && typeof module.default === 'function') { ItemClass = module.default; } else if (typeof module === 'function') { ItemClass = module; } else { const keys = Object.keys(module).filter((key) => key !== 'default'); for (const key of keys) { const exportValue = module[key]; if (typeof exportValue === 'function') { ItemClass = exportValue; break; } } } if (!ItemClass) { logger.warn(`No valid export found in ${file}`); continue; } const item = this.createInstance(ItemClass); if (this.validateItem(item)) { items.push(item); } } catch (error) { logger.error(`Error loading ${this.config.subdirectory.slice(0, -1)} ${file}: ${error.message}`); } } logger.debug(`Successfully loaded ${items.length} ${this.config.subdirectory}: ${items.map(this.getItemName).join(', ')}`); return items; } catch (error) { logger.error(`Failed to load ${this.config.subdirectory}: ${error.message}`); return []; } } }