1、大模型MCP原理
MCP(Model Context Protocol,模型上下文协议),由 Anthropic 推出的一种开放标准,旨在统一大模型与外部数据源和工具之间的通信协议。
图中就是MCP的工作原理图,从第1步到第7步。其中第4和第5步就是MCP Client和MCP Server通过MCP Protocol进行通信。

第1步提问“今天南京的天气”

第2步AIAgent获取MCP Server的工具列表,第3步返回工具查询结果
POST /mcp/messages HTTP/1.1
request
{
"jsonrpc": "2.0",
"method": "tools/list",
"id": "3e5f6a3c-7",
"params": {
}
}
response
{
"jsonrpc": "2.0",
"id": 2,
"result": [
{
"type": "function",
"function": {
"description": "获取中国城市的当前天气信息。输入为城市名称(例如:杭州、上海)",
"name": "getWeather",
"parameters": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"arg0": {
"type": "string"
}
},
"required": [
"arg0"
]
}
}
}
]
}
第4步构建prompt后发起的大模型请求如下,其中tools对象即为工具列表,getWeather是我们使用定义好的MCP工具方法,并使用注解进行标注。
{
"messages": [
{
"content": "今天南京的天气",
"role": "user"
}
],
"model": "Qwen3-14B",
"stream": true,
"temperature": 0.7,
"tools": [
{
"type": "function",
"function": {
"description": "获取中国城市的当前天气信息。输入为城市名称(例如:杭州、上海)",
"name": "getWeather",
"parameters": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"arg0": {
"type": "string"
}
},
"required": [
"arg0"
]
}
}
}
]
}
第5步返回选中的参数和提取的参数
{
"id": "chatcmpl-1758595028.402406",
"object": "chat.completion.chunk",
"created": 1758595028,
"model": "qwen",
"choices": [
{
"index": 0,
"delta": {
"tool_calls": {
"type": "function",
"function": {
"name": "getWeather",
"arguments": {
"arg0": "南京"
}
},
"id": "call_702672"
},
"content": "<tool_call>"
},
"finish_reason": "<tool_call>"
}
]
}
第6步和第8步,MCP Client调用MCP Server,即为MCP协议。MCP 协议有两种通信机制:
1、基于标准输入输出的本地通信
2、基于[SSE]
这两种机制都使用 [JSON-RPC 2.0]
JSON-RPC2.0的通信示例如下所示:
POST /mcp/messages HTTP/1.1
request
{
"jsonrpc": "2.0",
"method": "tools/call",
"id": "3e5f6a3c-8",
"params": {
"name": "getWeather",
"arguments": {
"arg0": "南京"
}
}
}
response
{
"jsonrpc": "2.0",
"result": {
"content": "\"城市: 南京\\n天气情况: Overcast\\n气压: 1014(mb)\\n温度: 24°C (Feels like: null°C)\\n湿度: 83%\\n降水量:0.0 (mm)\\n风速: 15 km/h (E)\\n能见度: 10 公里\\n紫外线指数: 0\\n观测时间: 2025-09-19 07:41 AM\\n\""
},
"id": 1
}
第9步将调用MCP Server的结果和问题一起构建大模型请求
{
"messages": [
{
"content": "南京今天的天气",
"role": "user"
},
{
"content": "<tool_call>",
"role": "assistant",
"tool_calls": [
{
"id": "call_803714",
"type": "function",
"function": {
"name": "getWeather",
"arguments": "{\"arg0\": \"南京\"}"
}
}
]
},
{
"content": "\"城市: 南京\\n天气情况: Overcast\\n气压: 1014(mb)\\n温度: 24°C (Feels like: null°C)\\n湿度: 83%\\n降水量:0.0 (mm)\\n风速: 15 km/h (E)\\n能见度: 10 公里\\n紫外线指数: 0\\n观测时间: 2025-09-19 07:41 AM\\n\"",
"role": "tool",
"name": "getWeather",
"tool_call_id": "call_803714"
}
],
"model": "Qwen3-14B",
"stream": true,
"temperature": 0.7,
"tools": [
{
"type": "function",
"function": {
"description": "获取中国城市的当前天气信息。输入为城市名称(例如:杭州、上海)",
"name": "getWeather",
"parameters": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"arg0": {
"type": "string"
}
},
"required": [
"arg0"
]
}
}
}
]
}
第10步大模型返回答案
大模型返回的流式响应
{"id": "chatcmpl-1758183786.445879", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "{\"name\": "}, "finish_reason": null}]}
{"id": "chatcmpl-1758183786.546777", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "\"getWeather\", "}, "finish_reason": null}]}
{"id": "chatcmpl-1758183786.6477", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "\"arguments\": "}, "finish_reason": null}]}
{"id": "chatcmpl-1758183786.748445", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "{\"arg0\": "}, "finish_reason": null}]}
{"id": "chatcmpl-1758183786.849172", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "\"\u5357\u4eac"}, "finish_reason": null}]}
{"id": "chatcmpl-1758183786.94977", "object": "chat.completion.chunk", "created": 1758183786, "model": "qwen", "choices": [{"index": 0, "delta": {"content": "\"}}\n"}, "finish_reason": null}]}
处理后的前台响应

