Spring AI Alibaba - MCP入门

MCP(Model Context Protocol)模型上下文协议

MCP:标准化了应用程序如何像LLM提供上下文。提供了一种标准化的方式将AI模型连接到不同的数据源和工具。

可以将MCP想象成AI应用的USB-C端口,USB-C提供了标准化方式将设备连接到外围设备,MCP提供一种标准化方式将AI模型连接到不同的数据源和工具。

解决多个大模型调用同一个外部工具的需求。

MCP.so - MCP 应用市场

MCP的两种协议,一般使用STDIO。因为是双向流

MCP架构

MCP主机:发起请求的AI程序,比如聊天机器人

MCP客户端:在主机程序内部,与MCP服务器保持1:1的连接

MCP服务器:为MCP客户端提供上下文、工具和提示信息。

本地资源:本地计算机中可供MCP服务器安全访问的资源,如文件

远程资源:MCP服务器可以远程连接到的资源,如通过API提供的数据。

开发者只需写一次MCP服务,所有兼容MCP协议模型都能调用,MCP让大模型从"被动应答"变为"主动调用工具"。

调用一个MCP服务器,就等价调用了带有多个功能的utils工具类。

代码演示

MCP服务端

  1. pom依赖

    xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--spring-ai-starter-mcp-server-webflux 不能和spring-boot-starter-web 依赖并存,
        否则会使用tomcat启动而不是netty。从而导致mcpserver启动失败。但程序正常运行,mcp客户端连不上-->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
  2. 配置文件

    properties 复制代码
    server.port=8013
    # ?????????
    server.servlet.encoding.charset=UTF-8
    server.servlet.encoding.enabled=true
    server.servlet.encoding.force=true
    
    spring.application.name=saa14-localmcpserver
    
    # mcp server configuration
    # ????
    spring.ai.mcp.server.type=async
    spring.ai.mcp.server.name=customer-define-mcp-server
    spring.ai.mcp.server.version=1.0.0
  3. 配置类

    java 复制代码
    @Configuration
    public class McpServerConfig {
    
        /**
         * 将工具方法暴露给外部的MCP client 调用
         * @param weatherService
         * @return
         */
        @Bean
        public ToolCallbackProvider weatherTools(WeatherService weatherService) {
            return MethodToolCallbackProvider.builder()
                    .toolObjects(weatherService)
                    .build();
        }
    }
  4. 服务类

    java 复制代码
    @Service
    public class WeatherService {
    
        @Tool(description = "根据城市名称获取天气信息")
        public String getWeather(String location) {
            Map<String, String> map = new HashMap<String, String>();
            map.put("北京", "最近下雨很多");
            map.put("上海", "一直都是多云");
            map.put("深圳", "阴晴不定的");
            return map.getOrDefault(location, "未知城市");
        }
    }

MCP客户端

  1. pom依赖

    xml 复制代码
    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
  2. 配置文件

    properties 复制代码
    server.port=8014
    # ?????????
    server.servlet.encoding.charset=UTF-8
    server.servlet.encoding.enabled=true
    server.servlet.encoding.force=true
    
    spring.application.name=saa15-localmcpclient
    
    #springai ????config
    spring.ai.dashscope.api-key=${aliQwen-apikey}
    
    # mcp client configuration
    spring.ai.mcp.client.type=async
    spring.ai.mcp.client.request-timeout=60s
    spring.ai.mcp.client.toolcallback.enabled=true
    spring.ai.mcp.client.sse.connections.mcp-server1.url=http://localhost:8013
  3. 配置类

    java 复制代码
    @Configuration
    public class SaaLLMConfig {
    
        private final String DEEPSEEk_MODEL="deepseek-v3";
        private final String QWEN_MODEL="qwen-max";
    
        // 方式一
        @Value("${spring.ai.dashscope.api-key}")
        private String apiKey;
    
        // 配置大模型对外暴露的api
        @Bean(name = "deepseekChatModel")
        public ChatModel deepseekChatModel() {
        return DashScopeChatModel.builder()
                // 配置apikey
                .dashScopeApi(DashScopeApi.builder().apiKey(apiKey).build())
                // 配置模型
                .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEk_MODEL).build())
                .build();
        }
    
        @Bean(name = "qwenChatModel")
        public ChatModel qwenChatModel() {
            return DashScopeChatModel.builder()
                    // 配置apikey
                    .dashScopeApi(DashScopeApi.builder().apiKey(apiKey).build())
                    // 配置模型
                    .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                    .build();
        }
    
        @Bean(name = "deepseekChatClient")
        public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel") ChatModel deepseekChatModel) {
            return ChatClient.builder(deepseekChatModel)
                    .build();
        }
    
        @Bean("qwenChatClient")
        public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel qwenChatModel, ToolCallbackProvider toolCallbackProvider) {
            return ChatClient.builder(qwenChatModel)
                    .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks()) // mcp server端暴露的工具方法
                    .build();
        }
    }
  4. 控制器类

    java 复制代码
    @RestController
    public class McpClientController {
    
        @Resource(name = &quot;qwenChatModel&quot;)
        private ChatModel qwenChatModel;
    
        @Resource(name = &quot;qwenChatClient&quot;)
        private ChatClient qwenChatClient;
    
        /**
         * 使用mcp server端暴露的工具方法
         * @param msg
         * @return
         */
        @GetMapping(&quot;/mcpclient/chat&quot;)
        public Flux&lt;String&gt; chat(@RequestParam(name=&quot;msg&quot;,defaultValue = &quot;北京&quot;) String msg) {
            return qwenChatClient.prompt(msg).stream().content();
        }
    
        /**
         * 不使用mcp server端暴露的工具方法
         * @param msg
         * @return
         */
        @GetMapping(&quot;/mcpclient/chat2&quot;)
        public Flux&lt;String&gt; chat2(@RequestParam(name=&quot;msg&quot;,defaultValue = &quot;北京&quot;) String msg) {
            return qwenChatModel.stream(msg);
        }
    
    }

