【 AI智能体时代:一名Javaer的技术随想录】MCP服务部署架构

核心概念解释

1. MCP(Model Context Protocol)是什么?

MCP是AI模型与外部数据/工具交互的协议,类似于:

  • AI模型的"插件系统"
  • 让AI模型能够调用外部工具、访问数据
  • 类似于ChatGPT的插件或Function Calling

2. 两种部署模式对比

模式A:独立进程(stdio模式)

复制代码
每个MCP服务 → 独立进程 → 通过标准输入输出与主进程通信

特点

  • 每个MCP服务运行在单独的进程中
  • 通过进程间通信(IPC)与主程序交互
  • 通常使用stdio(标准输入/输出)进行通信
  • 类似微服务架构,每个服务独立部署

代码示例

javascript 复制代码
// MCP服务作为独立进程
// server.js
const { spawn } = require('child_process');

// 启动独立的MCP服务进程
const mcpService1 = spawn('node', ['service1.js']);
const mcpService2 = spawn('python', ['service2.py']);

// 通过stdio通信
mcpService1.stdout.on('data', (data) => {
  console.log('收到服务1的响应:', data.toString());
});

mcpService2.stdout.on('data', (data) => {
  console.log('收到服务2的响应:', data.toString());
});

优点

  • 隔离性好,一个服务崩溃不影响其他
  • 可以用不同语言编写(Node.js, Python, Java等)
  • 独立扩展,独立部署
  • 资源隔离,内存/CPU独立

缺点

  • 通信开销大(进程间通信)
  • 部署复杂度高
  • 需要管理多个进程

模式B:Spring Boot内集成(SSE/WebMvc)

复制代码
一个Spring Boot应用 → 包含多个MCP服务模块 → 通过HTTP接口提供服务

特点

  • 所有MCP服务打包在同一个Spring Boot应用中
  • 通过HTTP端点(REST API)提供服务
  • 可以使用SSE(Server-Sent Events)或WebMvc
  • 类似单体应用架构

代码示例

less 复制代码
// Spring Boot应用,集成多个MCP服务
@RestController
public class MCPServiceController {
    
    // 服务1:文件系统访问
    @PostMapping("/mcp/filesystem")
    public ResponseEntity<?> fileSystemService(@RequestBody MCPRequest request) {
        // 处理文件系统相关请求
        return ResponseEntity.ok(fileService.handle(request));
    }
    
    // 服务2:数据库查询
    @PostMapping("/mcp/database")
    public ResponseEntity<?> databaseService(@RequestBody MCPRequest request) {
        // 处理数据库查询请求
        return ResponseEntity.ok(dbService.handle(request));
    }
    
    // 服务3:SSE流式响应
    @GetMapping(value = "/mcp/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamService() {
        return Flux.interval(Duration.ofSeconds(1))
                  .map(seq -> "data: " + seq + "\n\n");
    }
}

优点

  • 部署简单,一个应用搞定
  • 通信效率高(进程内调用)
  • 统一管理,统一监控
  • 资源共享,减少重复依赖

缺点

  • 耦合度高,一个服务问题可能影响整体
  • 必须使用Java/Scala/Kotlin
  • 扩展性受限(需要整体扩展)

具体部署架构

方案1:独立进程部署(推荐用于生产)

bash 复制代码
# docker-compose.yml
version: '3.8'
services:
  mcp-service-1:
    build: ./service1
    command: ["node", "index.js"]
    
  mcp-service-2:
    build: ./service2
    command: ["python", "service.py"]
    
  mcp-service-3:
    build: ./service3
    command: ["java", "-jar", "service.jar"]
    
  ai-main-app:
    build: ./main-app
    depends_on:
      - mcp-service-1
      - mcp-service-2
      - mcp-service-3

方案2:Spring Boot内集成(推荐用于原型/简单场景)

typescript 复制代码
@SpringBootApplication
public class MCPServerApplication {
    
    @Bean
    public MCPServer mcpServer(List<MCPService> services) {
        return new MCPServer(services);
    }
    
    @Bean
    public MCPService fileService() {
        return new FileSystemService();
    }
    
    @Bean
    public MCPService databaseService() {
        return new DatabaseService();
    }
    
    @Bean
    public MCPService weatherService() {
        return new WeatherService();
    }
    
    public static void main(String[] args) {
        SpringApplication.run(MCPServerApplication.class, args);
    }
}

如何选择?

选择独立进程的情况:

  1. 多语言技术栈:不同服务用不同语言编写
  2. 独立扩展需求:某些服务压力大,需要独立扩展
  3. 故障隔离要求高:一个服务崩溃不能影响其他
  4. 团队协作:不同团队负责不同服务
  5. 已有服务复用:已有现成的独立服务

