一、MCP 概念介绍

1.1 什么是 MCP?

MCP (Model Context Protocol) 是由 Anthropic 提出的一个开放协议,用于标准化 AI 模型与外部工具、数据源之间的交互方式。它提供了一种统一的接口,让 AI 模型能够安全、可控地访问外部资源。

1.2 MCP 的核心优势

特性说明
标准化提供统一的工具定义和调用规范
解耦工具服务与 AI 应用独立部署、独立扩展
安全工具调用经过明确的权限控制和参数校验
可扩展支持动态添加新工具,无需修改 AI 应用代码
复用同一个 MCP 服务可被多个 AI 应用共享使用

1.3 MCP 架构

┌─────────────────────────────────────────────────────────────────┐
│                        AI 应用 (MCP Client)                       │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐  │
│  │  ChatClient │───▶│  ChatModel  │───▶│ ToolCallbackProvider │  │
│  └─────────────┘    └─────────────┘    └─────────────────────┘  │
└────────────────────────────────┬────────────────────────────────┘
                                 │ SSE (Server-Sent Events)
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│                      MCP Server (工具服务)                        │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                    ToolCallbackProvider                      ││
│  │  ┌───────────────┐  ┌───────────────┐  ┌───────────────┐   ││
│  │  │ WeatherService │  │  OtherService │  │  AnotherTool  │   ││
│  │  │  @Tool方法     │  │  @Tool方法     │  │  @Tool方法     │   ││
│  │  └───────────────┘  └───────────────┘  └───────────────┘   ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

1.4 MCP 通信方式

MCP 支持两种主要通信方式:

  1. SSE (Server-Sent Events) - 基于 HTTP 的服务端推送,适合 Web 应用
  2. Stdio - 基于标准输入输出,适合本地进程间通信

二、Spring AI Tool 使用指南

2.1 核心注解

@Tool 注解

用于标记一个方法为可被 AI 调用的工具。

@Tool(description = "工具功能的详细描述")
public ReturnType toolMethod(@ToolParam(description = "参数说明") String param) {
    // 工具实现
}

属性说明:

  • description:工具功能的描述,AI 会根据此描述决定是否调用该工具
@ToolParam 注解

用于描述工具方法的参数。

@ToolParam(description = "参数的详细说明,帮助 AI 理解参数含义", required = true)
String paramName

属性说明:

  • description:参数描述
  • required:是否必需参数(默认 true)

2.2 ToolCallbackProvider

Spring AI 提供了 ToolCallbackProvider 接口,用于将工具方法注册到 AI 模型。

@Bean
public ToolCallbackProvider myTools(MyService myService) {
    return MethodToolCallbackProvider.builder()
        .toolObjects(myService)  // 注册整个服务对象
        .build();
}

2.3 工具调用流程

用户输入 ──▶ AI 分析 ──▶ 决定调用工具 ──▶ 执行工具方法 ──▶ 返回结果 ──▶ AI 生成回答

三、MCP 服务端实现

3.1 项目结构

weather-mcp-server/
├── src/main/java/com/ai/weather/mcp/
│   ├── WeatherMcpServerApplication.java    # 启动类
│   ├── config/
│   │   └── ToolCallbackProviderConfig.java # 工具注册配置
│   ├── model/
│   │   └── WeatherResponse.java            # 响应模型
│   └── service/
│       └── WeatherService.java             # 天气服务(工具实现)
└── src/main/resources/
    └── application.yml                     # 配置文件

3.2 Maven 依赖

<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.0.1</spring-ai.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- MCP Server 依赖 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.3 配置文件

server:
  port: 8889

spring:
  ai:
    mcp:
      server:
        name: weather-mcp-server          # MCP 服务名称
        sse-message-endpoint: /mcp/weather # SSE 端点路径

logging:
  level:
    com.ai.weather.mcp: DEBUG

3.4 工具服务实现

package com.ai.weather.mcp.service;

import com.ai.weather.mcp.model.WeatherResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

@Slf4j
@Service
@RequiredArgsConstructor
public class WeatherService {

    private static final String WEATHER_API_URL = "https://uapis.cn/api/v1/misc/weather";
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final HttpClient httpClient = HttpClient.newHttpClient();

    @Tool(description = "查询指定城市的天气信息,返回温度、湿度、风向、天气状况等详细信息")
    public WeatherResponse getWeather(
            @ToolParam(description = "城市名称,如:北京、上海、广州、深圳等") String city) {
        try {
            log.info("正在查询城市天气: {}", city);
            
            String url = UriComponentsBuilder.fromHttpUrl(WEATHER_API_URL)
                    .queryParam("city", city)
                    .build()
                    .encode()
                    .toUriString();
            
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .GET()
                    .build();
            
            HttpResponse<String> response = httpClient.send(request, 
                    HttpResponse.BodyHandlers.ofString());
            
            if (response.statusCode() == 200) {
                WeatherResponse weatherResponse = objectMapper.readValue(
                        response.body(), WeatherResponse.class);
                log.info("天气查询成功: {}", weatherResponse);
                return weatherResponse;
            } else {
                log.error("天气查询失败,状态码: {}", response.statusCode());
                throw new RuntimeException("天气查询失败,状态码: " + response.statusCode());
            }
        } catch (Exception e) {
            log.error("查询天气时发生错误: {}", e.getMessage(), e);
            throw new RuntimeException("查询天气时发生错误: " + e.getMessage(), e);
        }
    }
}

