// src/services/mcpService.js // MCP (Model Context Protocol) 服务层 // 用于与FastAPI后端的MCP工具进行交互 import axios from 'axios'; import { getApiBase } from '../utils/apiConfig'; import { logger } from '../utils/logger'; /** * MCP API客户端 */ class MCPService { constructor() { this.baseURL = `${getApiBase()}/mcp`; this.client = axios.create({ baseURL: this.baseURL, timeout: 60000, // 60秒超时(MCP工具可能需要较长时间) headers: { 'Content-Type': 'application/json', }, }); // 请求拦截器 this.client.interceptors.request.use( (config) => { logger.debug('MCPService', 'Request', { url: config.url, method: config.method, data: config.data, }); return config; }, (error) => { logger.error('MCPService', 'Request Error', error); return Promise.reject(error); } ); // 响应拦截器 this.client.interceptors.response.use( (response) => { logger.debug('MCPService', 'Response', { url: response.config.url, status: response.status, data: response.data, }); return response.data; }, (error) => { logger.error('MCPService', 'Response Error', { url: error.config?.url, status: error.response?.status, message: error.message, }); return Promise.reject(error); } ); } /** * 列出所有可用的MCP工具 * @returns {Promise} 工具列表 */ async listTools() { try { const response = await this.client.get('/tools'); return { success: true, data: response.tools || [], }; } catch (error) { return { success: false, error: error.message || '获取工具列表失败', }; } } /** * 获取特定工具的定义 * @param {string} toolName - 工具名称 * @returns {Promise} 工具定义 */ async getTool(toolName) { try { const response = await this.client.get(`/tools/${toolName}`); return { success: true, data: response, }; } catch (error) { return { success: false, error: error.message || '获取工具定义失败', }; } } /** * 调用MCP工具 * @param {string} toolName - 工具名称 * @param {Object} arguments - 工具参数 * @returns {Promise} 工具执行结果 */ async callTool(toolName, toolArguments) { try { const response = await this.client.post('/tools/call', { tool: toolName, arguments: toolArguments, }); return { success: true, data: response.data || response, }; } catch (error) { return { success: false, error: error.response?.data?.detail || error.message || '工具调用失败', }; } } /** * 智能对话 - 根据用户输入自动选择合适的工具 * @param {string} userMessage - 用户消息 * @param {Array} conversationHistory - 对话历史(可选) * @returns {Promise} AI响应 */ async chat(userMessage, conversationHistory = []) { try { // 这里可以实现智能路由逻辑 // 根据用户输入判断应该调用哪个工具 // 示例:关键词匹配 if (userMessage.includes('新闻') || userMessage.includes('资讯')) { return await this.callTool('search_china_news', { query: userMessage.replace(/新闻|资讯/g, '').trim(), top_k: 5, }); } else if (userMessage.includes('概念') || userMessage.includes('板块')) { const query = userMessage.replace(/概念|板块/g, '').trim(); return await this.callTool('search_concepts', { query, size: 5, sort_by: 'change_pct', }); } else if (userMessage.includes('涨停')) { const query = userMessage.replace(/涨停/g, '').trim(); return await this.callTool('search_limit_up_stocks', { query, mode: 'hybrid', page_size: 5, }); } else if (/^[0-9]{6}$/.test(userMessage.trim())) { // 6位数字 = 股票代码 return await this.callTool('get_stock_basic_info', { seccode: userMessage.trim(), }); } else { // 默认:搜索新闻 return await this.callTool('search_china_news', { query: userMessage, top_k: 5, }); } } catch (error) { return { success: false, error: error.message || '对话处理失败', }; } } /** * 工具类别枚举 */ static TOOL_CATEGORIES = { NEWS: 'news', // 新闻搜索 STOCK: 'stock', // 股票信息 CONCEPT: 'concept', // 概念板块 LIMIT_UP: 'limit_up', // 涨停分析 RESEARCH: 'research', // 研报搜索 ROADSHOW: 'roadshow', // 路演信息 FINANCIAL: 'financial', // 财务数据 TRADE: 'trade', // 交易数据 }; /** * 常用工具快捷方式 */ async searchNews(query, topK = 5, exactMatch = false) { return await this.callTool('search_china_news', { query, top_k: topK, exact_match: exactMatch, }); } async searchConcepts(query, size = 10, sortBy = 'change_pct') { return await this.callTool('search_concepts', { query, size, sort_by: sortBy, }); } async searchLimitUpStocks(query, mode = 'hybrid', pageSize = 10) { return await this.callTool('search_limit_up_stocks', { query, mode, page_size: pageSize, }); } async getStockInfo(seccode) { return await this.callTool('get_stock_basic_info', { seccode, }); } async getStockConcepts(stockCode, size = 10) { return await this.callTool('get_stock_concepts', { stock_code: stockCode, size, }); } async searchResearchReports(query, mode = 'hybrid', size = 5) { return await this.callTool('search_research_reports', { query, mode, size, }); } async getConceptStatistics(days = 7, minStockCount = 3) { return await this.callTool('get_concept_statistics', { days, min_stock_count: minStockCount, }); } } // 导出单例实例 export const mcpService = new MCPService(); // 导出类(供测试使用) export default MCPService;