news 2026/9/7 19:25:01

基于 Spring AI+MCP 协议实现大模型调用本地自定义工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Spring AI+MCP 协议实现大模型调用本地自定义工具

一、前言

随着 Spring AI 生态不断完善,MCP(Model Context Protocol) 成为了 AI 模型与本地自定义工具通信的核心协议。通过 MCP 协议,我们可以将本地自定义的业务工具方法暴露为 AI 可调用的工具,让大模型自动调用本地接口完成业务逻辑,极大拓展 AI 应用的落地能力。

本文将从零搭建 MCP 服务端(WebFlux 异步)+ MCP 客户端 完整工程,实现:

  • 对比「启用 MCP 工具调用」和「普通大模型调用」的差异
  • 解决 MCP 启动失败、Web 容器冲突等经典踩坑问题

整套案例基于 Spring Boot + Spring AI + 阿里 DashScope 实现,可直接落地复用。

二、核心原理与踩坑前置说明

2.1 MCP 核心作用

MCP 协议实现了 大模型 <-> 本地工具 的双向通信,客户端向 MCP 服务端发现工具、传递参数,服务端执行本地业务逻辑并返回结果,大模型基于结果生成最终回答。

2.2 关键避坑点

spring-ai-starter-mcp-server-webflux依赖 绝对不能与 spring-boot-starter-web 共存!

  • web 依赖会强制使用 Tomcat 容器启动
  • MCP WebFlux 依赖需要 Netty 容器支撑
  • 两者共存时,程序可正常启动,但 MCP 服务端异常,客户端无法连接调用工具

✅ 解决方案:MCP 服务端仅引入 webflux 相关依赖,剔除 web 依赖;客户端可正常引入 web 依赖。

三、MCP 服务端搭建

服务端核心职责:定义自定义工具、注册 MCP 工具回调、开启异步 MCP 服务,对外暴露工具调用能力。

3.1 Pom 核心依赖

服务端禁止引入 spring-boot-starter-web,仅保留核心启动器和 MCP WebFlux 依赖:

<dependencies>
<!-- Spring Boot 核心启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MCP 服务端 WebFlux 异步依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
</dependencies>

3.2 服务端配置文件 application.yml

# 服务端口
server.port=8014

# 全局编码配置
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

# 应用名称
spring.application.name=SAA-14LocalMcpServer

# MCP 服务端核心配置
spring.ai.mcp.server.type=async
spring.ai.mcp.server.name=customer-define-mcp-server
spring.ai.mcp.server.version=1.0.0

3.3 自定义工具业务类(天气查询)

通过 @Tool 注解标记工具方法,配置方法描述,用于大模型识别工具能力:

package com.atguigu.study.service;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import java.util.Map;

/**
* 自定义MCP工具服务:天气查询工具
*/
@Service
public class WeatherService
{
/**
* @Tool 注解:声明为AI可调用工具,description为工具描述,供大模型识别用途
*/
@Tool(description = "根据城市名称获取天气预报")
public String getWeatherByCity(String city)
{
Map<String, String> weatherMap = Map.of(
"北京", "11111降雨频繁,其中今天和后天雨势较强,部分地区有暴雨并伴强对流天气,需注意",
"上海", "22222多云,15℃~27℃,南风3级,当前温度27℃。",
"深圳", "333333多云40天,阴16天,雨30天,晴3天"
);
return weatherMap.getOrDefault(city, "抱歉:未查询到对应城市!");
}
}

3.4 MCP 工具注册配置类

将自定义的工具类注册为 ToolCallbackProvider,暴露给 MCP 客户端调用:

package com.atguigu.study.config;

import com.atguigu.study.service.WeatherService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* MCP服务配置:注册自定义工具,对外暴露调用能力
*/
@Configuration
public class McpServerConfig
{
/**
* 将自定义工具方法注册为MCP可调用工具
*/
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService)
{
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService)
.build();
}
}

四、MCP 客户端搭建

客户端核心职责:连接远程 MCP 服务端、加载远程工具、结合大模型实现自动工具调用、提供接口测试能力。客户端可正常引入 web 依赖。

4.1 Pom 核心依赖

<dependencies>
<!-- Web依赖:客户端需要提供接口测试能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 阿里通义千问大模型依赖 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- MCP 客户端依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
</dependencies>

4.2 客户端配置文件 application.yml

# 服务端口
server.port=8015

# 全局编码配置
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

# 应用名称
spring.application.name=SAA-15LocalMcpClient

# 阿里通义千问API密钥(替换为自己的密钥)
spring.ai.dashscope.api-key=${aliQwen-api}

# MCP客户端核心配置
spring.ai.mcp.client.type=async
spring.ai.mcp.client.request-timeout=60s
# 开启MCP工具回调
spring.ai.mcp.client.toolcallback.enabled=true
# 绑定本地MCP服务端地址
spring.ai.mcp.client.sse.connections.mcp-server1.url=http://localhost:8014

4.3 ChatClient 集成 MCP 工具配置

将 MCP 远程工具注入 ChatClient,实现大模型自动感知并调用远程工具:

package com.atguigu.study.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* AI 客户端配置:集成MCP远程工具
*/
@Configuration
public class SaaLLMConfig
{
/**
* 构建集成MCP工具的ChatClient
* 自动加载MCP服务端暴露的所有工具方法
*/
@Bean
public ChatClient chatClient(ChatModel chatModel, ToolCallbackProvider tools)
{
return ChatClient.builder(chatModel)
// 注入MCP远程工具回调
.defaultToolCallbacks(tools.getToolCallbacks())
.build();
}
}