2、项目地址
github开源的地址:
https://github.com/xujinhelaw/chat-bot-ananas.git
gittee开源的地址:
https://gitee.com/xuhelaw/chat-bot-ananas.git
项目结构如下
└── mcp-server/ (mcp服务端模块)
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── org/
│ │ │ │ └── ananas/
│ │ │ │ └── mcpserver/
│ │ │ │ │ └── config/
│ │ │ │ │ └── ToolCallbackProviderConfig.java(mcp服务端配置文件)
│ │ │ │ │ ├── model/
│ │ │ │ │ ├── CurrentCondition.java(天气情况对象)
│ │ │ │ │ ├── WeatherDesc.java(天气描述对象)
│ │ │ │ │ └── WeatherResponse.java(天气情况响应对象)
│ │ │ │ │ ├── service/
│ │ │ │ │ ├── WeatherService.java(天气mcp服务接口)
│ │ │ │ │ └── WeatherServiceImpl.java(天气mcp服务)
│ │ │ │ │ └── McpServerApplication.java(mcp服务后端应用启动代码)
│ │ │ └── resources/
│ │ │ └── application.yml(mcp服务后端配置文件)
MCP实现的效果如下:
未开启mcp,无法返回当前的天气情况

开启mcp,返回当前的天气情况

3、MCP Server 服务端实现
3.1、 将大模型从Qwen2-7B升级为Qwen3-14B
升级如下依赖软件的版本
python=3.8.10 --> 3.9.15
bitsandbytes==0.41.1 -> 0.47.0
accelerate==1.0.1 -> 1.10.1
modelscope==1.9.5 --> 1.28.0
transformers==4.34.0 --> 4.53.0
sentence-transformers==3.0.0 --> 5.1.0
完整的environment.yaml如下所示:
name: qwen
channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
dependencies:
- python=3.9.15
- pip=24.2
- pip:
- -i https://pypi.tuna.tsinghua.edu.cn/simple/ # 这里是pip访问国外仓被墙,添加指定国内仓
- torch==2.7.0
- modelscope==1.28.0
- tiktoken==0.7.0
- accelerate==1.10.1
- fastapi==0.104.1
- uvicorn==0.24.0.post1
- requests==2.32.4
- modelscope==1.9.5
- transformers==4.53.0
- transformers_stream_generator==0.0.4
- peft==0.4.0
- datasets==2.10.1
- scipy==1.10.1
- bitsandbytes==0.47.0
- accelerate==1.10.1
- pip==24.2
- sentence_transformers==5.1.0
- pyarrow==14.0.0
3.2、 Maven依赖
<!-- Spring AI Start -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
</dependency>
<!-- Spring AI End -->
<!-- LLM MCP -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webmvc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--解决 SSE 连接将在30秒后终止bug,引入0.8.1版本-->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webmvc</artifactId>
<version>0.8.1</version>
</dependency>
<!-- LLM MCP End-->
3.2、 代码实现
application.yml配置文件的配置
server:
port: 8090
spring:
application:
name: mcp-server
ai:
mcp:
server:
name: mcp-server
version: 1.0.0
type: SYNC
sse-message-endpoint: /mcp/messages
WeatherServiceImpl.java 天气mcp服务的实现,主要使用@Tool来标注mcp的工具方法
@Service
public class WeatherServiceImpl implements WeatherService {
private static final String BASE_URL = "https://wttr.in";
private final RestClient restClient;
public WeatherServiceImpl() {
this.restClient = RestClient.builder()
.baseUrl(BASE_URL)
.defaultHeader("Accept", "application/geo+json")
.defaultHeader("User-Agent", "WeatherApiClient/1.0 (your@email.com)")
.build();
}
@Override
@Tool(description = "获取中国城市的当前天气信息。输入为城市名称(例如:杭州、上海)")
public String getWeather(@RequestParam("arg0")String cityName) {
System.out.println("调用天气mcp服务WeatherServiceImpl!");
WeatherResponse response = restClient.get()
.uri("/{city_name}?format=j1", cityName)
.retrieve()
.body(WeatherResponse.class);
if (response != null && response.getCurrent_condition() != null && !response.getCurrent_condition().isEmpty()) {
CurrentCondition currentCondition = response.getCurrent_condition().get(0);
String result = String.format("""
城市: %s
天气情况: %s
气压: %s(mb)
温度: %s°C (Feels like: %s°C)
湿度: %s%%
降水量:%s (mm)
风速: %s km/h (%s)
能见度: %s 公里
紫外线指数: %s
观测时间: %s
""",
cityName,
currentCondition.getWeatherDesc().get(0).getValue(),
currentCondition.getPressure(),
currentCondition.getTemp_C(),
currentCondition.getFeelsLikeC(),
currentCondition.getHumidity(),
currentCondition.getPrecipMM(),
currentCondition.getWindspeedKmph(),
currentCondition.getWinddir16Point(),
currentCondition.getVisibility(),
currentCondition.getUvIndex(),
currentCondition.getLocalObsDateTime()
);
return result;
} else {
return "无法获取天气信息,请检查城市名称是否正确或稍后重试。";
}
}
在ToolCallbackProviderConfig.java配置文件中,实例化ToolCallbackProvider对象
@Configuration
public class ToolCallbackProviderConfig {
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService) {
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}
3.3、 前台代码实现没有太多变化,请自行参见代码仓的ChatView.vue源码
4、MCP Client客户端的实现
4.1、 Maven依赖
<!-- LLM MCP -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
<!-- LLM MCP End-->
引入mcp-client的starter后,会自动注入mcp client所需要的类
4.2、 代码实现
application.yml配置文件的配置
spring:
# AI 配置
ai:
openai:
api-key: your-api-key-here # 替换为您的 API Key,如果是本地大模型可以不修改
base-url: http://127.0.0.1:6006 # 大模型的访问地址
chat:
options:
model: Qwen3-14B
# temperature参数用于控制生成文本的多样性
#值越高,生成的文本越多样化,但也可能包含更多的随机性和不可预测的内容
#值越低,生成的文本越接近于确定性的结果,即生成的文本会更加一致和可预测
temperature: 0.7
# 嵌入模型配置
embedding:
options:
model: bge-large-zh-v1.5 # 模型名在这里
dimensions: 1024 # 向量维度
retry:
maxAttempts: 3
mcp:
client:
enabled: true # 是否启用MCP客户端
request-timeout: 60s # MCP客户端请求超时时间
type: SYNC # MCP客户端类型
sse:
connections:
server1:
url: http://127.0.0.1:8090
在ChatController.java 中通过mcp协议跟mcp server进行通信,主要是ToolCallbackProvider的使用
@RestController
// 允许前端跨域访问,生产环境应配置具体域名
@CrossOrigin(origins = "*")
public class ChatController {
private static final Logger log = LoggerFactory.getLogger(ChatController.class);
@Autowired
private ChatClient chatClient; // Spring AI 自动配置的客户端
@Autowired
private ToolCallbackProvider toolCallbackProvider; // MCP Provider
/**
* 处理聊天消息 (流式响应 - 推荐用于聊天界面)
*/
@PostMapping(value = "/api/chat-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chatStream(@RequestBody Map<String, String> request) {
String userMessage = constructPrompt(request.get("message"));
Flux<String> flux = chatClient.prompt()
.user(userMessage)
.tools(toolCallbackProvider.getToolCallbacks())//设置mcpclient
.stream()
.content()
.doOnNext(chunk -> log.info("Emitting chunk: #{}#", chunk))
.doOnSubscribe(s -> log.info("Subscription started"))
.doOnComplete(() -> log.info("Flux completed"));
return flux;
}
private String constructPrompt(String userMessage) {
String augmentedPrompt = """
你是一个智能助手,请回答下面的问题。
问题:
%s
""".formatted(userMessage);
System.out.println("augmentedPrompt is :" + augmentedPrompt);
return augmentedPrompt;
}
}
附录
springai实现的逻辑简单示意如下:
[用户] "今天南京天气如何?"
↓
[模型流式输出...] → 生成 tool_call:
{"name": "getWeather", "arguments": {"arg0": "南京"}}
↓
internalStream.detect(tool_call) → hasToolCalls() = true
↓
toolCallingManager.execute("getWeather", {"arg0": "南京"})
↓
找到 @FunctionCallback("getWeather") 方法
↓
调用 getWeather("南京") → 返回 "晴,25°C"
↓
生成 ToolExecutionResult
↓
if (returnDirect) → 直接返回结果
else → 递归 internalStream(新prompt含结果)
↓
[最终输出] "南京今天晴,25°C"(或模型润色后的句子)