MCP基础学习二:MCP服务搭建与配置

MCP服务搭建与配置

一,学习目标:

  • 学会如何搭建MCP服务环境,理解MCP服务的配置方式。
  • 掌握如何在本地应用中集成MCP功能。

二,学习内容:

1. 如何搭建MCP服务端

MCP(Model Context Protocol)服务是一个用于连接客户端应用与各种处理功能的中间层。搭建MCP服务端是构建整个系统的第一步,它将成为所有客户端请求的处理中心。

服务端初始化与配置

MCP服务的第一步是初始化服务器环境和配置。这个过程包括:

  • 安装必要依赖(Node.js、winston、express、dotenv)
  • 创建配置文件,管理服务器参数(端口、主机名、安全设置等)
  • 初始化MCPServer实例,准备注册工具和资源处理器

基础环境准备

在开始构建MCP服务前,我们需要准备基本的开发环境。MCP服务基于Node.js构建,因此需要确保系统已安装相关环境:

  • 需要: Node.js 16.0+, npm或yarn
  • 初始化:
    # 创建项目目录并进入
    mkdir mcp-demo && cd mcp-demo
    
    # 初始化package.json
    npm init -y
    
    # 安装必要依赖
    npm install winston express dotenv
    

上述命令会创建一个基本的项目结构,安装必要的依赖包:winston用于日志记录,express用于创建HTTP服务器,dotenv用于管理环境变量。

MCP服务架构与数据流交互图

在这里插入图片描述

核心实现

接下来,我们需要实现MCP服务的核心功能。MCP服务的核心是一个能够注册和管理各种工具与资源处理器的服务器类。

核心服务类

// src/lib/mcp-sdk.js - 核心SDK
export class MCPServer {
  constructor(config) {
    // 初始化服务器实例
    this.resources = new Map();  // 用于存储资源处理器的映射表
    this.tools = new Map();      // 用于存储工具函数的映射表
    this.config = config;        // 存储服务器配置信息
  }
  
  // 注册工具函数 - 用于添加新的API功能
  registerTool(name, handler) {
    // name: 工具名称,如'processText'、'calculate'
    // handler: 处理函数,接收请求参数并返回结果
    this.tools.set(name, handler);
    // 例如: server.registerTool('sum', (numbers) => numbers.reduce((a,b) => a+b));
  }
  
  // 注册资源处理器 - 用于处理文件和其他资源
  registerResourceHandler(type, handler) {
    // type: 资源类型,如'file'、'database'
    // handler: 资源处理函数,处理资源获取和存储
    this.resources.set(type, handler);
    // 例如: server.registerResourceHandler('file', (path) => fs.readFile(path));
  }
}

这个类是整个MCP服务的核心,通过Map结构存储注册的工具和资源处理器,实现了可扩展的插件式架构。MCPServer类提供了两个主要方法:

  • registerTool: 用于注册各种工具函数,如文本处理、数学计算等
  • registerResourceHandler: 用于注册资源处理器,如文件读取、数据库访问等
注册服务功能

MCP服务的核心是其功能注册机制,允许以插件式架构添加各种功能:

  • 工具注册:使用registerTool方法注册各种处理工具
  • 资源处理器:使用registerResourceHandler注册资源访问方法
  • 每个工具和资源处理器都是独立的功能单元,支持异步操作

接下来,我们使用这个核心类来创建一个实际的服务器实例,并注册一些基本功能:

// src/server/index.js - 服务器实现
// 创建服务器实例,配置基本参数
const server = new MCPServer({
  port: 3000,        // 服务器监听端口
  host: 'localhost'  // 服务器主机名
});

// 注册文本处理工具 - 提供文本分析功能
server.registerTool('processText', async ({text, operation}) => {
  // 根据操作类型处理文本
  switch(operation) {
    case 'wordCount': 
      // 计算文本中的单词数量
      return { count: text.split(/\s+/).length };
    case 'charCount': 
      // 计算文本中的字符数量
      return { count: text.length };
    case 'toUpperCase': 
      // 将文本转换为大写形式
      return { text: text.toUpperCase() };
    // 可以在这里添加更多文本处理功能
  }
});