4.4 测试控制器(对比MCP启用/关闭效果)

提供两个接口:分别为启用MCP工具调用、原生大模型调用(无工具),直观对比差异:

package com.atguigu.study.controller;

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
* MCP客户端测试控制器
*/
@RestController
public class McpClientController
{
// 集成MCP工具的AI客户端
@Resource
private ChatClient chatClient;

// 原生AI模型(无MCP工具)
@Resource
private ChatModel chatModel;

/**
* 带MCP工具调用的流式对话
* 大模型会自动调用MCP服务端的天气工具
*/
@GetMapping("/mcpclient/chat")
public Flux<String> chat(@RequestParam(name = "msg",defaultValue = "北京") String msg)
{
System.out.println("【使用MCP工具调用】");
return chatClient.prompt(msg).stream().content();
}

/**
* 原生大模型调用(无本地工具)
* 大模型仅通过自身知识库回答,无法获取本地自定义数据
*/
@GetMapping("/mcpclient/chat2")
public Flux<String> chat2(@RequestParam(name = "msg",defaultValue = "北京") String msg)
{
System.out.println("【未使用MCP工具调用】");
return chatModel.stream(msg);
}
}

五、项目启动与测试

5.1 启动顺序

  1. 先启动 MCP 服务端(8014),保证 MCP 服务正常监听
  2. 再启动 MCP 客户端(8015),自动连接服务端加载工具

5.2 接口测试

1、启用 MCP 工具调用

请求地址:http://localhost:8015/mcpclient/chat?msg=上海天气怎么样

效果:大模型自动识别需要调用本地天气工具,请求 8014 服务端接口,返回自定义的本地天气数据。

2、未启用 MCP 工具调用

请求地址:http://localhost:8015/mcpclient/chat2?msg=上海天气怎么样

效果:大模型仅通过自身知识库回答实时天气,无法读取我们自定义的本地天气数据。

六、常见问题总结

6.1 MCP客户端连接不上服务端

原因:服务端引入了 spring-boot-starter-web,导致容器变为 Tomcat,MCP 基于 Netty 的 WebFlux 服务失效。

解决:服务端删除 web 依赖,仅保留 MCP webflux 依赖。

6.2 大模型不会自动调用工具

  • 检查 @Tool 注解的 description 是否清晰准确,大模型依赖描述识别工具用途
  • 检查客户端是否正确注入 ToolCallbackProvider
  • 确认 MCP 客户端配置的服务端地址正确、网络通畅

6.3 工具参数匹配失败

保证工具方法参数名、参数类型与大模型推断的参数一致,简单字符串参数为最稳适配方案。

七、总结

本文完整实现了 Spring AI MCP 异步服务端+客户端 落地案例,核心要点如下:

  1. MCP 服务端基于 WebFlux 异步实现,严格规避 web 依赖冲突
  2. 通过 @Tool 注解+ToolCallbackProvider 实现自定义工具对外暴露
  3. 客户端集成 MCP 远程工具,让大模型具备调用本地业务接口的能力
  4. 区分原生大模型调用与工具调用的核心差异,适配业务落地场景

该方案可快速拓展至数据库查询、接口调用、文件处理等各类本地业务工具,是 Spring AI 本地化 AI 应用开发的核心方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 19:24:07

只做一件事,把产品做到极致:简申的长期主义与产品决策逻辑

1. 第一次注意到简申&#xff1a;一个只做一件事的团队长什么样聊简申之前&#xff0c;先讲我第一次注意到它的场景。那是在一个多品类消费品牌的选品会上&#xff0c;旁边坐了一位做供应链的老朋友。当时台上有人介绍自家产品线&#xff0c;一口气列了十几个SKU&#xff0c;从…

作者头像 李华
网站建设 2026/9/7 19:21:13

AIGC检测降重实战:从原理到工具,让你的论文更有“人味”

上周有个大三的专科生学弟给我发来一段消息&#xff0c;说自己的课程论文被AIGC检测标红了&#xff0c;红色比例接近一半&#xff0c;导师让他“自己重新写”。他觉得很冤&#xff1a;论文确实是自己从AI生成的内容一点点改出来的&#xff0c;不是直接交的机器稿。我把他的稿子…

作者头像 李华
网站建设 2026/9/7 19:20:40

微信小程序+SSM框架社团活动管理系统实战解析

1. 项目整体设计与思路拆解 1.1 核心需求解析 大学生社团活动管理&#xff0c;这个题目我相信很多计算机专业的同学都不陌生。每年毕设季&#xff0c;社团管理系统、社团活动管理平台这类选题几乎占据了半壁江山。为什么&#xff1f;因为它的业务边界清晰、用户角色明确、功能…

作者头像 李华
网站建设 2026/9/7 19:17:51

发布前文章测试:从占位符到六维检查的完整指南

发布之前&#xff0c;先别急着按下“群发”按钮。在内容行业里&#xff0c;“测试文章标题01”这种占位符文本经常会被直接推到生产环境——不是因为它藏着什么秘密&#xff0c;而是因为整个发布链条上&#xff0c;没有人对这篇文章做过一次完整的“验收测试”。我做过几年技术…

作者头像 李华
网站建设 2026/9/7 19:17:43

深度学习驱动的作物产量预测:从数据工程到模型实践

简介&#xff1a;面向需要复现深度学习作物产量预测研究的开发者&#xff0c;AAAI 2017最佳学生论文奖配套代码覆盖从遥感数据获取到模型训练与结果分析的完整链路。包内共54个文件&#xff0c;以38个Python脚本为核心&#xff0c;分别实现Google Earth Engine数据下载、图像切…

作者头像 李华