UNPKG

answer-book-mcp

Version:

智能问答和决策辅助的 MCP (Model Context Protocol) 服务器

242 lines (211 loc) 6.21 kB
/** * 答案之书服务器核心逻辑 * 负责工具管理、数据加载和业务逻辑协调 */ import { AskQuestionTool } from './tools/ask-question.js' import { GetAdviceTool } from './tools/get-advice.js' import { RandomAnswerTool } from './tools/random-answer.js' import { SaveQuestionTool } from './tools/save-question.js' import { GetHistoryTool } from './tools/get-history.js' import { StorageManager } from './utils/storage.js' import { logger } from './utils/logger.js' import { validateConfig } from './utils/validator.js' import fs from 'fs-extra' import path from 'path' /** * 答案之书服务器类 */ export class AnswerBookServer { constructor () { this.tools = new Map() this.storageManager = null this.config = null this.initialized = false } /** * 初始化服务器 */ async initialize () { try { logger.info('初始化答案之书服务器...') // 加载配置 await this.loadConfig() // 初始化存储管理器 this.storageManager = new StorageManager(this.config) await this.storageManager.initialize() // 注册工具 await this.registerTools() this.initialized = true logger.info('答案之书服务器初始化完成') } catch (error) { logger.error('服务器初始化失败', { error: error.message, stack: error.stack }) throw error } } /** * 加载配置文件 */ async loadConfig () { try { const configPath = path.join(process.cwd(), 'data', 'config.json') // 如果配置文件不存在,创建默认配置 if (!await fs.pathExists(configPath)) { await this.createDefaultConfig(configPath) } const configData = await fs.readJson(configPath) this.config = validateConfig(configData) logger.debug('配置加载成功', { config: this.config }) } catch (error) { logger.error('配置加载失败', { error: error.message }) throw new Error(`配置加载失败: ${error.message}`) } } /** * 创建默认配置文件 */ async createDefaultConfig (configPath) { const defaultConfig = { server: { name: 'answer-book-mcp', version: '1.0.0', description: '智能问答和决策辅助 MCP 服务器' }, features: { smart_matching: true, history_tracking: true, multilingual: true, personalization: false }, data: { answers_path: './data/answers/', history_path: './data/history.json', max_history_records: 1000 }, matching: { min_confidence: 0.3, fallback_to_random: true, keyword_weight: 0.7, category_weight: 0.3 }, logging: { level: 'info', file: './logs/server.log', max_files: 5, max_size: '10m' } } await fs.ensureDir(path.dirname(configPath)) await fs.writeJson(configPath, defaultConfig, { spaces: 2 }) logger.info('创建默认配置文件', { path: configPath }) } /** * 注册所有工具 */ async registerTools () { try { const tools = [ new AskQuestionTool(this.storageManager, this.config), new GetAdviceTool(this.storageManager, this.config), new RandomAnswerTool(this.storageManager, this.config), new SaveQuestionTool(this.storageManager, this.config), new GetHistoryTool(this.storageManager, this.config) ] for (const tool of tools) { await tool.initialize() this.tools.set(tool.name, tool) logger.debug(`注册工具: ${tool.name}`) } logger.info(`成功注册 ${this.tools.size} 个工具`) } catch (error) { logger.error('工具注册失败', { error: error.message }) throw error } } /** * 获取工具定义列表 */ getToolDefinitions () { if (!this.initialized) { throw new Error('服务器未初始化') } return Array.from(this.tools.values()).map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema })) } /** * 调用指定工具 */ async callTool (name, args) { if (!this.initialized) { throw new Error('服务器未初始化') } const tool = this.tools.get(name) if (!tool) { throw new Error(`未找到工具: ${name}`) } try { const startTime = Date.now() const result = await tool.execute(args) const duration = Date.now() - startTime logger.info(`工具执行完成: ${name}`, { duration, success: true }) return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] } } catch (error) { logger.error(`工具执行失败: ${name}`, { error: error.message, args }) throw new Error(`工具执行失败: ${error.message}`) } } /** * 获取服务器状态 */ getStatus () { return { initialized: this.initialized, tools_count: this.tools.size, config_loaded: !!this.config, data_manager_ready: this.dataManager?.isReady() || false, uptime: process.uptime(), memory_usage: process.memoryUsage(), version: this.config?.server?.version || '1.0.0' } } /** * 重新加载配置和数据 */ async reload () { try { logger.info('重新加载服务器配置和数据...') await this.loadConfig() await this.dataManager.reload() logger.info('服务器重新加载完成') } catch (error) { logger.error('服务器重新加载失败', { error: error.message }) throw error } } /** * 优雅关闭服务器 */ async shutdown () { try { logger.info('正在关闭答案之书服务器...') if (this.storageManager) { await this.storageManager.close() } this.tools.clear() this.initialized = false logger.info('答案之书服务器已关闭') } catch (error) { logger.error('服务器关闭失败', { error: error.message }) throw error } } }