通过MCP调用百度地图

  1. pom依赖

    xml 复制代码
    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
  2. 配置文件

    properties 复制代码
    server.port=8015
    # ?????????
    server.servlet.encoding.charset=UTF-8
    server.servlet.encoding.enabled=true
    server.servlet.encoding.force=true
    
    spring.application.name=saa16-ClientCallBaiduMapMcpServer
    
    #springai ????config
    spring.ai.dashscope.api-key=${aliQwen-apikey}
    
    # mcp client configuration
    spring.ai.mcp.client.request-timeout=60s
    spring.ai.mcp.client.toolcallback.enabled=true
    # json5 ???????????json????
    spring.ai.mcp.client.stdio.servers-configuration=classpath:mcp-server.json5

    mcp-server.json5文件内容如下:

    json 复制代码
    {
      "mcpServers": {
        "baidu-map": {
          "command": "cmd",
          "args": [
            "/c",
            "npx",
            "-y",
            "@baidumap/mcp-server-baidu-map"
          ],
          "env": {
            "BAIDU_MAP_API_KEY": "1ZGpFxxONtxxzhq3WEd5Z3BnNoB6"
          }
        }
      }
    }
  3. 配置类

    java 复制代码
    @Configuration
    public class SaaLLMConfig {
    
        private final String QWEN_MODEL="qwen-max";
    
        // 方式一
        @Value("${spring.ai.dashscope.api-key}")
        private String apiKey;
    
    
        @Bean(name = "qwenChatModel")
        public ChatModel qwenChatModel() {
            return DashScopeChatModel.builder()
                    // 配置apikey
                    .dashScopeApi(DashScopeApi.builder().apiKey(apiKey).build())
                    // 配置模型
                    .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                    .build();
        }
    
    
        @Bean("qwenChatClient")
        public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel qwenChatModel, ToolCallbackProvider toolCallbackProvider) {
            return ChatClient.builder(qwenChatModel)
                    .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks()) // mcp server端暴露的工具方法
                    .build();
        }
    }
  4. 控制器类

    java 复制代码
    @RestController
    public class McpClientCallBaiduMcpController {
    
        @Resource(name = "qwenChatModel")
        private ChatModel qwenChatModel;
    
        @Resource(name = "qwenChatClient")
        private ChatClient qwenChatClient;
    
        /**
         * 使用mcp server端暴露的工具方法
         * 可以查询天气,IP归属地、路线规划
         * demo参数:查询北纬39.9042°,东经116.4074°的天气情况
         * demo参数:查询61.149.121.66归属地
         * demo参数:查询从北京到上海的路线规划
         * @param msg
         * @return
         */
        @GetMapping("/mcpclient/chat")
        public Flux<String> chat(@RequestParam(name="msg",defaultValue = "北京") String msg) {
            return qwenChatClient.prompt(msg).stream().content();
        }
    
    }
相关推荐
nice_lcj52015 分钟前
【从零理解 Spring AI · 07】对话记忆:让模型记住上一句说了什么
java·spring ai·ai应用开发·chatmemory·对话记忆
SL_staff1 小时前
制造业交付崩盘?用跨部门节点协同计划打通销售、生产与质量链路
java·开源·产品
文丑颜不良啊2 小时前
LeetCode2261~2280题目解析
java·leetcode
SL_staff2 小时前
告别规则黑盒:JVS-Rules 在金融风控中的可视化决策编排实践
java·产品·全栈
逃逸线LOF3 小时前
服务网关Gateway
java·运维·gateway
灿飞屋3 小时前
Kotlin与Java虚拟机四:函数
java·python·kotlin·安卓·android jetpack
阡陌数智4 小时前
Claude API新版本重大变更与安全升级指南
java·linux·安全
学长毕设6 小时前
基于SpringBoot的野生动物公益保护平台设计与实现-附源码
java·spring boot·后端
SL_staff7 小时前
离散制造排程破局:JVS-APS 四步闭环落地实践(开发者视角)
java·产品·全栈