图片来源:Unsplash
Web应用 vs MCP Server


1. 从“写一个工具函数”到“部署一个MCP Server”——Agent工程化的必经之路

在早期AI Agent开发中,我们常将工具逻辑直接写在代码里:

# ❌ 内嵌工具(难以复用、无法跨语言)
def get_weather(city):
    return requests.get(f"https://api.weather.com/v1/{city}").json()

但当Agent数量增长、工具需被多个Agent共享、或涉及敏感操作(如数据库写入)时,将工具封装为独立服务成为必然选择。

于是,MCP(Model Context Protocol) 应运而生——它定义了Agent与外部工具/服务的标准通信协议。而MCP Server,就是这些工具的服务端实现。

💡 类比理解:

  • 内嵌工具 ≈ 在Controller里写SQL
  • MCP Server ≈ 独立微服务 + 标准API契约

本文将聚焦MCP Server的生命周期管理,教你如何像部署Web应用一样,可靠地运行和维护AI Agent的“工具后端”。


2. MCP协议与Web技术的天然契合

MCP与Web栈

MCP协议基于HTTP/WebSocket,其设计充分借鉴了Web工程最佳实践:

MCP 概念 Web 类比 说明
MCP Server 微服务(如用户服务) 独立进程,暴露标准接口
Orchestrator 服务注册中心(Eureka/Nacos) Agent通过它发现可用工具
Capabilities OpenAPI/Swagger 文档 描述Server能做什么(JSON Schema)
Health Check /actuator/health 监控Server是否存活
Graceful Shutdown Spring Boot 优雅停机 处理完当前请求再退出

✅ 关键优势:
Web开发者无需学习全新网络模型——MCP就是“为AI Agent定制的RESTful+WebSocket”。


3. MCP Server生命周期四阶段详解

MCP Server的生命周期可分为四个关键阶段,每个阶段都需精心处理:

阶段1:启动(Startup)

  • 初始化工具逻辑(如数据库连接池、API密钥)
  • 启动HTTP/WebSocket服务端口
  • 向Orchestrator注册自身能力
// 注册消息示例
{
  "serverId": "weather-mcp-01",
  "capabilities": [
    {
      "name": "get_current_weather",
      "description": "获取城市当前天气",
      "parameters": { "type": "object", "properties": { "city": { "type": "string" } } }
    }
  ],
  "endpoint": "ws://weather-mcp:8080/mcp"
}

阶段2:运行(Runtime)

  • 接收Agent通过Orchestrator路由来的调用请求
  • 执行工具逻辑并返回结果
  • 定期发送心跳(防止被Orchestrator标记为离线)

阶段3:健康检查(Health Monitoring)

  • 提供/health端点供Orchestrator轮询
  • 检查依赖服务(如数据库、第三方API)是否可用

阶段4:销毁(Shutdown)

  • 收到SIGTERM信号(如K8s pod终止)
  • 向Orchestrator发送unregister事件
  • 停止接收新请求,等待进行中任务完成
  • 释放资源(关闭连接池、清理缓存)

⚠️ 忽略任一阶段,都将导致Agent调用失败或资源泄漏。


4. 实战:用Spring Boot构建生产级MCP Server

实战代码

我们将实现一个天气查询MCP Server,支持Agent调用get_current_weather

4.1 技术栈

  • Java 17 + Spring Boot 3.2
  • WebSocket(STOMP over WebSocket)
  • Micrometer(健康监控)
  • Maven(依赖管理)

4.2 项目结构

weather-mcp/
├── pom.xml
├── src/main/java
│   └── com/example/weathermcp
│       ├── WeatherMcpApplication.java
│       ├── config/McpLifecycleConfig.java    // 生命周期管理
│       ├── controller/HealthController.java  // 健康检查
│       ├── service/WeatherService.java       // 工具逻辑
│       └── websocket/McpWebSocketHandler.java // WebSocket处理
└── resources/application.yml

4.3 关键代码实现

pom.xml 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
</dependencies>

McpLifecycleConfig.java(生命周期核心)

@Component
public class McpLifecycleConfig implements ApplicationRunner, DisposableBean {

    private final RestTemplate restTemplate;
    private final String orchestratorUrl = "http://agent-orchestrator:9000/register";
    private final String serverId = "weather-mcp-" + UUID.randomUUID().toString().substring(0, 6);

