mcp和mcp-server

首先需要明确mcp是什么:

  MCP本质上是一套模型无关的、用于构建可互操作AI应用的工程协议,其核心组件Server/ClientLLM的智能决策并无直接关联。

MCP由三个部分组成,host(端口),Client(客户端),server(服务器)。它引入了host的概念。区别于传统的client-server架构。

host的主要分工为和LLM进行直接交互。比如上下文的完整性,动态构筑和拼接Pormpt,解析LLM的响应,根据AI决策生成于mcp-server交互的指令。它负责了用户与ai交互的最前沿的感知。

Client是一个无状态的协议中间件,主要负责host和server的沟通。负责协议握手、会话管理和心跳维持,它不关心业务逻辑也不理解AI意图,仅作为标准化通信通道。

Server是一个标准的网络服务,它提供一组确定性的的、可供远程调用的能力,这些能力包括文件读取,工具调用等。它接收标准化的信息,执行对应的能力,返回确定的结果,它的行为是确定的可以预测的。

这里暂且只记录mcp-server。

首先是一个基础版本的server服务:它支持在本地调试,但是因为未曾暴露端口仅能在和Client处于同一位置时才可以进行对应的工具调用,有些局限性,但是方便调试与熟悉内容。

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
// Load env and use typed access
import { env } from './config.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { create, all } from 'mathjs';
import OpenAI from "openai";
// 创建 MCP 服务器(使用低层 Server 避免对等依赖 zod)
const server = new Server(
    {
        name: 'my-mcp-server',
        version: '1.0.0',
    },
    {
        capabilities: {
            tools: {},
        }
    }
);

const openai = new OpenAI({
    apiKey: env.OPENAI_API_KEY ?? env.DASHSCOPE_API_KEY,
    // 以下是北京地域base_url,如果使用新加坡地域的模型,需要将base_url替换为:https://dashscope-intl.aliyuncs.com/compatible-mode/v1
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
});

// 工具列表(按照新规范使用 inputSchema)
const tools = [
    {
        name: 'greet',
        description: '打招呼',
        inputSchema: {
            type: 'object',
            properties: {
                name: {
                    type: 'string',
                    description: '姓名',
                },
            },
            required: ['name'],
        },
    },
    {
        name: 'calculate',
        description: '计算',
        inputSchema: {
            type: 'object',
            properties: {
                expression: {
                    type: 'string',
                    description: '数学表达式',
                },
            },
            required: ['expression'],
        },
    },
    {
        name: 'ask-AI',
        description: '询问 AI',
        inputSchema: {
            type: 'object',
            properties: {
                question: {
                    type: 'string',
                    description: '问题',
                },
            },
            required: ['question'],
        },
    }
];

// 处理工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: tools.map(tool => ({
            name: tool.name,
            description: tool.description,
            inputSchema: tool.inputSchema,
        })),
    }
});

// 处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;

    switch (name) {
        case 'greet': 
            const { name: personName } = args as { name: string };
            return {
                content: [
                    {
                        type: 'text',
                        text: `Hello, ${personName}!`,
                    }
                ]
            };
        case 'calculate':
            try {
                const { expression } = args as { expression: string };
                const result = safeEval(expression || "0");
                return {
                    content: [
                        {
                            type: 'text',
                            text: `${expression} = ${result}`,
                        }
                    ]
                };
            } catch (error: any) {
                return {
                    content: [
                        {
                            type: 'text',
                            text: `计算错误: ${error.message}`,
                        }
                    ]
                };
            } 
        case 'ask-AI':
            const { question } = args as { question: string };
            // TODO: 调用 AI 模型
            const completion = await openai.chat.completions.create({
                model: "qwen3-vl-plus",
                messages: [
                    {
                        role: "user",
                        content: question,
                    }
                ],
                temperature: 0.7,
            });
            return {
                content: [
                    {
                        type: 'text',
                        text: completion.choices[0].message.content,
                    }
                ]
            };
        default:
            throw new Error(`未知工具: ${name}`);
    }
});

// 安全计算函数
function safeEval(expression: string): number {
  try {
    // 创建 math 实例并计算表达式
    const math = create(all, {
      precision: 14
    });
    return math.evaluate(expression);
  } catch (error: any) {
    throw new Error(`无效的数学表达式: ${expression}, 错误: ${error?.message || String(error)}`);
  }
}

