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

相关推荐
Danny转行做跨境4 小时前
AI 搜索时代选品数据采集: MCP 与爬虫实战对比
跨境电商·mcp·sorftime
壹米饭6 小时前
手搓 MCP 到最简 Agent,我都做了什么?
agent·ai编程·mcp
Sakura_j_h_6 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
xrlfreedom6 小时前
MCP 面试高频考点:企业内网统一管理多个 MCP Server,Tools 权限与审计怎么落地?
tools·mcp·最小权限与审计日志·typescript mcp sdk
风雨中的小七9 小时前
解密Prompt系列73. 爆改对话框:揭秘 Intelligent UI 的动态界面魔法
llm·agent·mcp
正在走向自律1 天前
AI Agent 落地这一年:从“能跑起来”到“敢放出去”
大数据·人工智能·ai agent·智能体·mcp·a2a
VIP_CQCRE1 天前
视频任务显示‘已提交’之后:别让异步生成变成黑盒
异步任务·工作流·ai视频·mcp
xrlfreedom1 天前
MCP 面试高频考点:为团队沉淀可复用 Prompts 工作流,Tools、Resources、RAG 怎么分工?
tools·resources·mcp·rag 知识库
vjmap2 天前
MCP 实战:在 WorkBuddy 里一句话让 AI 生成红军长征地图动画(唯杰 AI 地图动画 MCP 接入教程)
aigc·gis·mcp
Bayze2 天前
让两个模型吵一架,再用第三个裁决——我把多 AI 协作磨成了五种模式,六轮真实测试修出七个 Bug
mcp