Spring AI + MCP实战:手把手教你为Java项目接入Claude的‘外挂’能力

想象一下,当你的Java后端服务突然拥有了让AI直接调用内部业务逻辑的能力——这不是科幻场景,而是通过Spring AI与MCP协议结合就能实现的真实技术方案。作为Java工程师,我们早已习惯用RESTful API构建服务边界,但MCP协议正在重新定义人机交互的边界。

1. 为什么Java项目需要MCP协议?

传统AI集成方案通常要求开发者将业务逻辑封装成API,再通过提示词工程让AI学会调用这些接口。这种模式存在两个致命缺陷:

  1. 上下文割裂:AI需要额外学习接口规范
  2. 权限失控:开放HTTP端点带来安全隐患

MCP协议通过标准化工具调用流程,实现了三个突破性改进:

  • 声明式工具注册:像Spring Bean一样定义AI可调用的函数
  • 沙箱化执行:所有调用经过权限校验和输入过滤
  • 协议级集成:无需额外暴露HTTP端口
// 传统API方式 vs MCP方式对比
+---------------------+---------------------------+
|      传统API        |           MCP            |
+---------------------+---------------------------+
| 需要设计Swagger文档 | 函数即工具(代码即文档)    |
| 需处理CORS等问题    | 内置跨协议通信支持        |
| 独立部署维护        | 与应用生命周期绑定        |
+---------------------+---------------------------+

提示:MCP特别适合已有成熟业务系统需要快速AI化的场景,能复用80%现有Java代码

2. 环境准备与基础配置

2.1 依赖引入与版本选择

在Spring Boot 3.x项目中添加关键依赖:

<dependencies>
    <!-- Spring AI核心 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-core</artifactId>
        <version>0.8.1</version>
    </dependency>
    
    <!-- MCP协议实现 -->
    <dependency>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-ai-mcp</artifactId>
        <version>0.5.0</version>
    </dependency>
    
    <!-- 可选:用于工具函数验证 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

注意版本兼容性矩阵:

Spring Boot Spring AI Java
3.1.x 0.8.x 17+
3.0.x 0.7.x 17+
2.7.x 0.6.x 11+

2.2 最小化配置示例

创建基础配置类开启MCP支持:

@Configuration
@EnableAiTools // 关键注解
public class AiConfig {
    
    @Bean
    FunctionCallback weatherService() {
        return FunctionCallback.builder()
            .name("getWeather")
            .description("获取指定城市天气信息")
            .function(city -> {
                // 实际业务逻辑实现
                return "晴转多云 25℃";
            })
            .build();
    }
}

3. 实战:构建计算器工具链

3.1 定义领域模型

首先建立数学运算的领域对象:

@Data
@AllArgsConstructor
class MathInput {
    private Double operand1;
    private Double operand2;
    private Operator operator;
    
    enum Operator {
        ADD, SUBTRACT, MULTIPLY, DIVIDE
    }
}

3.2 实现工具函数

创建具有自描述能力的计算器工具:

@Bean
FunctionCallback advancedCalculator() {
    return FunctionCallback.builder()
        .name("mathCalculator")
        .description("高级科学计算器,支持加减乘除")
        .inputType(MathInput.class) // 自动生成schema
        .function(input -> {
            MathInput math = (MathInput) input;
            switch(math.getOperator()) {
                case ADD: 
                    return math.getOperand1() + math.getOperand2();
                case SUBTRACT:
                    return math.getOperand1() - math.getOperand2();
                case MULTIPLY:
                    return math.getOperand1() * math.getOperand2();
                case DIVIDE:
                    if (math.getOperand2() == 0) {
                        throw new IllegalArgumentException("除数不能为零");
                    }
                    return math.getOperand1() / math.getOperand2();
                default:
                    throw new UnsupportedOperationException();
            }
        })
        .build();
}

3.3 配置MCP服务器

