支持私有云部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


代码级拆解:如何用Java从0开始构建MCP Client(附完整Demo)

发布日期:2025-03-20 05:10:02 浏览次数: 1528 来源:whthomas
推荐语

探索Java在MCP协议中的新应用,深入了解如何从零构建Java MCP Client。

核心内容:
1. MCP协议及其在Java生态中的新发展
2. 工具调用机制的详细解释与MCP的应用
3. 完整的Java MCP Client构建过程及代码示例

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

 

MCP协议最近风头正盛,之前MCP整个社区的例子都是Python和TypeScript居多,而最近MCP官方发布了一条消息:

我们很高兴地宣布,由 Spring AI 在 VMware Tanzu 开发的 Java SDK 现在成为 MCP 的官方 Java SDK。这使我们支持的语言列表不断增长,其中包括我们现有的 Kotlin SDK。Spring AI 团队将作为模型上下文协议组织的一个组成部分来维护 SDK。我们非常高兴欢迎他们加入 MCP 社区!

MCP协议已经提供了Java语言的SDK,并且是Java生态位中著名的Spring团队提供的支持。

我通过官方提供的SDK实现了一个简易的Java MCP Client,跟大家分享下如何在Java中对接各种MCP服务。

如果还不了解MCP协议,前面《Claude、Cline都在用的MCP协议,正在掀起AI工具新革命 》的文章中做了相应的介绍。

工具调用 Tools Calling

在使用MCP之前,先了解一下工具调用这个机制,OpenAI的请求API中存在一个参数tools,用于让LLM进行工具调用。

工具调用(也称为函数调用)提供对外部工具让LLM进行调用。LLM不直接调用工具,但是它会建议调用哪个工具,怎么入参。然后用户单独调用工具,并将结果反馈给LLM。最后LLM将结合工具调用的结果再回答用户问题。

具体的解释可以参见OpenAI的解释: https://platform.openai.com/docs/guides/function-calling

这张图很好地解释了tools calling的机制,MCP的tools其实就是利用了这个tools calling的机制。

Java MCP Client Demo