选择Spring Boot内集成的情况:

  1. 技术栈统一:全部用Java/Kotlin/Scala
  2. 简单快速:原型开发,快速上线
  3. 资源有限:服务器资源有限,不想开多个进程
  4. 本地开发:开发调试方便
  5. 内部工具:不对外提供单独服务

实际MCP服务示例

独立进程示例(Node.js):

php 复制代码
// service.js - 独立MCP服务
const { MCPServer } = require('@modelcontextprotocol/sdk');

const server = new MCPServer({
  name: "file-system-service",
  version: "1.0.0"
});

// 注册工具
server.tool("read_file", {
  description: "读取文件内容",
  parameters: {
    path: { type: "string", description: "文件路径" }
  }
}, async ({ path }) => {
  const content = fs.readFileSync(path, 'utf-8');
  return { content };
});

// 启动服务(stdio模式)
server.listen();

Spring Boot内集成示例:

less 复制代码
// MCP服务定义
@Service
public class FileSystemService implements MCPService {
    
    @Override
    public String getName() {
        return "file-system-service";
    }
    
    @MCPTool(name = "read_file", description = "读取文件内容")
    public String readFile(@MCPParam(name = "path") String path) {
        return Files.readString(Path.of(path));
    }
    
    @MCPTool(name = "list_files", description = "列出目录文件")
    public List<String> listFiles(@MCPParam(name = "directory") String dir) {
        return Arrays.asList(new File(dir).list());
    }
}

// HTTP端点
@RestController
@RequestMapping("/mcp")
public class MCPController {
    
    @Autowired
    private List<MCPService> services;
    
    @PostMapping("/{serviceName}/{toolName}")
    public ResponseEntity<?> executeTool(
            @PathVariable String serviceName,
            @PathVariable String toolName,
            @RequestBody Map<String, Object> params) {
        
        MCPService service = services.stream()
            .filter(s -> s.getName().equals(serviceName))
            .findFirst()
            .orElseThrow();
        
        Object result = service.executeTool(toolName, params);
        return ResponseEntity.ok(result);
    }
}

混合方案

你也可以采用混合方案:

typescript 复制代码
@Configuration
public class MCPConfig {
    
    // 内置服务
    @Bean
    public MCPService localService() {
        return new LocalService();
    }
    
    // 外部服务代理
    @Bean
    public MCPService externalFileService() {
        return new StdioMCPService("node", "/path/to/external-file-service.js");
    }
    
    @Bean
    public MCPService externalDatabaseService() {
        return new StdioMCPService("python", "/path/to/db-service.py");
    }
}

建议决策流程

markdown 复制代码
考虑因素:
1. 团队技能 → 全部Java?多语言? → 选择合适架构
2. 性能要求 → 高并发?低延迟? → 独立进程可能更好
3. 部署环境 → 云原生?容器化? → 独立进程适合K8s
4. 维护成本 → 小团队? → Spring Boot集成更简单
5. 扩展计划 → 未来要拆分成微服务? → 从独立进程开始

总结

问题回答

"4个MCP服务是作为独立进程(stdio模式)部署,还是作为同一个Spring Boot应用内的SSE/WebMvc模式?"

这个问题的本质是在问:

  • 独立进程:4个服务各自为政,通过进程间通信,隔离性好但复杂
  • Spring Boot集成:4个服务打包在一起,通过HTTP接口,简单但耦合

我的建议

  1. 如果是生产环境、需要扩展、多语言团队 → 选择独立进程
  2. 如果是原型开发、小团队、快速迭代 → 选择Spring Boot内集成
  3. 可以考虑渐进式架构:先用Spring Boot集成,后续根据需要拆分为独立进程

你需要根据具体的业务需求、团队能力和运维能力来做出选择。

相关推荐
千寻girling2 小时前
RabbitMQ 详细教程(38K字数)
java·后端·面试
Rust研习社2 小时前
Rust 多线程从入门到实战
开发语言·后端·rust
卷毛的技术笔记2 小时前
从“拆东墙补西墙”到“最终一致”:分布式事务在Spring Boot/Cloud中的破局之道
java·spring boot·分布式·后端·spring cloud·面试·rocketmq
袋鱼不重2 小时前
Hermes Agent 直连飞书机器人
前端·后端·ai编程
Pkmer3 小时前
古法编程: 深度解析Java调度器Timer
java·后端
小强19883 小时前
C++23/26新特性解析:那些让你放弃Boost库的杀手锏
后端
Aolith3 小时前
学 Express 被 app.use 绕晕了?用流水线思维一次性搞懂 5 种中间件
后端·express
BduL OWED3 小时前
将 vue3 项目打包后部署在 springboot 项目运行
java·spring boot·后端
二月龙3 小时前
从C++到WebAssembly:让高并发计算跑在浏览器里
后端