将工具注册到MCP服务端点:

@Bean
McpServer mcpServer(List<FunctionCallback> tools) {
    return McpServer.withDefaults()
        .info("科学计算服务", "1.0.0")
        .tools(ToolHelper.toToolRegistration(tools))
        .interceptor(new AuditInterceptor()) // 添加审计拦截器
        .start();
}

4. 高级技巧与生产级实践

4.1 工具组合与编排

MCP支持工具链式调用,实现复杂业务流:

@Bean
FunctionCallback financeAnalyzer() {
    return FunctionCallback.builder()
        .name("analyzeInvestment")
        .description("组合投资分析工具")
        .function(input -> {
            // 调用计算器工具
            Object calcResult = aiClient.callTool("mathCalculator", params);
            
            // 调用市场数据工具
            Object marketData = aiClient.callTool("getMarketData", params);
            
            // 业务逻辑处理
            return analysisResult;
        })
        .build();
}

4.2 安全控制策略

生产环境必须实现的三大安全措施:

  1. 权限验证:基于Spring Security的工具级鉴权
  2. 输入消毒:防止Prompt注入攻击
  3. 调用限流:避免AI过度调用
public class SecurityInterceptor implements McpInterceptor {
    
    @Override
    public ToolResponse intercept(ToolRequest request) {
        // 1. 验证调用者身份
        if (!hasPermission(request.getSession())) {
            throw new AccessDeniedException();
        }
        
        // 2. 检查输入参数
        if (containsMaliciousInput(request.getInput())) {
            throw new IllegalArgumentException();
        }
        
        // 3. 执行速率限制
        rateLimiter.check(request.getToolName());
        
        return chain.next(request);
    }
}

4.3 监控与可观测性

集成Micrometer实现全方位监控:

@Bean
MeterRegistryCustomizer<MeterRegistry> metricsConfig() {
    return registry -> {
        registry.config().meterFilter(
            new MeterFilter() {
                @Override
                public DistributionStatisticConfig configure(
                    Meter.Id id, DistributionStatisticConfig config) {
                    if (id.getName().startsWith("mcp.")) {
                        return DistributionStatisticConfig.builder()
                            .percentiles(0.5, 0.95, 0.99)
                            .build()
                            .merge(config);
                    }
                    return config;
                }
            });
    };
}

关键监控指标示例:

指标名称 类型 说明
mcp.tools.invocations Counter 工具调用次数统计
mcp.latency Timer 调用耗时分布
mcp.errors Gauge 错误率监控

5. 调试与问题排查

5.1 常见错误代码速查

遇到问题时优先检查这些方面:

  • MCP-401:工具调用未授权
  • MCP-422:输入参数不符合schema
  • MCP-429:调用频率超限
  • MCP-503:工具执行超时

5.2 交互式测试方法

使用cURL测试工具可用性:

# 获取已注册工具列表
curl http://localhost:8080/mcp/tools

# 模拟AI调用示例
curl -X POST http://localhost:8080/mcp/execute \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "mathCalculator",
    "input": {
      "operand1": 15,
      "operand2": 3,
      "operator": "DIVIDE"
    }
  }'

5.3 IDE调试技巧

在IntelliJ IDEA中配置调试器:

  1. 添加远程JVM调试配置
  2. 设置断点在ToolExecutionAspect
  3. 使用Evaluate Expression查看AI原始请求
// 调试时可查看的上下文信息
@Aspect
@Component
public class ToolExecutionAspect {
    
    @Around("@annotation(org.springframework.ai.tools.ToolExecutor)")
    public Object logToolExecution(ProceedingJoinPoint pjp) {
        // 这里可以检查输入输出
        return pjp.proceed();
    }
}

在实际项目落地过程中,最常遇到的坑是工具函数的输入输出类型定义不够明确。建议为每个工具定义强类型的DTO对象,而不是直接使用Map或JSONNode等动态结构。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