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...

相关推荐
twc82914 小时前
MCP赋能测试:Tools、Resources、Prompts三种能力的开发与应用
软件测试·大模型·mcp
twc82914 小时前
MCP协议核心解析:标准化AI工具调用的设计与实践
人工智能·大模型·mcp·ai工具调用
八苦1 天前
如何用c# 做 mcp/ChatGPT app
c#·mcp
光于前裕于后1 天前
配置钉钉龙虾OpenClaw机器人调用OpenMetadata
机器人·钉钉·数据治理·mcp·openclaw
星野云联AIoT技术洞察1 天前
2026 年 MCP + MQTT:AI Agent 真正控制 IoT 设备的落地路径
数字孪生·ack·ai agent·物联网平台·agentic·mcp·命令服务
API开发2 天前
一个MCP操作所有的数据库
数据库·api·api接口·apisql·mcp·mcpserver·openclaw
ZTrainWilliams2 天前
swagger-mcp-toolkit 让 AI编辑器 更快“读懂并调用”你的接口
前端·后端·mcp
EichKite2 天前
链接智能与工具:深度解析 MCP 接入 LLM 的两大主流实现架构
openai·mcp
sanshanjianke2 天前
claudecode/opencode 数学插件工具的调用
数学建模·mcp·claudecode·vibe
码路飞3 天前
MCP 工具只能返回文字?现在能直接弹出交互式 UI 了,手把手写一个
mcp