3.5 工具注册配置

package com.ai.weather.mcp.config;

import com.ai.weather.mcp.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;

@Configuration
public class ToolCallbackProviderConfig {

    @Bean
    public ToolCallbackProvider livingCityTools(WeatherService weatherService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(weatherService)  // 注册 WeatherService 中的所有 @Tool 方法
                .build();
    }
}

3.6 响应模型

package com.ai.weather.mcp.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class WeatherResponse {
    private String province;
    private String city;
    private String adcode;
    private String weather;
    
    @JsonProperty("weather_icon")
    private String weatherIcon;
    
    private Integer temperature;
    
    @JsonProperty("wind_direction")
    private String windDirection;
    
    @JsonProperty("wind_power")
    private String windPower;
    
    private Integer humidity;
    
    @JsonProperty("report_time")
    private String reportTime;
}

3.7 日志

启动时,会打印已注册的工具数

2026-03-19T16:27:11.990+08:00  INFO 3528 --- [           main] o.s.a.m.s.a.McpServerAutoConfiguration   : Enable tools capabilities, notification: true
2026-03-19T16:27:12.025+08:00  INFO 3528 --- [           main] o.s.a.m.s.a.McpServerAutoConfiguration   : Registered tools: 1

四、MCP 客户端实现

4.1 项目结构

spring-ai/
├── src/main/java/com/ai/springai/
│   ├── SpringAiApplication.java           # 启动类
│   ├── config/
│   │   └── ChatConfig.java                # ChatClient 配置
│   └── controller/
│       └── WeatherController.java         # 天气对话接口
└── src/main/resources/
    └── application.yml                     # 配置文件

4.2 Maven 依赖

<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.0.1</spring-ai.version>
</properties>

<dependencies>
    <!-- MCP Client 依赖 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
    
    <!-- OpenAI 模型支持 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

4.3 配置文件

server:
  port: 8888

spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            weather-service:           # 连接名称(自定义)
              url: http://localhost:8889  # MCP Server 地址
        toolcallback:
          enabled: true               # 启用工具回调
    openai:
      base-url: https://ark.cn-beijing.volces.com/api/v3
      api-key: your-api-key
      chat:
        options:
          model: doubao-seed-2-0-code-preview-260215

logging:
  level:
    org.springframework.ai: debug

关键配置说明:

配置项说明
spring.ai.mcp.client.sse.connectionsMCP Server 连接配置
spring.ai.mcp.client.toolcallback.enabled是否自动注册 MCP 工具到 ChatClient
spring.ai.mcp.client.sse.connections.xxx.urlMCP Server 的地址

4.4 ChatClient 配置

package com.ai.springai.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
@Configuration
public class ChatConfig {

    @Value("${spring.ai.openai.base-url}")
    private String baseUrl;

    @Value("${spring.ai.openai.api-key}")
    private String apiKey;

    @Value("${spring.ai.openai.chat.options.model}")
    private String model;

    @Bean
    public OpenAiApi openAiApi() {
        return OpenAiApi.builder()
                .baseUrl(baseUrl)
                .apiKey(apiKey)
                .completionsPath("/chat/completions")
                .embeddingsPath("/embeddings")
                .build();
    }

    @Bean
    public ChatModel chatModel(OpenAiApi openAiApi) {
        OpenAiChatOptions options = OpenAiChatOptions.builder()
                .model(model)
                .build();
        return OpenAiChatModel.builder()
                .openAiApi(openAiApi)
                .defaultOptions(options)
                .build();
    }

    @Bean
    public ChatClient chatClient(ChatModel chatModel, 
                                  List<ToolCallbackProvider> toolCallbackProviders) {
        log.debug("初始化ChatClient...");
        ChatClient.Builder builder = ChatClient
                .builder(chatModel)
                .defaultSystem("你是一个智能助手,帮助用户解决问题。你可以使用天气工具查询城市的天气信息。");
        
        // 注册所有工具回调(包括 MCP Client 自动提供的工具)
        for (ToolCallbackProvider provider : toolCallbackProviders) {
            builder.defaultToolCallbacks(provider.getToolCallbacks());
        }
        
        return builder.build();
    }
}

4.5 控制器实现

package com.ai.springai.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@Slf4j
@RestController
@RequestMapping("/ai")
@RequiredArgsConstructor
public class WeatherController {

    private final ChatClient chatClient;

