Spring AI 自定义MCP Server(天气预报服务)

该文章已生成可运行项目,

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

一、前言

  字节的扣子、腾讯的元器,当我们使用这些平台构建AI智能体的时候会有各种各样功能的插件供我们使用。

  你是不是惊叹字节的扣子、腾讯的元器这些AI平台的海量插件生态?其实这些插件都是使用MCP协议构建的MCP Server服务。那么我们是不是可以构建我们自己的插件?搭建我们自己的MCP Server。

  今天我们就来介绍一下,定义一个自己的MCP Server工具,并与DeepSeek结合为我们播报指定地区的天气预报。

二、MCP是什么?

  由 Anthropic 提出并开源的通信协议,于 2024 年 11 月正式发布,旨在解决大型语言模型(LLM)与外部数据源及工具之间的无缝集成问题。该协议通过标准化 AI 系统与数据源的交互方式,帮助模型获取更丰富的上下文信息,从而生成更准确、更相关的响应。
在这里插入图片描述

三、为什么要有MCP?

  当大型语言模型首次出现时,用户必须将代码复制并粘贴到文本界面中才能与它们进行交互。这很快被证明是不够的,导致自定义集成以更好地加载上下文。然而,这些是零散的,需要单独开发。模型上下文协议 (MCP) 通过提供通用协议来与 AI 与本地和远程资源进行高效交互,从而解决了这一问题。

四、MCP主要功能点?

1.标准化通信接口为 AI 模型和外部资源(如数据库、API、代码编辑器)提供统一的交互方式,简化集成流程。

2.动态上下文感知MCP支持AI模型在多轮交互中动态维护上下文,确保对话或任务的连贯性。 例如,用户与AI讨论方案后,切换模型仍可继续基于已有上下文协作。

3.动态资源访问模型可通过 MCP 实时调用外部工具(如网页抓取、文件操作)或获取最新数据(如股票价格、天气信息)。

4.安全与隐私保护MCP内置多层安全机制,包括本地服务器处理敏感数据、API密钥隔离存储、细粒度权限控制等。

五、搭建MCP Server

整体环境

SpringBoot 3.2.5 
JDK 17 
spring-ai-mcp-server-webmvc-spring-boot-starter  1.0.0-M6

Spring-ai-mcp 是 Spring AI 生态中用于快速集成 MCP(Model Context Protocol)服务端功能的 Spring Boot Starter。

其核心作用是为基于 Spring MVC 的传统 Web 应用提供开箱即用的 MCP 服务端能力,简化 AI 模型与外部工具/数据源的集成流程。

添加依赖

<dependency>    
	<groupId>org.springframework.ai</groupId>    
	<artifactId>
		spring-ai-mcp-server-webmvc-spring-boot-starter
	</artifactId>    
	<version>1.0.0-M6</version>
</dependency>

