1. 簡介

本文主要介紹基於 spring ai 自定義搭建 mcp 服務端和客户端,主要場景是:

基於本地的mcp服務讓飛書機器人跟場景回答不同的問題

實現效果如下

sample.png

最後附了源碼鏈接.整體代碼非常簡單,容易上手。

2.概念

2.1 什麼是 AI MCP?

MCP(Model Context Protocol) 是一種 ​標準化協議​,用來解決一個長期痛點:

👉 如何讓 AI“安全、可控、標準化地”調用外部工具 / 系統能力?

它的核心目標不是“讓 AI 更聰明”,而是:

  • AI 能調用真實系統
  • 同時 避免 AI 亂編、亂連、亂訪問
  • 並且 工具接入方式統一

2.2 MCP 解決了什麼問題?

1️⃣ 傳統 Function Call 的問題

以 OpenAI Function Calling / Tool Calling 為例:

  • 工具定義寫死在 Prompt 或代碼裏
  • 每個 AI 框架一套接口
  • 權限 / 生命週期 / 連接管理全靠業務自己寫
  • 工具多了以後 極難維護

👉 在真實系統裏會變成:

  • Prompt 很長
  • Tool 定義重複
  • 不同 AI 模型不可複用

2️⃣ MCP 的解決思路

MCP 把 ​工具變成一個標準化的 Server​:

AI Model
   |
   |  MCP 協議
   |
MCP Client  ────── MCP Server
                   ├─ 查數據庫
                   ├─ 調內部系統
                   ├─ 查文件
                   ├─ 調 HTTP API

AI ​不直接接觸工具實現​,只通過 MCP 協議:

  • 發現工具
  • 調用工具
  • 獲取結構化結果

3. 工程結構

主要分為2個模塊,mcp-servermcp-client, mcp-client裏面通過 java -jar 的形式運行 mcp 服務端,在 mcp-client 最終結合 AI 以及飛書機器人的集成實現消息的回覆.

image.png

4. 相關源碼介紹

4.1 mcp 服務端

服務端非常簡單,例如保留一個天氣的服務,只需要在方法上加入org.springframework.ai.tool.annotation.Tool; 註解即可

import io.kings1990.mcp.mcpserver.enums.WeatherType;
import io.kings1990.mcp.mcpserver.record.WeatherRequest;
import io.kings1990.mcp.mcpserver.record.WeatherResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class WeatherService {


    @Tool(name = "getWeather", description = "查詢指定城市的天氣")
    public WeatherResult getWeather(@ToolParam(description = "請求參數") WeatherRequest req) {
        log.info("MCP Tool getWeather called, city={}", req.city());
        return new WeatherResult(
                req.city(),
                WeatherType.SUNNY,
                "25°C",
                "°C",
                "mcp:getWeather"
        );
    }
}

4.2 mcp客户端

4.2.1讓 AI 集成 ToolCallbacks

@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder, List<McpSyncClient> mcpSyncClients) {
        return builder
                .defaultSystem("你是一個AI助手,必須調用工具 kings-spring-ai-mcp-tools 下的方法,如果工具不可用,就明確説明無法調用工具,不要編造。")
                .defaultToolCallbacks(
                        SyncMcpToolCallbackProvider.builder()
                                .mcpClients(mcpSyncClients)
                                .build()
                )
                .build();
    }
}

4.2.2基於飛書機器人的長鏈接集成,實現消息的自動回覆

import cn.hutool.core.thread.ThreadUtil;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.service.im.ImService;
import com.lark.oapi.service.im.v1.model.P2MessageReceiveV1;
import com.lark.oapi.ws.Client;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class LarkWsListener implements CommandLineRunner, DisposableBean {

    @Resource
    private LarkBotService botService;

    @Resource
    private Client.Builder larkWsBuilder;

    @Override
    public void run(String... args) {
        //verificationToken和 encryptionKey 可選,用於驗證和解密事件
        EventDispatcher handler = EventDispatcher.newBuilder("", "")
                .onP2MessageReceiveV1(new ImService.P2MessageReceiveV1Handler() {
                    @Override
                    public void handle(P2MessageReceiveV1 event) throws Exception {

                        // 1) messageId 用於 reply
                        String messageId = event.getEvent().getMessage().getMessageId();

                        // 2) content 是 JSON 字符串,需要解析出文本
                        String contentJson = event.getEvent().getMessage().getContent();

                        System.err.println("收到消息: " + contentJson);

                        String userText = LarkMsgParser.extractText(contentJson);

                        ThreadUtil.execAsync(() -> {
                            botService.onUserMessage(messageId, userText);
                        });

                    }
                })
                .build();

        // 建議把 appId/appSecret 放配置文件
        Client wsClient = larkWsBuilder.eventHandler(handler).build();

        wsClient.start();
    }


    @Override
    public void destroy() throws Exception {

    }
}

4.2.3 AI Api-Key 植入

我這邊使用 zhipu ai. 這邊可以獲取api-key.

加入依賴

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>

並且在配置中配置 api-key

spring:
  ai:
    zhipuai:
      api-key: your_api_key_here
      chat:
        options:
          model: glm-4.6

5.啓動

直接運行mcp-client 主程序,查看飛書機器人是否註冊成功

connected to wss://msg-frontier.feishu.cn/

啓動成功後在飛書應用裏輸入例如北京,等待機器人回覆

6.源碼

github 倉庫. 可以 star 查看後續更新


Fast Request是一個類似於 Postman 的 IDEA 插件。它是一個強大的 restful api 工具包插件,可以根據已有的方法幫助您快速生成 url 和 params。 Restful Fast Request = API調試工具 + API管理工具 + API搜索工具。 它有一個漂亮的界面來完成請求、檢查服務器響應、存儲你的 api 請求和導出 api 請求。插件幫助你在 IDEA 界面內更快更高效得調試你的 API。