Files
linshen 1a55a5e719 feat(server): 集成 MCP 服务器
本次提交主要集成了 MCP 服务器,为系统增加了用户提示词优化工具,并通过优化部署流程,提升了整体易用性。

具体变更内容包括:

* **功能增强:**
    * 集成 MCP 服务器,提供用户和系统提示词优化工具,支持 stdio 和 HTTP 两种传输方式,并集成了 Claude Desktop。
    * 实现基于会话的 HTTP 传输,允许多客户端连接,并为每个会话创建独立的 MCP 服务器实例,确保会话间的隔离性。

* **部署优化:**
    * 将 MCP 服务器端口变更为与 Web 界面共享 80 端口,通过路径区分,简化了 Docker 部署配置,降低了部署复杂度。
    * 优化 Docker 部署流程,使用 Supervisor 进行进程管理,并改进模板参数(使用枚举类型 + 默认值),同时提供了包含 MCP 服务器使用说明的 Docker 部署文档。

* **代码优化与重构:**
    * 优化模型选择逻辑,提高模型选择的准确性。
    * 优化日志记录功能,支持更灵活的日志级别设置,并添加了详细的错误提示和调试信息,方便问题排查。
    * 重构代码,分离构建和启动入口,优化环境变量加载和模型初始化逻辑,提高了代码的可维护性和可扩展性,并解决了构建副作用问题。

* **文档更新:**
    * 更新工具描述和使用说明,提供了用户和系统提示词工具的具体示例,并补充了迭代提示词工具的改进需求描述和使用场景。
    * 更新 Docker 部署方案,包含了 `docker-compose.yml`、`Dockerfile` 和 `env.local.example` 配置示例,并更新了 README 文档以明确连接方式。
    * 更新 `nginx.conf`,使用环境变量 `NGINX_PORT`,修改 `start-services.sh`,增加 nginx 配置处理,更新 `supervisord.conf`,调整 MCP 服务器启动方式,优化 `Dockerfile`,安装额外依赖并调整工作目录,调整环境变量加载机制,使用 `preload-env.cjs`。

* **其他:**
    * 提供快速开始指南、环境变量配置和问题排除等文档,更新了相关文档链接和获取帮助指引,并完成了基础测试用例和开发/设计文档。

本次更新旨在提升用户在提示词优化方面的能力,并简化部署流程,提高系统的整体可用性和可维护性。
2025-07-27 00:31:23 +08:00

7.8 KiB
Raw Permalink Blame History

MCP Server 模块开发经验总结

🎯 核心经验

零侵入性设计原则

在开发 MCP Server 模块时,我们采用了零侵入性设计原则,完全不修改 Core 模块代码,通过适配层实现功能集成。这种设计方式带来了以下好处:

  1. 保持架构清洁:避免了对核心模块的修改,保持了代码的纯净性
  2. 降低维护成本:核心模块的更新不会影响到 MCP Server 模块
  3. 提高可测试性:可以独立测试 MCP Server 模块和 Core 模块

实现要点

  • 绝对不修改 Core 模块代码:所有适配都在 MCP server 层完成
  • 使用现有接口:严格按照 Core 模块的现有 API 进行调用
  • 完整服务初始化:必须初始化所有 Core 服务依赖

Core 模块服务化架构匹配

Core 模块的服务化架构与 MCP 协议高度匹配,这为零侵入性设计提供了良好的基础:

  • 所有核心功能都通过服务接口暴露
  • 服务间依赖关系清晰,便于适配层管理
  • 参数和返回值格式规范,便于协议转换

分层架构设计

采用分层架构设计,将 MCP 协议层、传输层和服务适配层分离,使得各层职责清晰,便于维护和扩展。

🛠️ 技术实现经验

环境变量加载时机问题

在 Node.js 应用中,环境变量的加载时机非常重要。我们遇到的问题是 Core 模块在导入时就初始化了配置,而此时环境变量还未加载。

问题现象

  • Node.js 环境变量必须在模块导入前加载,否则模块初始化时读取不到
  • Core 模块在导入时就会读取环境变量进行配置初始化

解决方案

  1. 使用 Node.js 的 -r 参数在模块系统初始化前预加载环境变量
  2. 创建预加载脚本preload-env.js支持多路径查找适应不同部署场景
  3. 统一配置在项目根目录,便于管理
  4. 支持静默加载,避免找不到配置文件时的错误

实现细节

node -r ./preload-env.js dist/index.js

构建时副作用控制

在使用 tsup 构建工具时,需要注意入口文件的副作用问题。