    @GetMapping(value = "/weather/chat", produces = "text/html;charset=utf-8")
    public Flux<String> weatherChat(@RequestParam String prompt) {
        log.info("用户询问天气: {}", prompt);
        return chatClient.prompt()
                .user(prompt)
                .stream()
                .content();
    }
}

五、调用示例

5.1 启动服务

步骤 1:启动 MCP Server(天气服务)

cd weather-mcp-server
mvn spring-boot:run

服务启动在 http://localhost:8889

步骤 2:启动 MCP Client(AI 应用)

cd spring-ai
mvn spring-boot:run

服务启动在 http://localhost:8888

5.2 API 调用

请求示例
GET http://localhost:8888/ai/weather/chat?prompt=北京今天天气怎么样

5.3 调用流程详解

1. 用户发送请求
   └── GET /ai/weather/chat?prompt=北京今天天气怎么样

2. Controller 调用 Spring AI ChatClient
   └──此处Spring AI会构建请求(ChatCompletionRequest request = createRequest(prompt, true);)
   {
      "messages" : [ {
        "content" : "你是一个智能助手,帮助用户解决问题,不要脱离这个设定。你可以使用天气工具查询城市的天气信息。",
        "role" : "SYSTEM"
      }, {
        "content" : "北京今天天气怎么样",
        "role" : "USER"
      } ],
      "model" : "doubao-seed-2-0-code-preview-260215",
      "stream" : true,
      "tools" : [ {
        "function" : {
          "description" : "查询指定城市的天气信息,返回温度、湿度、风向、天气状况等详细信息",
          "name" : "spring_ai_mcp_client_weather_service_getWeather",
          "parameters" : {
            "additionalProperties" : false,
            "type" : "object",
            "properties" : {
              "city" : {
                "type" : "string",
                "description" : "城市名称,如:北京、上海、广州、深圳等"
              }
            },
            "required" : [ "city" ]
          }
        },
        "type" : "FUNCTION"
      } ]
    }
3. MCP Client(启动时)已完成:
   └── 建立 SSE 连接
   └── 拉取 tools
   └── 注册到 ToolCallingManager
   └── 工具名转换:
       getWeather → spring_ai_mcp_client_weather_service_getWeather

4. AI 分析用户意图
   └── 判断需要调用工具(天气查询)

5. AI 返回 Tool Call(不是直接执行)
	{
        "choices": [
            {
                "delta": {
                    "content": "",
                    "role": "assistant",
                    "tool_calls": [
                        {
                            "function": {
                                "arguments": "",
                                "name": "spring_ai_mcp_client_weather_service_getWeather"
                            },
                            "id": "call_cs71398kwr3uxqkcs6wso4xe",
                            "index": 0,
                            "type": "function"
                        }
                    ]
                },
                "index": 0
            }
        ],
        "created": 1773915311,
        "id": "021773915303316a865bad2195e810a7735887290a9a7b686b37d",
        "model": "doubao-seed-2-0-code-preview-260215",
        "service_tier": "default",
        "object": "chat.completion.chunk",
        "usage": null
	}
   └── spring_ai_mcp_client_weather_service_getWeather(city="北京")

6. Spring AI ToolCallingManager 执行工具
   └── 打印日志:
       Executing tool call: spring_ai_mcp_client_weather_service_getWeather

7. MCP Client 发起远程调用
   └── POST http://localhost:8889/sse
   └── tool = getWeather

8. MCP Server 接收请求
   └── 路由到 @Tool 方法

9. 执行业务逻辑
   └── WeatherService.getWeather("北京")

10. 返回 WeatherResponse

11. Spring AI 接收 ToolResult

12. 再次调用大模型(关键步骤)
   └── 将 ToolResult 注入上下文

13. AI 生成最终自然语言回答

14. 通过 SSE 流式返回给用户

5.4 响应

客户端:

2026-03-19T16:47:46.558+08:00  INFO 25284 --- [nio-8888-exec-1] c.a.s.controller.WeatherController       : 用户询问天气: 北京今天天气怎么样
2026-03-19T16:48:07.954+08:00 DEBUG 25284 --- [oundedElastic-2] o.s.a.m.tool.DefaultToolCallingManager   : Executing tool call: spring_ai_mcp_client_weather_service_getWeather

mcp服务端:

2026-03-19T16:48:07.970+08:00  INFO 3528 --- [oundedElastic-1] c.ai.weather.mcp.service.WeatherService  : 正在查询城市天气: 北京
2026-03-19T16:48:08.219+08:00  INFO 3528 --- [oundedElastic-1] c.ai.weather.mcp.service.WeatherService  : 天气查询成功: WeatherResponse(province=北京市, city=北京, adcode=110000, weather=晴, weatherIcon=100, temperature=16, windDirection=南风, windPower=2级, humidity=9, reportTime=2026-03-19 15:57:48)

响应:

北京今天天气晴朗,气温25℃,湿度45%,东南风3级。总体来说是个不错的天气,适合外出活动。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