answer-book-mcp
Version:
智能问答和决策辅助的 MCP (Model Context Protocol) 服务器
242 lines (211 loc) • 6.21 kB
JavaScript
/**
* 答案之书服务器核心逻辑
* 负责工具管理、数据加载和业务逻辑协调
*/
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
}
}
}