问题现象

  • 构建工具(如 tsup执行模块级代码时会导致服务器意外启动
  • 构建过程中占用端口,影响开发体验

最佳实践

  1. 入口文件只导出,不执行任何有副作用的代码
  2. 使用单独的启动文件负责执行主逻辑
  3. 避免在模块顶层调用有副作用的函数
  4. 分离构建入口和启动入口

Windows 进程管理兼容性

在 Windows 环境下开发时,需要注意进程管理的特殊问题。

问题现象

  • Windows 下 concurrently 等进程管理工具信号处理有问题
  • Ctrl+C 无法正确终止子进程
  • 复杂的进程管理导致开发体验差

解决方案

  1. 避免使用复杂的进程管理工具如 concurrently
  2. 分离构建和启动流程,使用简单的 npm scripts
  3. 使用简单的 npm scripts 替代复杂的命令组合
  4. 在 Windows 环境下优先考虑简单的解决方案

MCP 协议调试技巧

在开发 MCP Server 时,调试是一个重要环节。

调试工具

  1. MCP Inspector:使用官方调试工具进行协议级别测试
  2. 分层测试策略:先测试 Core 服务再测试 MCP 包装,快速定位问题
  3. 日志驱动调试:详细记录每个环节状态,快速定位问题

测试方法

  • 使用自定义 MCP Inspector 测试工具验证功能
  • 中英文输入测试确保国际化支持
  • 自定义参数测试验证参数适配正确性

🚫 避坑指南

环境变量加载时机陷阱

问题:环境变量在模块导入后才加载,导致配置无法正确初始化 原因Node.js 模块系统在导入时就会执行模块代码,此时环境变量可能还未加载 解决方案:使用 Node.js 的 -r 参数预加载环境变量脚本 避免方法:在项目启动脚本中统一处理环境变量加载

构建时副作用陷阱

问题:构建过程中意外执行了服务器启动代码,占用端口 原因:构建工具会执行模块级代码来分析依赖关系 解决方案:分离构建入口和启动入口,确保构建过程无副作用 避免方法:入口文件只做导出,不执行任何有副作用的操作

Windows 信号处理陷阱

问题:在 Windows 下使用 concurrently 等工具时信号处理有问题,无法正确终止进程 原因Windows 的信号处理机制与 Unix 系统不同 解决方案:避免使用复杂的进程管理工具,采用简单的 npm scripts 避免方法:在 Windows 环境下优先选择简单的解决方案

存储层环境差异陷阱

问题:不同环境下存储层配置不一致 原因:浏览器环境和 Node.js 环境的存储机制不同 解决方案:使用 StorageFactory 适配不同环境,配置时选择正确的 Provider 避免方法:在项目初期就明确存储策略,避免后期大规模修改

🔄 架构设计经验

适配器模式的深度应用

在 MCP Server 模块中,我们大量使用了适配器模式,将 MCP 协议的接口转换为 Core 模块的接口。这种设计模式的优势包括:

  1. 解耦MCP 协议层和 Core 服务层完全解耦
  2. 可扩展性:可以轻松添加新的适配器支持更多功能
  3. 可维护性:每个适配器职责单一,便于维护

实现复杂度考虑

  • 服务管理:需要管理完整的 Core 服务栈
  • 参数转换MCP 简单参数 → Core 复杂参数格式
  • 配置管理:默认模型、模板的配置和验证
  • 错误处理Core 错误 → MCP 协议错误的转换

无状态设计的价值

MCP Server 采用了无状态设计,使用内存存储,无持久化,每次重启都是全新状态。这种设计的优势:

  1. 简化部署:无需考虑数据持久化和状态管理
  2. 提高可靠性:避免了状态不一致的问题
  3. 便于测试:每次测试都是全新的环境
  4. 专业工具定位:符合工具类应用的使用模式

独立模块设计原则

保持依赖关系清洁,避免循环依赖:

  • 只依赖 Core 模块,避免 UI 层污染
  • 按功能分层组织,便于维护和扩展
  • 统一错误转换层,提供一致的用户体验

📚 学习资源与工具配置

有用文档

开发工具配置

  • MCP TypeScript SDK:使用 registerTool/registerResource 方法,支持 Zod 验证
  • tsup 构建工具:配置 ESM/CJS 双格式输出,与 Core 模块保持一致
  • 环境变量预加载:创建 preload-env.js 脚本,支持多路径查找和静默加载

代码实现模式

  • MCP Tools 实现模式:使用 registerTool + Zod 验证
  • 存储层适配StorageFactory.create('memory') - 内存存储配置
  • 参数适配模式MCP 简单参数 → Core 复杂参数的转换

🎯 关键决策记录

技术选型决策

  • MCP SDK:选择官方 TypeScript SDK原因类型安全、完整功能支持
  • 存储方案:选择 MemoryStorageProvider原因适合工具类应用无持久化需求
  • 传输方式:支持 stdio + HTTP 双模式,原因:灵活部署,满足不同使用场景
  • 验证库:选择 Zod原因项目已使用与 MCP SDK 完美匹配

架构决策

  • 依赖关系:只依赖 Core 模块,原因:保持架构清洁,避免 UI 层污染
  • 模块结构:按功能分层组织,原因:便于维护和扩展
  • 错误处理:统一错误转换层,原因:提供一致的用户体验
  • 零侵入性原则:完全不修改 Core 代码,原因:保持核心模块纯净性