// 启动服务器
async function startServer() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.log('NODE.JS MCP SERVER STARTED');
    console.log('传输方式:stdio');
    console.log('工具列表:', tools.map(tool => tool.name).join(','));
}

startServer().catch(error => {
    console.error('启动服务器失败:', error);
    process.exit(1);
});

其次,为了能够提供远程的服务,需要对它进行一些改造,主要内容是通讯协议方面由Stdio修改为stream,暴露一些服务端口来方便部署于其他位置的Client进行访问通信;

// server.js - 修复版
const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const os = require('os');

// 工具管理器函数
function createToolManager() {
  const tools = new Map();
  
  return {
    /**
     * 注册工具
     */
    registerTool(name, description, parameters, executeFn) {
      tools.set(name, {
        name,
        description,
        parameters,
        execute: executeFn
      });
      console.log(`🛠️  Tool registered: ${name}`);
      return this;
    },
    
    /**
     * 注册工具对象
     */
    registerToolObject(tool) {
      tools.set(tool.name, tool);
      console.log(`🛠️  Tool registered: ${tool.name}`);
      return this;
    },
    
    /**
     * 获取工具
     */
    getTool(name) {
      return tools.get(name);
    },
    
    /**
     * 获取所有工具
     */
    getAllTools() {
      return Array.from(tools.values()).map(tool => ({
        name: tool.name,
        description: tool.description,
        parameters: tool.parameters || {}
      }));
    },
    
    /**
     * 执行工具
     */
    async executeTool(name, params) {
      const tool = tools.get(name);
      if (!tool) {
        throw new Error(`Tool "${name}" not found`);
      }
      
      try {
        return await tool.execute(params);
      } catch (error) {
        throw new Error(`Tool execution failed: ${error.message}`);
      }
    },
    
    /**
     * 注册内置工具
     */
    registerBuiltinTools() {
      // 计算器工具
      this.registerTool(
        'calculator',
        'Perform mathematical calculations',
        {
          expression: {
            type: 'string',
            description: 'Mathematical expression to evaluate',
            required: true
          }
        },
        async (params) => {
          const { expression } = params;
          const sanitized = expression.replace(/[^0-9+\-*/().\s]/g, '');
          
          try {
            const result = eval(sanitized);
            if (typeof result !== 'number' || !isFinite(result)) {
              throw new Error('Invalid calculation result');
            }
            return { 
              result, 
              expression,
              formatted: `${expression} = ${result}`
            };
          } catch (error) {
            throw new Error(`Calculation error: ${error.message}`);
          }
        }
      );
      
      // 时间工具
      this.registerTool(
        'get_current_time',
        'Get the current date and time',
        {
          format: {
            type: 'string',
            description: 'Time format (ISO, local, timestamp, custom)',
            default: 'ISO',
            enum: ['ISO', 'local', 'timestamp']
          },
          timezone: {
            type: 'string',
            description: 'Timezone (e.g., "UTC", "America/New_York")',
            default: 'UTC'
          }
        },
        async (params) => {
          const { format = 'ISO', timezone = 'UTC' } = params;
          const now = new Date();
          
          let formatted;
          switch (format.toLowerCase()) {
            case 'iso':
              formatted = now.toISOString();
              break;
            case 'local':
              formatted = now.toLocaleString('en-US', { timeZone: timezone });
              break;
            case 'timestamp':
              formatted = now.getTime().toString();
              break;
            default:
              formatted = now.toISOString();
          }
          
          return {
            timestamp: now.getTime(),
            formatted,
            timezone,
            date: now.toDateString(),
            time: now.toTimeString()
          };
        }
      );
      
      // HTTP请求工具
      this.registerTool(
        'http_request',
        'Make HTTP requests',
        {
          url: {
            type: 'string',
            description: 'Request URL',
            required: true
          },
          method: {
            type: 'string',
            description: 'HTTP method',
            default: 'GET',
            enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
          },
          headers: {
            type: 'object',
            description: 'Request headers',
            default: {}
          },
          body: {
            type: 'any',
            description: 'Request body',
            default: null
          }
        },
        async (params) => {
          const { url, method = 'GET', headers = {}, body = null } = params;
          
          return new Promise((resolve, reject) => {
            const parsedUrl = new URL(url);
            const client = parsedUrl.protocol === 'https:' ? https : http;
            
            const options = {
              hostname: parsedUrl.hostname,
              port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
              path: parsedUrl.pathname + parsedUrl.search,
              method,
              headers: {
                'User-Agent': 'MCP-Server/1.0',
                ...headers
              }
            };
            
            const req = client.request(options, (res) => {
              let responseData = '';
              const responseHeaders = { ...res.headers };
              
              res.on('data', chunk => responseData += chunk);
              res.on('end', () => {
                let data;
                try {
                  data = JSON.parse(responseData);
                } catch {
                  data = responseData;
                }
                
                resolve({
                  status: res.statusCode,
                  statusText: res.statusMessage,
                  headers: responseHeaders,
                  data
                });
              });
            });
            
            req.on('error', reject);
            
            if (body) {
              if (typeof body === 'object') {
                req.write(JSON.stringify(body));
              } else {
                req.write(body);
              }
            }
            
            req.end();
          });
        }
      );
      
      // 天气工具(模拟)
      this.registerTool(
        'weather',
        'Get weather information for a city',
        {
          city: {
            type: 'string',
            description: 'City name',
            required: true
          },
          country: {
            type: 'string',
            description: 'Country code (e.g., "us", "cn")',
            default: ''
          },
          units: {
            type: 'string',
            description: 'Temperature units (metric, imperial)',
            default: 'metric',
            enum: ['metric', 'imperial']
          }
        },
        async (params) => {
          const { city, country = '', units = 'metric' } = params;
          
          // 模拟天气数据
          return {
            city: country ? `${city}, ${country}` : city,
            temperature: units === 'metric' ? 25 : 77,
            description: 'Sunny',
            humidity: 65,
            wind_speed: units === 'metric' ? 15 : 9.3,
            units,
            timestamp: new Date().toISOString()
          };
        }
      );
      
      // 文件系统工具
      this.registerTool(
        'filesystem',
        'Perform file system operations',
        {
          action: {
            type: 'string',
            description: 'Action to perform',
            required: true,
            enum: ['read', 'write', 'list', 'delete', 'stat']
          },
          path: {
            type: 'string',
            description: 'File or directory path',
            required: true
          },
          content: {
            type: 'string',
            description: 'Content to write (for write action)',
            default: ''
          },
          encoding: {
            type: 'string',
            description: 'File encoding',
            default: 'utf-8'
          }
        },
        async (params) => {
          const { action, path: filePath, content = '', encoding = 'utf-8' } = params;
          
          try {
            let result;
            
            switch (action) {
              case 'read':
                result = await fs.promises.readFile(filePath, encoding);
                break;
                
              case 'write':
                await fs.promises.writeFile(filePath, content, encoding);
                result = { written: content.length, path: filePath };
                break;
                
              case 'list':
                const files = await fs.promises.readdir(filePath);
                result = files.map(file => ({
                  name: file,
                  isDirectory: fs.statSync(path.join(filePath, file)).isDirectory()
                }));
                break;
                
              case 'delete':
                await fs.promises.unlink(filePath);
                result = { deleted: filePath };
                break;
                
              case 'stat':
                const stats = await fs.promises.stat(filePath);
                result = {
                  size: stats.size,
                  mtime: stats.mtime,
                  isFile: stats.isFile(),
                  isDirectory: stats.isDirectory()
                };
                break;
                
              default:
                throw new Error(`Unsupported action: ${action}`);
            }
            
            return {
              success: true,
              action,
              result
            };
          } catch (error) {
            return {
              success: false,
              action,
              error: error.message
            };
          }
        }
      );
      
      // 系统信息工具
      this.registerTool(
        'system_info',
        'Get system information',
        {
          type: {
            type: 'string',
            description: 'Type of information to get',
            default: 'all',
            enum: ['all', 'memory', 'cpu', 'network']
          }
        },
        async (params) => {
          const { type = 'all' } = params;
          
          const info = {
            platform: os.platform(),
            arch: os.arch(),
            uptime: os.uptime(),
            timestamp: new Date().toISOString()
          };
          
          if (type === 'all' || type === 'memory') {
            info.memory = {
              total: os.totalmem(),
              free: os.freemem(),
              used: os.totalmem() - os.freemem(),
              usage: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2) + '%'
            };
          }
          
          if (type === 'all' || type === 'cpu') {
            info.cpus = os.cpus().map(cpu => ({
              model: cpu.model,
              speed: cpu.speed,
              times: cpu.times
            }));
            info.loadavg = os.loadavg();
          }
          
          if (type === 'all' || type === 'network') {
            info.network = os.networkInterfaces();
          }
          
          return info;
        }
      );
      
      return this;
    }
  };
}

