核心概念解释
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);
}
}
如何选择?
选择独立进程的情况:
- 多语言技术栈:不同服务用不同语言编写
- 独立扩展需求:某些服务压力大,需要独立扩展
- 故障隔离要求高:一个服务崩溃不能影响其他
- 团队协作:不同团队负责不同服务
- 已有服务复用:已有现成的独立服务
选择Spring Boot内集成的情况:
- 技术栈统一:全部用Java/Kotlin/Scala
- 简单快速:原型开发,快速上线
- 资源有限:服务器资源有限,不想开多个进程
- 本地开发:开发调试方便
- 内部工具:不对外提供单独服务
实际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接口,简单但耦合
我的建议:
- 如果是生产环境、需要扩展、多语言团队 → 选择独立进程
- 如果是原型开发、小团队、快速迭代 → 选择Spring Boot内集成
- 可以考虑渐进式架构:先用Spring Boot集成,后续根据需要拆分为独立进程
你需要根据具体的业务需求、团队能力和运维能力来做出选择。