MCP:LLM与知识库之间的通信协议—(2) 简单实现

引言

上一部分,简单介绍了什么是MCP协议,并根据官方示例实现了一个STDIO模式的。不过STDIO模式的一般只适用于本地使用,不适合网络共享。同时,由于写上文时,关于Client与SSE服务器的BUG未处理完毕,故在本文主要是展示一下这俩东西的代码。

STDIO实现

见上一部分,或者见下方Github,本部分不再指赘述。

SSE模式实现

导入以来

在STDIO下,我们导入的包为

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>

而在SSE下,本部分改用了webmvc模式的mcp-server开发依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

可见,该依赖是上一依赖的超集,多出了spring-boot-starter-web以及mcp-spring-webmvc

实际上仅需这一步,就能将STDIO转成SSE了,不需要再做任何额外更改,这也算是Spring Boot的优势。

定义工具

与STDIO类似,但由于使用网络连接,其编码格式为UTF-8。不需要再像STDIO(window系统)模式一样需要先把编码转回GBK再转到UTF-8了。

java 复制代码
@Service
public class WeatherService {

    // 响应模板,自然语句格式
    private static final String RESPONSE_TEMPLATE = """
            %s的天气为%s, 气温为%s
            """;

    private final RestClient restClient;

    public WeatherService() {
        String apiUrl = "http://apis.juhe.cn/simpleWeather/query";
        this.restClient = RestClient.builder()
                .baseUrl(apiUrl)
                .defaultHeader("Content-Type", "application/x-www-form-urlencoded")
                .defaultHeader("Accept", "application/json")
                .defaultHeader("User-Agent", "WeatherApiClient/1.0")
                .build();
    }

    @Tool(description = "获得中国的天气信息")
    public String getWeather(
            @ToolParam(description = "城市") String city
    ) throws UnsupportedEncodingException {

        String apiKey = "xxxxxxxxx";
        // 发起网络连接
        RestClient.ResponseSpec retrieve = this.restClient.get()
                .uri("?key=" + apiKey + "&city=" + city)
                .retrieve();
        WeatherPojo body = retrieve.body(WeatherPojo.class);
        try {
            return String.format(RESPONSE_TEMPLATE,
                    city,
                    body.getResult().getRealtime().getInfo(),
                    body.getResult().getRealtime().getTemperature()
            );
        } catch (NullPointerException e) {
            return "抱歉,我无法获取到" + city + "的天气信息";
        }
    }
}

与STDIO相同

java 复制代码
@SpringBootApplication
public class McpServerSseApplication {

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

    // 需要先把对应的类注册为工具
    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        return  MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
    }
}

Client实现

依赖导入

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

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

配置信息

有两种配置方式,命令模式与sse模式

json 复制代码
{
  "mcpServers": {  // 这是必须的
    "mcp-server": {  // 名字自己起
      "command": "java",
      "args": [
        "-jar",
        "D:\Documents\IdeaProjects\mcp-server\target\mcpserver-0.0.1-SNAPSHOT.jar"
      ]
    },
    "sse-server": {  // 名字自己起
        "url": "http://localhost:8080/sse"
    }
  }
}
ini 复制代码
// 这个是要有的,不然tools无法被自动注册
spring.ai.mcp.client.toolcallback.enabled=true

下面是Spring AI的文档内容

When tool callbacks are enabled, the registered MCP Tools with all MCP clients are provided as a ToolCallbackProvider instance:

构造Chat客户端

java 复制代码
@Configuration
public class ChatClientConfig {

    @Bean
    // 必须spring.ai.mcp.client.toolcallback.enabled=true
    // ToolCallbackProvider才能被导入
    public ChatClient chatClient(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools) {
        return chatClientBuilder
                .defaultTools(tools)
                .build();
    }
}

主函数

在 Spring Boot 完成应用上下文初始化并启动后立即运行。CommandLineRunner 是 Spring Boot 提供的一个接口,用于在应用启动后执行一些自定义逻辑。

java 复制代码
@SpringBootApplication
public class McpClientApplication  {

    @Autowired
    private ChatClient chatClient;

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

    @Bean
    public CommandLineRunner predefinedQuestions(ConfigurableApplicationContext context) {

        return args -> {
            System.out.println(">>> ASSISTANT: " + chatClient
                    .prompt()
                    .user("今天福州这个城市天气怎么样")
                    .call()
                    .content());
            context.close();
        };
    }
}

GitHub

具体的代码以及依赖在该代码库里 github.com/Vocal-map/m...

相关推荐
阑梦清川4 小时前
你真的理解MCP么?一个实战案例带你学懂弄通MCP
mcp
老纪的技术唠嗑局4 小时前
Vibe Coding 时代的开源社区开发新体验
cursor·mcp·vibecoding
老周聊大模型1 天前
LangChain已死?不,是时候重新思考AI工程范式了
人工智能·langchain·mcp
人生都在赌1 天前
MCP生态全景:2025年最值得关注的AI工具集成现状深度调研
人工智能·ai编程·mcp
GM_8281 天前
【最新最完整】SpringAI-1.0.0开发MCP Server,搭建MCP Client 实战笔记(进阶+详细+完整代码)
java·后端·ai编程·springai·mcp
友莘居士2 天前
Dify中的Agent和发现和调用mcp工具两个节点调用的异同
agent·react·dify·functioncalling·mcp
潘锦2 天前
聊下 AI Agent 的 上下文工程(Context Engineering)
agent·mcp
SelectDB3 天前
Apache Doris Data Agent 解决方案:开启智能运维与数据治理新纪元
github·apache·mcp
陈佬昔没带相机3 天前
Dify MCP功能实测,小参数模型竟然全军覆没!
ollama·deepseek·mcp
老纪的技术唠嗑局4 天前
AI 替代传统 GUI:基于 MCP 的 OBCloud 工作流
运维·mcp