// 注册计算工具 - 提供数学计算功能
server.registerTool('calculate', async ({operation, numbers}) => {
  // 根据操作类型进行数学计算
  switch(operation) {
    case 'sum':
      // 计算数组元素之和
      return { value: numbers.reduce((a,b) => a+b, 0) };
    case 'average':
      // 计算数组元素的平均值
      return { value: numbers.reduce((a,b) => a+b, 0) / numbers.length };
    case 'max':
      // 找出数组中的最大值
      return { value: Math.max(...numbers) };
    case 'min':
      // 找出数组中的最小值
      return { value: Math.min(...numbers) };
    // 可以在这里添加更多计算功能
  }
});

在这段代码中,我们创建了一个监听在3000端口的MCP服务器,并注册了两个工具:

  1. processText: 提供文本处理功能,包括单词计数、字符计数和转换大写
  2. calculate: 提供数学计算功能,包括求和、平均值、最大值和最小值

这些函数将作为服务的API端点,供客户端调用。

服务器启动与API暴露

完成配置和功能注册后,服务器需要启动并暴露API接口:

  • 配置Express中间件(JSON解析、跨域支持、请求限制)
  • 定义API路由(/tools/:name/resources/:type
  • 启动HTTP服务器监听指定端口
  • 创建日志目录和启动日志系统

最后,我们需要启动服务器,使其能够接收和处理请求:

# 启动MCP服务器
node src/server/index.js

# 服务器将在localhost:3000上运行
# 可以通过浏览器或API客户端访问

执行上述命令后,MCP服务将在后台运行,等待客户端连接和请求。

2. 本地应用与MCP服务的集成

一旦MCP服务端搭建完成,我们就需要开发客户端应用来与之交互。本节将介绍如何创建一个客户端SDK和应用程序,以便与MCP服务进行通信。

客户端SDK实现

为了便于应用程序与MCP服务交互,实现了客户端SDK:

  • 基础客户端类:MCPClient封装了与服务器通信的基本方法
  • 扩展客户端类:MCPDemoClient添加了日志、错误处理和功能封装
  • 客户端类提供语义化API,简化服务调用流程

首先,我们需要一个客户端SDK来简化与MCP服务的通信。这个SDK封装了网络请求和错误处理细节,提供了一个简洁的接口:

// src/lib/mcp-sdk.js - 客户端SDK部分
export class MCPClient {
  constructor(serverUrl) {
    // 初始化客户端
    this.serverUrl = serverUrl;  // MCP服务器地址,如'http://localhost:3000'
  }
  
  // 连接到MCP服务器
  async connect() {
    // 实际项目中,这里可能包含身份验证逻辑
    console.log(`连接到MCP服务器: ${this.serverUrl}`);
    return true; // 返回连接状态
  }
  
  // 调用远程工具
  async callTool(name, params) {
    // name: 工具名称,例如'processText'、'calculate'
    // params: 调用参数对象
    console.log(`调用工具: ${name}, 参数:`, params);
    
    // 实际项目中,这里应该是一个HTTP请求到服务器
    // 例如:await fetch(`${this.serverUrl}/tools/${name}`, { method: 'POST', body: JSON.stringify(params) })
    
    // 模拟返回结果,实际应该返回服务器响应
    switch(name) {
      case 'processText':
        if(params.operation === 'wordCount') return { count: params.text.split(/\s+/).length };
        if(params.operation === 'charCount') return { count: params.text.length };
        if(params.operation === 'toUpperCase') return { text: params.text.toUpperCase() };
        break;
      case 'calculate':
        if(params.operation === 'sum') return { value: params.numbers.reduce((a,b) => a+b, 0) };
        if(params.operation === 'average') return { value: params.numbers.reduce((a,b) => a+b, 0) / params.numbers.length };
        if(params.operation === 'max') return { value: Math.max(...params.numbers) };
        if(params.operation === 'min') return { value: Math.min(...params.numbers) };
        break;
    }
    
    return { status: 'error', message: '不支持的操作' };
  }
  
  // 获取资源
  async getResource(type, path) {
    // type: 资源类型,如'file'
    // path: 资源路径
    console.log(`获取资源: ${type}, 路径: ${path}`);
    
    // 实际项目中,这里应该是一个HTTP请求到服务器
    // 例如:await fetch(`${this.serverUrl}/resources/${type}?path=${path}`)
    
    // 模拟返回结果
    return { content: '资源内容示例' };
  }
}

这个类封装了与服务器通信的基本方法,简化了客户端应用的开发流程。MCPClient类提供了以下主要功能:

  • connect(): 连接到MCP服务器
  • callTool(name, params): 调用服务器上注册的工具
  • getResource(type, path): 获取服务器上的资源

注意:为了简化示例,这里使用了本地模拟实现,而不是真正的网络请求。在实际项目中,应该使用fetch或axios等库发送HTTP请求。

客户端应用实现

有了基础SDK后,我们可以创建一个更加完善的客户端应用,它不仅封装了与MCP服务的通信,还添加了日志记录和错误处理等功能:

// src/client/index.js
import { MCPClient } from '../lib/mcp-sdk.js';
import winston from 'winston';

export class MCPDemoClient {
  constructor() {
    // 初始化客户端应用
    this.serverUrl = 'http://localhost:3000';  // MCP服务器地址
    this.setupLogger();                        // 设置日志记录器
  }

  // 设置日志记录系统
  setupLogger() {
    // 创建Winston日志记录器,支持文件和控制台输出
    this.logger = winston.createLogger({
      level: 'info',                           // 日志级别
      format: winston.format.combine(
        winston.format.timestamp(),            // 添加时间戳
        winston.format.json()                  // 使用JSON格式
      ),
      transports: [
        // 文件输出
        new winston.transports.File({ filename: 'logs/client.log' }),
        // 控制台输出
        new winston.transports.Console()
      ]
    });
  }

  // 连接到MCP服务器
  async connect() {
    try {
      // 创建MCP客户端实例并连接
      this.client = new MCPClient(this.serverUrl);
      await this.client.connect();
      
      this.logger.info(`已连接到MCP服务器: ${this.serverUrl}`);
      return true;
    } catch (error) {
      // 记录连接错误
      this.logger.error(`连接MCP服务器失败: ${error.message}`);
      throw error;  // 重新抛出异常以便上层处理
    }
  }

  // 文本处理功能
  async processText(text, operation) {
    try {
      // 记录操作
      this.logger.info(`执行文本处理: ${operation}`);
      
      // 调用MCP服务
      const result = await this.client.callTool('processText', {
        text,      // 要处理的文本
        operation  // 操作类型
      });
      
      // 根据操作类型返回相应结果
      switch(operation) {
        case 'wordCount':   // 单词计数
        case 'charCount':   // 字符计数
          return result.count;
        case 'toUpperCase': // 转换大写
          return result.text;
        default:
          throw new Error('不支持的操作');
      }
    } catch (error) {
      // 记录错误
      this.logger.error(`文本处理失败: ${error.message}`);
      throw error;
    }
  }

  // 计算功能
  async calculate(operation, numbers) {
    try {
      // 记录操作
      this.logger.info(`执行计算: ${operation}`);
      
      // 调用MCP服务
      const result = await this.client.callTool('calculate', {
        operation,  // 计算操作
        numbers     // 数字数组
      });
      
      return result.value;  // 返回计算结果
    } catch (error) {
      // 记录错误
      this.logger.error(`计算失败: ${error.message}`);
      throw error;
    }
  }

  // 文件读取功能
  async readFile(filePath) {
    try {
      // 记录操作
      this.logger.info(`读取文件: ${filePath}`);
      
      // 调用MCP服务获取文件内容
      return await this.client.getResource('file', filePath);
    } catch (error) {
      // 记录错误
      this.logger.error(`读取文件失败: ${error.message}`);
      throw error;
    }
  }
}

这个类在基础客户端的基础上添加了日志记录、错误处理和功能封装,提供了更加语义化的API。MCPDemoClient类是对基础MCPClient的进一步封装和扩展。它添加了以下功能:

  1. 日志系统:使用winston库记录操作日志和错误信息,支持同时输出到文件和控制台
  2. 错误处理:为每个操作添加了try-catch结构,确保异常被正确处理和记录
  3. 功能封装:提供了更加语义化的方法,如processTextcalculatereadFile

这种分层设计使得应用代码更加清晰和易于维护。底层的MCPClient处理通信细节,而上层的MCPDemoClient关注业务逻辑和错误处理。

功能演示与测试

最后,通过演示脚本展示MCP服务的各项功能:

  • 文本处理:单词计数、字符计数、转换大写
  • 数据计算:求和、平均值、最大值、最小值
  • 文件操作:读取文件内容
  • 错误处理:捕获并记录各种异常情况

有了客户端应用后,我们可以创建一个演示脚本来展示如何使用这些功能:

// src/client/demo.js
import { MCPDemoClient } from './index.js';

async function runDemo() {
  try {
    console.log('启动MCP客户端演示...');
    
    // 创建客户端并连接到服务器
    const client = new MCPDemoClient();
    await client.connect();
    
    console.log('\n=== MCP 功能演示 ===\n');
    
    // 1. 文本处理演示
    const text = 'Hello, MCP!';
    console.log('1. 文本处理功能:');
    console.log(`原始文本: ${text}`);
    
    // 获取单词数
    const wordCount = await client.processText(text, 'wordCount');
    console.log(`单词数: ${wordCount}`);                        // 预期输出: 2
    
    // 获取字符数
    const charCount = await client.processText(text, 'charCount');
    console.log(`字符数: ${charCount}`);                        // 预期输出: 10
    
    // 转换为大写
    const upperCase = await client.processText(text, 'toUpperCase');
    console.log(`转换大写: ${upperCase}`);                      // 预期输出: HELLO, MCP!
    
    // 2. 计算功能演示
    const numbers = [1, 2, 3, 4, 5];
    console.log('\n2. 计算功能:');
    console.log(`数据集: ${JSON.stringify(numbers)}`);
    
    // 求和
    const sum = await client.calculate('sum', numbers);
    console.log(`sum: ${sum}`);                                // 预期输出: 15
    
    // 平均值
    const avg = await client.calculate('average', numbers);
    console.log(`average: ${avg}`);                            // 预期输出: 3
    
    // 最大值
    const max = await client.calculate('max', numbers);
    console.log(`max: ${max}`);                                // 预期输出: 5
    
    // 最小值
    const min = await client.calculate('min', numbers);
    console.log(`min: ${min}`);                                // 预期输出: 1
    
    // 3. 文件读取演示
    console.log('\n3. 文件读取功能:');
    const fileContent = await client.readFile('test.txt');
    console.log(`文件内容: ${fileContent.content}`);
    
    console.log('\n演示完成!');
  } catch (error) {
    // 捕获并显示所有错误
    console.error('演示过程中发生错误:', error);
  }
}

// 运行演示
runDemo();

这个演示脚本展示了如何使用MCPDemoClient类的各种功能:

  1. 初始化和连接:创建客户端实例并连接到MCP服务器
  2. 文本处理:演示三种文本操作(单词计数、字符计数、转大写)
  3. 数据计算:演示四种计算操作(求和、平均值、最大值、最小值)
  4. 文件读取:演示如何读取文件内容

该脚本还包含了全局的错误处理,确保任何异常都能被捕获并显示给用户。

启动客户端演示

要运行这个演示,只需执行以下命令:

# 确保MCP服务器已启动后,运行客户端演示
node src/client/demo.js

# 客户端将连接到localhost:3000的MCP服务
# 并演示各种功能调用

通过这个简单的命令,您可以看到MCP服务的各种功能演示。确保在运行客户端之前,MCP服务器已经启动并正常运行。

3. 配置和启动MCP服务

MCP服务的成功运行离不开正确的配置和启动流程。本节将详细介绍如何配置MCP服务、如何使用完整的服务器代码,以及如何部署和启动服务。

服务器配置文件

首先,我们需要创建一个配置文件来管理服务器的各种参数。这样可以避免硬编码,使服务更加灵活:

// src/config/server.config.js
export const serverConfig = {
  // 基础配置
  port: 3000,                             // 服务器监听端口
  host: 'localhost',                      // 服务器主机名
  
  // 自定义功能配置
  customFeatures: {
    enableCache: true,                    // 启用缓存功能
    maxCacheSize: 1000,                   // 最大缓存条目数
    allowedTypes: ['text', 'json']        // 允许的内容类型
  },
  
  // 安全配置
  security: {
    allowedOrigins: ['http://localhost:8080'], // 允许的来源
    maxRequestSize: '1mb',                // 最大请求大小
    customRules: {
      maxRequestsPerIP: 1000,             // IP请求速率限制
      blacklistedIPs: []                  // 黑名单IP列表
    }
  },

  // 日志配置
  logging: {
    level: 'info',                        // 日志级别
    filename: './logs/server.log'         // 日志文件路径
  }
};

这个配置文件包含了四大类设置:

  1. 基础配置:包括服务器监听的端口和主机名
  2. 自定义功能配置:控制缓存和内容类型等功能特性
  3. 安全配置:设置CORS、请求大小限制和IP访问控制
  4. 日志配置:设置日志级别和输出文件路径

通过将这些配置抽离到单独的文件中,我们可以根据不同环境(开发、测试、生产)使用不同的配置,而无需修改代码。

完整服务器启动代码

接下来,我们来看一个更加完整的服务器实现,它使用Express框架创建HTTP服务器,并整合了之前定义的MCP功能:

// src/server/index.js - 完整实现
import { MCPServer } from '../lib/mcp-sdk.js';
import { serverConfig } from '../config/server.config.js';
import winston from 'winston';
import fs from 'fs/promises';
import express from 'express';

class MCPDemoServer {
  constructor() {
    // 初始化服务器
    this.setupLogger();
    this.server = new MCPServer(serverConfig);
    this.app = express();
    this.setupMiddleware();
    this.setupHandlers();
  }

  // 设置日志记录器
  setupLogger() {
    // 创建Winston日志记录器,支持文件和控制台输出
    this.logger = winston.createLogger({
      level: serverConfig.logging.level,
      format: winston.format.combine(
        winston.format.timestamp(),            // 添加时间戳
        winston.format.json()                  // 使用JSON格式
      ),
      transports: [
        // 文件输出
        new winston.transports.File({ 
          filename: serverConfig.logging.filename 
        }),
        // 控制台输出
        new winston.transports.Console()
      ]
    });
  }

  // 设置Express中间件
  setupMiddleware() {
    // 解析JSON请求体
    this.app.use(express.json({ limit: serverConfig.security.maxRequestSize }));
    
    // 日志中间件
    this.app.use((req, res, next) => {
      this.logger.info(`${req.method} ${req.path}`);
      next();
    });
    
    // CORS设置
    this.app.use((req, res, next) => {
      const origin = req.headers.origin;
      if (serverConfig.security.allowedOrigins.includes(origin)) {
        res.header('Access-Control-Allow-Origin', origin);
      }
      res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
      res.header('Access-Control-Allow-Headers', 'Content-Type');
      next();
    });
    
    // 请求速率限制(简化版)
    const requestCounts = new Map();
    this.app.use((req, res, next) => {
      const ip = req.ip;
      
      // 检查黑名单
      if (serverConfig.security.customRules.blacklistedIPs.includes(ip)) {
        return res.status(403).json({ error: '访问被拒绝' });
      }
      
      // 检查请求速率
      const count = requestCounts.get(ip) || 0;
      if (count >= serverConfig.security.customRules.maxRequestsPerIP) {
        return res.status(429).json({ error: '请求过多' });
      }
      
      // 更新计数
      requestCounts.set(ip, count + 1);
      next();
    });
  }

  // 设置请求处理器
  setupHandlers() {
    // 注册文件资源处理器
    this.server.registerResourceHandler('file', async (path) => {
      try {
        const content = await fs.readFile(path, 'utf-8');
        this.logger.info(`成功读取文件: ${path}`);
        return { content };
      } catch (error) {
        this.logger.error(`读取文件失败: ${error.message}`);
        throw new Error(`无法读取文件: ${error.message}`);
      }
    });

    // 注册文本处理工具
    this.server.registerTool('processText', async ({ text, operation }) => {
      this.logger.info(`处理文本,操作: ${operation}`);
      try {
        switch(operation) {
          case 'wordCount':
            return { count: text.split(/\s+/).length };
          case 'charCount':
            return { count: text.length };
          case 'toUpperCase':
            return { text: text.toUpperCase() };
          default:
            throw new Error('不支持的操作');
        }
      } catch (error) {
        this.logger.error(`文本处理失败: ${error.message}`);
        throw error;
      }
    });

    // 注册计算工具
    this.server.registerTool('calculate', async ({ operation, numbers }) => {
      this.logger.info(`执行计算,操作: ${operation}`);
      try {
        if (!Array.isArray(numbers)) {
          throw new Error('输入必须是数组');
        }
        
        switch(operation) {
          case 'sum':
            return { value: numbers.reduce((a, b) => a + b, 0) };
          case 'average':
            return { value: numbers.reduce((a, b) => a + b, 0) / numbers.length };
          case 'max':
            return { value: Math.max(...numbers) };
          case 'min':
            return { value: Math.min(...numbers) };
          default:
            throw new Error('不支持的操作');
        }
      } catch (error) {
        this.logger.error(`计算失败: ${error.message}`);
        throw error;
      }
    });
    
    // 设置API路由
    this.app.post('/tools/:name', async (req, res) => {
      try {
        const name = req.params.name;
        const handler = this.server.tools.get(name);
        
        if (!handler) {
          return res.status(404).json({ error: '工具不存在' });
        }
        
        const result = await handler(req.body);
        res.json(result);
      } catch (error) {
        this.logger.error(`API错误: ${error.message}`);
        res.status(500).json({ error: error.message });
      }
    });
    
    this.app.get('/resources/:type', async (req, res) => {
      try {
        const type = req.params.type;
        const path = req.query.path;
        const handler = this.server.resources.get(type);
        
        if (!handler) {
          return res.status(404).json({ error: '资源类型不存在' });
        }
        
        const result = await handler(path);
        res.json(result);
      } catch (error) {
        this.logger.error(`资源错误: ${error.message}`);
        res.status(500).json({ error: error.message });
      }
    });
  }

  // 启动服务器
  async start() {
    try {
      // 创建日志目录
      try {
        await fs.mkdir('./logs', { recursive: true });
      } catch (err) {
        // 目录可能已存在,忽略错误
      }
      
      // 启动HTTP服务器
      const port = serverConfig.port;
      const host = serverConfig.host;
      
      this.app.listen(port, host, () => {
        this.logger.info(`MCP服务器已启动,监听 ${host}:${port}`);
      });
    } catch (error) {
      this.logger.error(`服务器启动失败: ${error.message}`);
      throw error;
    }
  }
}

// 创建并启动服务器
const server = new MCPDemoServer();
server.start().catch(error => {
  console.error('服务器错误:', error);
  process.exit(1);
});

这个完整的服务器实现包含了以下关键组件:

  1. MCPDemoServer类:封装了服务器的全部功能

    • setupLogger(): 设置日志系统
    • setupMiddleware(): 配置Express中间件
    • setupHandlers(): 注册工具和资源处理器
    • start(): 启动服务器
  2. 中间件配置

    • JSON解析器:处理请求体
    • 日志中间件:记录所有请求
    • CORS中间件:处理跨域请求
    • 速率限制中间件:防止滥用
  3. API路由

    • /tools/:name:访问各种工具功能
    • /resources/:type:访问各种资源

这种结构设计使得服务器代码更加模块化和可维护,同时提供了完善的安全和日志功能。

部署脚本

为了简化部署过程,我们可以创建一个部署脚本,它会自动创建必要的目录、检查配置文件、安装依赖并启动服务器:

// scripts/deploy.js - 部署辅助脚本
import fs from 'fs/promises';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

async function deploy() {
  try {
    // 1. 确保目录结构存在
    console.log('创建目录结构...');
    await fs.mkdir('./logs', { recursive: true });
    await fs.mkdir('./src/config', { recursive: true });
    await fs.mkdir('./src/lib', { recursive: true });
    await fs.mkdir('./src/server', { recursive: true });
    await fs.mkdir('./src/client', { recursive: true });
    
    // 2. 检查配置文件
    console.log('检查配置文件...');
    try {
      await fs.access('./src/config/server.config.js');
      console.log('配置文件已存在');
    } catch {
      console.log('创建默认配置文件...');
      const defaultConfig = `export const serverConfig = {
        port: 3000,
        host: 'localhost',
        logging: { level: 'info', filename: './logs/server.log' }
      };`;
      await fs.writeFile('./src/config/server.config.js', defaultConfig);
    }
    
    // 3. 安装依赖
    console.log('安装依赖...');
    await execAsync('npm install');
    
    // 4. 启动服务器
    console.log('启动MCP服务器...');
    await execAsync('node src/server/index.js');
  } catch (error) {
    console.error('部署失败:', error);
  }
}

// 执行部署
deploy();

这个部署脚本执行了以下步骤:

  1. 创建必要的目录结构
  2. 检查并创建默认配置文件(如果不存在)
  3. 安装项目依赖
  4. 启动MCP服务器

通过这个脚本,您可以一键完成所有部署步骤,无需手动执行多个命令。

完整启动流程

如果您想手动执行每个步骤,可以按照以下流程操作:

# 1. 安装依赖
npm install

# 2. 创建日志目录
mkdir -p logs

# 3. 检查配置
node -e "console.log('验证配置...')"

# 4. 启动服务器
node src/server/index.js

# 5. 在新终端测试服务
curl http://localhost:3000/tools/processText -H "Content-Type: application/json" \
     -d '{"text":"Hello World","operation":"wordCount"}'
# 预期输出: {"count":2}

这个流程确保了所有必要的准备工作都已完成,并验证服务器是否正常运行。最后的curl命令测试了文本处理功能,如果一切正常,您应该能看到返回的单词数量。

三,整体实现代码逻辑讲解

MCP服务的整体实现遵循了一种模块化和可扩展的设计理念,主要包含以下几个关键部分:

1. 服务端初始化与配置

MCP服务的第一步是初始化服务器环境和配置。这个过程包括:

  • 安装必要依赖(Node.js、winston、express、dotenv)
  • 创建配置文件,管理服务器参数(端口、主机名、安全设置等)
  • 初始化MCPServer实例,准备注册工具和资源处理器

服务端的核心是MCPServer类,它提供了工具和资源注册的功能,通过Map数据结构存储各种处理器。完整的服务器实现(MCPDemoServer类)在此基础上添加了日志记录、中间件配置和API路由定义,使其成为一个功能完整的HTTP服务器。

2. 注册服务功能

MCP服务的核心是其功能注册机制,允许以插件式架构添加各种功能:

  • 工具注册:使用registerTool方法注册各种处理工具
  • 资源处理器:使用registerResourceHandler注册资源访问方法
  • 每个工具和资源处理器都是独立的功能单元,支持异步操作

我们在示例中注册了两类工具(文本处理和数值计算)和一种资源处理器(文件读取),它们共同构成了MCP服务的基本功能。

3. 客户端SDK实现

为了便于应用程序与MCP服务交互,实现了客户端SDK:

  • 基础客户端类:MCPClient封装了与服务器通信的基本方法
  • 扩展客户端类:MCPDemoClient添加了日志、错误处理和功能封装
  • 客户端类提供语义化API,简化服务调用流程

客户端SDK采用了分层设计,底层的MCPClient负责通信细节,上层的MCPDemoClient关注业务逻辑和错误处理,这种设计使得应用代码更加清晰和易于维护。

4. 安全性和性能考虑

完整的MCP服务实现考虑了多方面的安全性和性能因素:

  • CORS设置:控制跨域请求,只允许特定来源的访问
  • 请求限制:实现IP黑名单和请求速率限制,防止服务滥用
  • 错误处理:全面的错误捕获和日志记录,便于问题排查
  • 配置分离:将配置项抽离到单独文件,方便不同环境的部署

四,可扩展的内容

MCP服务设计为高度可扩展的架构,以下是可以进一步扩展的方向:

1. 核心服务扩展

MCPServer类设计为可扩展架构,允许注册任意数量的工具和资源处理器。您可以添加新的工具功能,如:

  • 数据转换功能(JSON、XML、CSV等格式转换)
  • 机器学习模型集成(图像识别、文本分类等)
  • 第三方API集成(地图服务、支付系统等)

2. 配置系统扩展

配置文件支持多环境部署,可扩展的方面包括:

  • 多环境配置(开发、测试、生产)
  • 动态配置加载(基于环境变量或配置服务)
  • 配置验证和自动修复机制

3. 中间件扩展

Express中间件层可以添加更多功能:

  • 身份验证和授权(JWT、OAuth等)
  • 请求压缩和缓存策略
  • 高级监控和性能分析

4. 客户端功能扩展

客户端SDK可以扩展更多功能:

  • 离线模式和数据同步
  • 批处理和队列机制
  • 智能重试和熔断器模式

5. 部署与运维扩展

部署脚本可以扩展为完整的CI/CD流程:

  • 容器化部署(Docker、Kubernetes)
  • 自动化测试和质量检查
  • 监控和告警系统集成

五, 学习资源

在学习和开发MCP服务的过程中,以下资源将非常有帮助:

1. 搭建MCP服务的快速入门

快速入门资源可以帮助您迅速理解MCP服务的基本概念和使用方法:

  • MCP SDK文档: https://docs.anthropic.com/mcp/
    这里包含了MCP SDK的完整API参考、使用示例和最佳实践。

  • API参考: https://api.anthropic.com/mcp/
    提供了详细的API端点说明、请求/响应格式和错误处理指南。

2. MCP基础学习相关文章链接

3. 相关代码链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习的周周啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值