    public McpLifecycleConfig(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    // 阶段1: 启动时注册
    @Override
    public void run(ApplicationArguments args) {
        Capability weatherCap = new Capability("get_current_weather",
            "获取指定城市的当前天气", 
            Map.of("city", new Parameter("string", "城市名")));
        
        RegistrationRequest req = new RegistrationRequest(serverId, 
            List.of(weatherCap), 
            "ws://localhost:8080/mcp");
        
        restTemplate.postForEntity(orchestratorUrl, req, Void.class);
        System.out.println("✅ MCP Server registered: " + serverId);
    }

    // 阶段4: 销毁时注销
    @Override
    public void destroy() {
        UnregisterRequest req = new UnregisterRequest(serverId);
        restTemplate.postForEntity(orchestratorUrl + "/unregister", req, Void.class);
        System.out.println("🛑 MCP Server unregistered: " + serverId);
    }
}

HealthController.java(阶段3:健康检查)

@RestController
public class HealthController {

    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        // 检查第三方天气API是否可达
        boolean weatherApiOk = checkWeatherApi();
        if (weatherApiOk) {
            return ResponseEntity.ok(Map.of("status", "UP"));
        } else {
            return ResponseEntity.status(503).body(Map.of("status", "DOWN"));
        }
    }
}

McpWebSocketHandler.java(阶段2:运行时处理)

@Component
public class McpWebSocketHandler extends TextWebSocketHandler {

    private final WeatherService weatherService;

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        try {
            McpRequest req = parseRequest(message.getPayload());
            if ("get_current_weather".equals(req.getToolName())) {
                String city = (String) req.getArguments().get("city");
                String result = weatherService.getCurrentWeather(city);
                session.sendMessage(new TextMessage(result));
            }
        } catch (Exception e) {
            session.sendMessage(new TextMessage("{\"error\":\"" + e.getMessage() + "\"}"));
        }
    }
}

4.4 前端监控面板(Vue 3)

<template>
  <div class="agent-status">
    <h3>MCP Server 状态</h3>
    <div v-for="server in servers" :key="server.id">
      <span :class="{ online: server.status === 'UP' }">
        {{ server.id }} - {{ server.status }}
      </span>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const servers = ref([])

onMounted(async () => {
  // 从Orchestrator获取所有注册的MCP Server
  const res = await fetch('http://agent-orchestrator:9000/servers')
  servers.value = await res.json()
})
</script>

<style scoped>
.online { color: green; }
</style>

4.5 生命周期流程图

启动 Spring Boot

初始化工具逻辑

向Orchestrator注册能力

运行中

接收Agent调用

定期心跳

health 健康检查

SIGTERM 信号

发送 unregister

停止接收新请求

等待任务完成

释放资源,退出


5. Web开发者常见陷阱与避坑指南

运维陷阱

❌ 陷阱1:启动后未注册,Agent找不到工具

解决方案:在ApplicationRunner中强制注册,失败则抛出异常终止启动。

❌ 陷阱2:进程被kill -9,Orchestrator残留“僵尸”Server

解决方案

  • 使用DisposableBean确保优雅注销
  • Orchestrator侧设置心跳超时(如30秒无心跳自动注销)

❌ 陷阱3:健康检查只检查自身,忽略下游依赖

解决方案/health端点必须验证所有关键依赖(数据库、第三方API)。

❌ 陷阱4:WebSocket连接未关闭,导致文件描述符泄漏

解决方案:在WebSocketHandlerafterConnectionClosed中显式清理资源。

❌ 陷阱5:多实例部署时ServerId冲突

解决方案:ServerId包含随机后缀或Pod名称(K8s中可通过环境变量注入)。


6. 总结与AI Agent运维学习路径

MCP Server是AI Agent系统工程化的基石。掌握其生命周期管理,意味着你已从“写Demo”迈向“上生产”。

🔜 推荐学习路径:

  1. 基础:理解MCP协议规范(modelcontextprotocol.ai
  2. 实践:用Spring Boot/Express实现一个MCP Server(如数据库查询、邮件发送)
  3. 监控:集成Prometheus + Grafana监控MCP Server指标(调用次数、延迟、错误率)
  4. 编排:在K8s中部署MCP Server,配置Liveness/Readiness探针
  5. 安全:为MCP通信添加mTLS双向认证

📚 可靠资源:

🚀 行动建议:
将你下一个内部工具(如日志查询、报表生成)封装为MCP Server。让Agent们通过标准协议调用它——这不仅是技术升级,更是工程思维的跃迁。


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