// AI 服务函数
function createAIService(config) {
  const aiConfig = {
    apiKey: config.apiKey,
    endpoint: config.endpoint || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
    model: config.model || 'gpt-3.5-turbo',
    temperature: config.temperature || 0.7,
    timeoutMs: Number(
      (config && config.timeoutMs != null ? config.timeoutMs : process.env.AI_API_TIMEOUT_MS) || 15000
    ),
  };

  /**
   * 调用 AI API
   */
  async function callAIAPI(messages, options = {}) {
    const requestData = JSON.stringify({
      model: options.model || aiConfig.model,
      messages,
      temperature: options.temperature || aiConfig.temperature,
      max_tokens: options.max_tokens,
      stream: options.stream || false
    });

    return new Promise((resolve, reject) => {
      const url = new URL(aiConfig.endpoint);
      
      const req = https.request({
        hostname: url.hostname,
        port: url.port || 443,
        path: url.pathname,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${aiConfig.apiKey}`,
          ...(options.stream && { 'Accept': 'text/event-stream' })
        },
        timeout: aiConfig.timeoutMs,
      }, (res) => {
        let data = '';
        
        res.on('data', (chunk) => {
          if (options.stream && options.onChunk) {
            options.onChunk(chunk.toString());
          } else {
            data += chunk;
          }
        });

        res.on('end', () => {
          if (options.stream) {
            resolve({ complete: true });
          } else {
            try {
              console.log('DEBUG: Raw AI Response:', data);
              const response = JSON.parse(data);
              
              if (res.statusCode !== 200) {
                reject(new Error(`AI API error: ${response.error?.message || 'Unknown error'}`));
                return;
              }

              resolve(response.choices?.[0]?.message?.content || '');
            } catch (error) {
              console.error('DEBUG: JSON Parse Error. Data was:', data);
              reject(new Error('Failed to parse AI response'));
            }
          }
        });
      });

      // 超时保护:上游长时间无响应时中断
      req.setTimeout(aiConfig.timeoutMs, () => {
        req.destroy(new Error('Upstream timeout'));
      });

      req.on('error', reject);
      req.write(requestData);
      req.end();
    });
  }

  /**
   * 流式聊天
   */
  async function streamChat(messages, options = {}) {
    return callAIAPI(messages, { ...options, stream: true });
  }

  return {
    callAIAPI,
    streamChat
  };
}

// 主服务器创建函数
function createMCPServer(config = {}) {
  const server = http.createServer();
  const port = config.port || 3000;
  const toolManager = createToolManager();
  const aiService = config.ai ? createAIService(config.ai) : null;
  
  // 增加最大监听器数量
  server.setMaxListeners(20);
  
  // 默认配置
  const defaultConfig = {
    cors: true,
    logging: true,
    bodyLimit: '1mb',
    ...config
  };
  
  // 自动注册内置工具
  toolManager.registerBuiltinTools();

  /**
   * 设置响应头
   */
  function setResponseHeaders(res) {
    res.setHeader('Content-Type', 'application/json');
    
    if (defaultConfig.cors) {
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
      res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    }
  }

  /**
   * 解析请求体
   */
  function parseRequestBody(req) {
    return new Promise((resolve, reject) => {
      if (req.method === 'GET' || req.method === 'HEAD') {
        resolve({});
        return;
      }
      
      const contentType = req.headers['content-type'] || '';
      let body = '';
      
      req.on('data', chunk => {
        body += chunk.toString();
      });
      
      req.on('end', () => {
        try {
          if (!body) {
            resolve({});
            return;
          }
          
          console.log('DEBUG: Received body:', body);
          console.log('DEBUG: Content-Type:', contentType);

          if (contentType.includes('application/json')) {
            resolve(JSON.parse(body));
          } else {
            resolve({ raw: body });
          }
        } catch (error) {
          console.error('DEBUG: Parse error:', error.message, 'Body was:', body);
          reject(new Error('Invalid request body'));
        }
      });
      
      req.on('error', reject);
    });
  }

  /**
   * 发送 JSON 响应
   */
  function sendJson(res, statusCode, data) {
    res.statusCode = statusCode;
    res.end(JSON.stringify(data, null, 2));
  }

  /**
   * 处理请求的主函数
   */
  async function handleRequest(req, res) {
    const startTime = Date.now();
    
    try {
      // 设置响应头
      setResponseHeaders(res);
      
      // 处理 OPTIONS 预检请求
      if (req.method === 'OPTIONS') {
        res.writeHead(204);
        res.end();
        return;
      }
      
      // 解析 URL
      const url = new URL(req.url, `http://${req.headers.host}`);
      const pathname = url.pathname;
      
      // 解析请求体
      const body = await parseRequestBody(req);
      
      // 路由处理
      if (req.method === 'GET' && pathname === '/') {
        sendJson(res, 200, {
          name: 'MCP Server',
          version: '1.0.0',
          endpoints: {
            '/health': 'GET - Health check',
            '/tools': 'GET - List all tools',
            '/tools/:name': 'POST - Execute a tool',
            '/chat': 'POST - Chat with AI',
            '/chat/stream': 'POST - Stream chat with AI'
          },
          timestamp: new Date().toISOString()
        });
        return;
      }
      
      if (req.method === 'GET' && pathname === '/health') {
        sendJson(res, 200, {
          status: 'ok',
          timestamp: new Date().toISOString(),
          uptime: process.uptime(),
          memory: process.memoryUsage()
        });
        return;
      }
      
      if (req.method === 'GET' && pathname === '/tools') {
        sendJson(res, 200, {
          tools: toolManager.getAllTools(),
          count: toolManager.getAllTools().length
        });
        return;
      }
      
      if (req.method === 'POST' && pathname.startsWith('/tools/')) {
        const toolName = pathname.substring('/tools/'.length);
        
        try {
          const result = await toolManager.executeTool(toolName, body);
          sendJson(res, 200, {
            success: true,
            tool: toolName,
            result
          });
        } catch (error) {
          sendJson(res, 400, {
            success: false,
            tool: toolName,
            error: error.message
          });
        }
        return;
      }
      
      if (req.method === 'POST' && pathname === '/chat') {
        if (!aiService) {
          sendJson(res, 500, { error: 'AI service not configured' });
          return;
        }
        
        try {
          const { messages, model, temperature, stream } = body;
          
          if (!messages || !Array.isArray(messages)) {
            sendJson(res, 400, { error: 'Messages array is required' });
            return;
          }
          
          if (stream) {
            // 流式响应
            res.writeHead(200, {
              'Content-Type': 'text/event-stream',
              'Cache-Control': 'no-cache',
              'Connection': 'keep-alive',
              'Access-Control-Allow-Origin': '*'
            });
            
            await aiService.streamChat(messages, { 
              model, 
              temperature,
              onChunk: (chunk) => {
                res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
              }
            });
            
            res.write('data: [DONE]\n\n');
            res.end();
          } else {
            // 普通响应
            const response = await aiService.callAIAPI(messages, { model, temperature });
            
            sendJson(res, 200, {
              id: `chatcmpl-${Date.now()}`,
              object: 'chat.completion',
              created: Math.floor(Date.now() / 1000),
              model: model || 'gpt-3.5-turbo',
              choices: [{
                index: 0,
                message: {
                  role: 'assistant',
                  content: response
                },
                finish_reason: 'stop'
              }],
              usage: {
                prompt_tokens: 0,
                completion_tokens: 0,
                total_tokens: 0
              }
            });
          }
        } catch (error) {
          const msg = (error && error.message) ? String(error.message) : String(error);
          if (/timeout/i.test(msg)) {
            sendJson(res, 504, { error: msg });
          } else {
            sendJson(res, 500, { error: msg });
          }
        }
        return;
      }
      
      // 404 处理
      sendJson(res, 404, { 
        error: 'Not Found',
        path: pathname
      });
      
    } catch (error) {
      console.error('Request error:', error);
      sendJson(res, 500, { 
        error: 'Internal Server Error',
        message: error.message
      });
    } finally {
      // 记录日志
      if (defaultConfig.logging) {
        const duration = Date.now() - startTime;
        console.log(`[${new Date().toISOString()}] ${req.method} ${req.url} - ${res.statusCode} - ${duration}ms`);
      }
    }
  }

  /**
   * 启动服务器
   */
  function start(callback) {
    // 设置请求处理器 - 只设置一次!
    server.on('request', handleRequest);
    
    server.listen(port, (err) => {
      if (callback) callback(err, server);
      
      if (defaultConfig.logging) {
        console.log(`🚀 MCP Server running on http://localhost:${port}`);
        console.log('📡 Available endpoints:');
        console.log(`  GET  /               - Server info`);
        console.log(`  GET  /health         - Health check`);
        console.log(`  GET  /tools          - List available tools`);
        console.log(`  POST /tools/:name    - Execute a tool`);
        console.log(`  POST /chat          - Chat with AI`);
        console.log(`  POST /chat/stream   - Stream chat with AI`);
        console.log('');
        console.log(`🛠️  Available tools: ${toolManager.getAllTools().map(t => t.name).join(', ')}`);
      }
    });
    
    return server;
  }

  /**
   * 停止服务器
   */
  function stop(callback) {
    server.close(callback);
    
    if (defaultConfig.logging) {
      console.log('🛑 MCP Server stopped');
    }
  }

  /**
   * 注册工具
   */
  function registerTool(name, description, parameters, executeFn) {
    toolManager.registerTool(name, description, parameters, executeFn);
  }

  /**
   * 注册工具对象
   */
  function registerToolObject(tool) {
    toolManager.registerToolObject(tool);
  }

  /**
   * 执行工具
   */
  async function executeTool(name, params) {
    return toolManager.executeTool(name, params);
  }

  /**
   * 获取所有工具
   */
  function getTools() {
    return toolManager.getAllTools();
  }

  return {
    start,
    stop,
    registerTool,
    registerToolObject,
    executeTool,
    getTools
  };
}

module.exports = {
  createMCPServer,
  createToolManager,
  createAIService
};

 

截至此时,这个mcp-Server才算是一个完整的可供调用的服务。如果想要运行可以在此页面新增

// 如果直接运行此文件
if (require.main === module) {
  require('dotenv/config');
  
  const port = Number(process.env.PORT || 3000);
  const aiKey = process.env.AI_API_KEY || '';
  const aiEndpoint = process.env.AI_API_ENDPOINT;
  const aiModel = process.env.AI_MODEL || 'gpt-3.5-turbo';
  const aiTemperature = Number(process.env.AI_TEMPERATURE || 0.7);
  const aiTimeoutMs = Number(process.env.AI_API_TIMEOUT_MS || 15000);

  console.log('🚀 Starting server directly from server.js...');
  console.log('DEBUG: AI_API_KEY length:', aiKey ? aiKey.length : 0);

  const config = {
    port,
    ai: aiKey ? {
      apiKey: aiKey,
      endpoint: aiEndpoint,
      model: aiModel,
      temperature: aiTemperature,
      timeoutMs: aiTimeoutMs,
    } : undefined
  };

  const mcpServer = createMCPServer(config);
  mcpServer.start((err) => {
    if (err) {
      console.error('Failed to start server:', err);
      process.exit(1);
    }
    console.log('✅ Server is up and running!');
  });
}

这样就可以通过node server.js来运行,

如果不想修改server可以通过index.js,运行方式为 node index.js

// index.js
require('dotenv/config');
const { createMCPServer } = require('./server');

// 环境变量读取与默认值
const port = Number(process.env.PORT || 3000);
const host = process.env.HOST || '0.0.0.0'; const aiKey
= process.env.AI_API_KEY || ''; const aiEndpoint = process.env.AI_API_ENDPOINT; // 可选:自定义上游(如代理/兼容端点) const aiModel = process.env.AI_MODEL || 'gpt-3.5-turbo'; const aiTemperature = Number(process.env.AI_TEMPERATURE || 0.7); const aiTimeoutMs = Number(process.env.AI_API_TIMEOUT_MS || 15000); // 仅当提供了 API Key 时启用 AI 服务,避免误调用上游导致超时 console.log('DEBUG: AI_API_KEY length:', aiKey ? aiKey.length : 0); console.log('DEBUG: AI_API_KEY starts with:', aiKey ? aiKey.substring(0, 3) : 'N/A'); const ai = aiKey ? { apiKey: aiKey, endpoint: aiEndpoint, model: aiModel, temperature: aiTemperature, timeoutMs: aiTimeoutMs, } : undefined; const config = { port,
host, cors:
true, logging: true, ai, }; const mcpServer = createMCPServer(config); mcpServer.start((err) => { if (err) { console.error('Failed to start server:', err); process.exit(1); } console.log('✅ Server started successfully!'); }); // 优雅关闭 process.on('SIGINT', () => { console.log('\n🔻 Shutting down server...'); mcpServer.stop(() => { console.log('✅ Server stopped'); process.exit(0); }); });

 新增工具可以使用

mcpServer.registerTool(name: any, description: any, parameters: any, executeFn: any)

 

 

posted @ 2026-01-08 16:10  妄欢  阅读(391)  评论(0)    收藏  举报