编写代码

 // 免费天气API基础URL
    private static final String BASE_URL = "https://api.open-meteo.com/v1";

    private final RestClient restClient;

    public WeatherService() {
        this.restClient = RestClient.builder()
                .baseUrl(BASE_URL)
                .defaultHeader("Accept", "application/json")
                .defaultHeader("User-Agent", "OpenMeteoClient/1.0")
                .build();
    }

    /**
     * 获取指定经纬度的天气预报
     *
     * @param latitude  纬度
     * @param longitude 经度
     * @return 指定位置的天气预报
     * @throws RestClientException 如果请求失败
     */
    @Tool(description = "获取特定经纬度的天气预报")
    public String getWeatherConditionByLocation(@ToolParam(description = "纬度") double latitude, @ToolParam(description = "经度") double longitude) {
        System.out.println("开始获取指定地点的天气预报");
        WeatherInfo weatherInfoData = restClient.get()
                .uri("/forecast?latitude={latitude}&longitude={longitude}&current=temperature_2m,apparent_temperature,relative_humidity_2m,precipitation,weather_code,wind_speed_10m,wind_direction_10m&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,weather_code,wind_speed_10m_max,wind_direction_10m_dominant&timezone=auto&forecast_days=7",
                        latitude, longitude)
                .retrieve()
                .body(WeatherInfo.class);

        CurrentWeather current = weatherInfoData.getCurrent();
        String temperatureUnit = weatherInfoData.getCurrentUnit() != null ? weatherInfoData.getCurrentUnit().getTemperatureUnit() : "°C";
        String windSpeedUnit = weatherInfoData.getCurrentUnit() != null ? weatherInfoData.getCurrentUnit().getWindSpeedUnit() : "km/h";
        String humidityUnit = weatherInfoData.getCurrentUnit() != null ? weatherInfoData.getCurrentUnit().getHumidityUnit() : "%";

        StringBuilder weatherStr = new StringBuilder();

        weatherStr.append(String.format("""
                当前天气:
                温度: %.1f%s (体感温度: %.1f%s)
                天气: %s
                风向: %s (%.1f %s)
                湿度: %d%s
                降水量: %.1f 毫米

                """,
                current.getTemperature(),
                temperatureUnit,
                current.getFeelsLike(),
                temperatureUnit,
                getWeatherDescription(current.getWeatherCode()),
                getWindDirection(current.getWindDirection()),
                current.getWindSpeed(),
                windSpeedUnit,
                current.getHumidity(),
                humidityUnit,
                current.getPrecipitation()));

        // 添加未来天气预报
        weatherStr.append("未来天气预报:\n");
        FutureWeatherForecast daily = weatherInfoData.getDaily();

        for (int i = 0; i < daily.getTime().size(); i++) {
            String date = daily.getTime().get(i);
            double tempMin = daily.getTempMin().get(i);
            double tempMax = daily.getTempMax().get(i);
            int weatherCode = daily.getWeatherCode().get(i);
            double windSpeed = daily.getWindSpeedMax().get(i);
            int windDir = daily.getWindDirection().get(i);
            double precip = daily.getPrecipitationSum().get(i);

            // 格式化日期
            LocalDate localDate = LocalDate.parse(date);
            String formattedDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd (EEE)"));

            weatherStr.append(String.format("""
                    %s:
                    温度: %.1f%s ~ %.1f%s
                    天气: %s
                    风向: %s (%.1f %s)
                    降水量: %.1f 毫米

                    """,
                    formattedDate,
                    tempMin, temperatureUnit,
                    tempMax, temperatureUnit,
                    getWeatherDescription(weatherCode),
                    getWindDirection(windDir),
                    windSpeed, windSpeedUnit,
                    precip));
        }
        return weatherStr.toString();
    }

这是获取天气预报的功能代码,需要完整的代码,可以在下面的公众号上给我留言。

添加启动类,并将MCP Server中的方法暴露出去

@SpringBootApplication
public class WeatherApplication {

    public static void main(String[] args) {
        SpringApplication.run(WeatherApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
    }
}

增加配置

server:
  port: 8098

spring:
  ai:
    mcp:
      server:
        name: weather-server
        version: 0.0.1

六、调用MCP Server

使用 VSCode + Cline 调用我们自定义的MCP服务。

《VSCode安装Cline配置deepseek调用MCP插件》

1.stdio模式(本地 Server)

将刚才MCP Server项目打成jar,对应的Cline中的配置如下

"xxxx名称": {    
		"disabled":  false,
	    "timeout": 60,
	    "command": "java",
	    "args": ["-jar", "刚才MCP服务的jar位置"],
	    "transportType": "stdio"
}

2.SSE模式(连接远程服务器)

这种方式,我们首先启动一下我们的项目

在Cline中添加MCP Server,配置如下点击 Add Server

在这里插入图片描述
添加之后,就可以看到我们刚才写的天气预报的方法

在这里插入图片描述

输入我们的问题

北京天气预报:  latitude: 39.9042   longitude: 116.4074

这里可以看到,将用到我们自定义的MCP Server
在这里插入图片描述
MCP Server的输出结果
在这里插入图片描述

前面配置过DeepSeek,所以大模型会调整输出样式
在这里插入图片描述

通过MCP协议的系统性实践,我们不仅掌握了自建MCP Server的核心技术架构,更成功打通了大模型与定制化服务间的认知协同通道。

本文章已经生成可运行项目

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗的狍子007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值