这个部分我分享一下用Java实现MCP Client的思路。

  1. 1. 首先在本地安装一个MCP Server,示例中我使用的是Fetch(https://github.com/zcaceres/fetch-mcp) 这个MCP Server。

如何安装可以参考之前的文章《Claude、Cline都在用的MCP协议,正在掀起AI工具新革命》

  1. 2. 通过Java MCP SDK,在自己的项目中创建一个对应的Fetch MCP Client.
/**
 * 创建一个Fetch MCP Client
 *
 * @return
 */

publicstatic McpSyncClient createFetchMcpClient() {

    // 声明MCP Server的参数
    ServerParametersparams= ServerParameters
        .builder("node")
        .args("/Users/whthomas/Documents/Cline/MCP/fetch-mcp/dist/index.js")
        .build();

    // 声明MCP Server的传输方式
    ClientMcpTransporttransport=newStdioClientTransport(params);

    // 创建一个MCP Client
    McpSyncClientclient= McpClient
        .sync(transport)
        .requestTimeout(Duration.ofSeconds(10))
        // 设置MCP Client的基本信息
        .clientInfo(newMcpSchema.Implementation("Fetch""1.0.0"))
        .capabilities(McpSchema.ClientCapabilities.builder().roots(true).sampling().build())
        .build();

    // 初始化MCP Server
    client.initialize();

    return client;
}
  1. 3. 通过上一步创建的Fetch MCP Client获取这个MCP Server中全部的tools,并转换成LLM服务使用的Tools。
public static List<ChatCompletionTool> prepareChatCompletionTools(McpSyncClient mcpClient) {

        // 列出对应的MCP Server上全部的tools
        McpSchema.ListToolsResulttools= mcpClient.listTools();

        // 将其转换成OpenAI Client上的Tools参数
        return tools
                .tools()
                .stream()
                .map(tool -> {

                    return ChatCompletionTool
                            .builder()
                            .function(FunctionDefinition.builder()
                                    .name(tool.name())
                                    .description(tool.description())
                                    .parameters(prepareFunctionParameters(tool))
                                    .build()
                            )
                            .build();

                })
                .toList();

    }

/**
 * 将工具的入参定义进行转换
 */

privatestatic FunctionParameters prepareFunctionParameters(Tool tool) {

        try {

            ObjectMapperobjectMapper=newObjectMapper();

            StringjsonString= objectMapper.writeValueAsString(tool.inputSchema());

            JsonNodejsonNode= objectMapper.readTree(jsonString);

            FunctionParameters.BuilderparamsBuilder= FunctionParameters.builder();

            jsonNode.fields().forEachRemaining(entry -> {

                JsonValuevalue= JsonValue.fromJsonNode(entry.getValue());

                paramsBuilder.putAdditionalProperty(entry.getKey(), value);

            });

            return paramsBuilder.build();

        } catch (JsonProcessingException e) {
            thrownewRuntimeException(e);
        }

}
  1. 4. 将MCP Client得到的Tools信息转换成LLM服务使用的Tools,并提供给大模型,大模型就会根据tools calling的机制进行思考和输出,最终再通过MCP Client去调用MCP Server上的服务,得到MCP Server的执行结果并提供给后续的调用。
    public voidchatWithMcpServer(String userMessage, String chatModel) {

        List<ChatCompletionTool> chatCompletionTools = McpToolExample.prepareChatCompletionTools(mcpClient);

        // 构建ChatCompletionCreateParams对象,设置用户消息、模型、工具等参数
        ChatCompletionCreateParamsparams= ChatCompletionCreateParams.builder()
                .addUserMessage(userMessage)
                .model(chatModel)
                .tools(chatCompletionTools)
                .build();

        // 调用OpenAI的Chat API
        openAIClient
                .chat()
                .completions()
                .create(params)
                .thenAccept(completion -> completion
                        .choices()
                        .stream()
                        .map(ChatCompletion.Choice::message)
                        .flatMap(message -> {
                            message.content().ifPresent(System.out::println);
                            return message.toolCalls().stream().flatMap(Collection::stream);
                        })
                        .forEach(toolCall -> System.out.println(callFunction(toolCall.function())))
                )
                .join();

    }

    /**
     * 通过MCP Client 调用MCP Server上的方法
     *
     * @param function LLM思考得到的期望被调用的函数信息(包括函数对应的参数)
     * @return
     */

    private String callFunction(ChatCompletionMessageToolCall.Function function) {

        try {

            Map<String, Object> toolParams = objectMapper.readValue(function.arguments(), HashMap.class);

            McpSchema.CallToolResultresult= mcpClient.callTool(newMcpSchema.CallToolRequest(function.name(), toolParams));

            // 将执行的结果返回
            return result.content().stream().map(Object::toString).collect(Collectors.joining());

        } catch (Exception ex) {
            return ex.getMessage();
        }

    }

注意:

  1. 1. 完整的Demo代码已经上传到Github上,未来我做的其他MCP相关的一些实验也会放到这个仓库里面: https://github.com/whthomas/mcp-example
  2. 2. MCP官方的SDK最低支持的JDK版本是Java 17.

实践中的几个观察

这几天尝试用Java来编写一个MCP的Client有几个观察:

  1. 1. 这个Demo实现本来我是希望通过Spring AI来构建的,Spring一如既往地进行了大量的封装(甚至是过度的封装),做了几次不太成功的尝试之后,我最后还是决定使用官方的SDK手搓一个Demo。
  2. 2. 官方的Java文档其实写的暂时不太完善,按照这个文档的步骤,调试出来其实有点困难,我是看着官方Python的MCP Client文档把这个过程弄明白的。
  3. 3. MCP中最重要的Tools(至少我目前认为Tools是MCP协议中提供的最重要功能),输出的结构与OpenAI Chat API中的tools参数是兼容的,也就是MCP的tools给出描述的json结构直接赋值到OpenAI Chat API是可以直接用的。我觉得这种生态发展还是比较良性的,虽然Anthropic是OpenAI的竞争对手,但在构建生态的一些设计上,没有选择重新设计,对整个生态来说是一个很好的事情。
  4. 4. OpenAI官方的Java SDK是通过Kotlin实现的,我观察到不止是OpenAI其他一些厂商在Java生态中的SDK实现也逐渐采用Kotlin作为实现(比如OkHttp),不知道是基于移动端的复用考虑还是其他?OpenAI Java SDK 设计的还是比较优雅的,等待它正式release。

总结

MCP这个生态目前主流还是以Python和TS为主,但随着企业端的需求逐渐增长(Java应用在企业侧的占比还是非常高的),我认为Java应用在MCP的生态位还是会逐渐变得重要,在生态构建的初期,市场上还是充满了各种竞争的机会。

 

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询