ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">MCP协议最近风头正盛,之前MCP整个社区的例子都是Python和TypeScript居多,而最近MCP官方发布了一条消息:ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;font-style: normal;padding: 1em;border-radius: 6px;color: rgba(0, 0, 0, 0.5);background: rgb(247, 247, 247);">ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1em;display: block;letter-spacing: 0.1em;color: rgb(63, 63, 63);">我们很高兴地宣布,由 Spring AI 在 VMware Tanzu 开发的 Java SDK 现在成为 MCP 的官方 Java SDK。这使我们支持的语言列表不断增长,其中包括我们现有的 Kotlin SDK。Spring AI 团队将作为模型上下文协议组织的一个组成部分来维护 SDK。我们非常高兴欢迎他们加入 MCP 社区!ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">MCP协议已经提供了Java语言的SDK,并且是Java生态位中著名的Spring团队提供的支持。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">我通过官方提供的SDK实现了一个简易的Java MCP Client,跟大家分享下如何在Java中对接各种MCP服务。如果还不了解MCP协议,前面《Claude、Cline都在用的MCP协议,正在掀起AI工具新革命 》的文章中做了相应的介绍。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);">工具调用 Tools CallingingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">在使用MCP之前,先了解一下工具调用这个机制,OpenAI的请求API中存在一个参数tools,用于让LLM进行工具调用。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">工具调用(也称为函数调用)提供对外部工具让LLM进行调用。LLM不直接调用工具,但是它会建议调用哪个工具,怎么入参。然后用户单独调用工具,并将结果反馈给LLM。最后LLM将结合工具调用的结果再回答用户问题。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">具体的解释可以参见OpenAI的解释: https://platform.openai.com/docs/guides/function-callingingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">这张图很好地解释了tools calling的机制,MCP的tools其实就是利用了这个tools calling的机制。Java MCP Client Demo这个部分我分享一下用Java实现MCP Client的思路。 - 1. 首先在本地安装一个MCP Server,示例中我使用的是Fetch(https://github.com/zcaceres/fetch-mcp) 这个MCP Server。
如何安装可以参考之前的文章《Claude、Cline都在用的MCP协议,正在掀起AI工具新革命》 - 2. 通过Java MCP SDK,在自己的项目中创建一个对应的Fetch MCP Client.
/** * 创建一个Fetch MCP Client * *@return */ publicstaticMcpSyncClientcreateFetchMcpClient(){
// 声明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();
returnclient; }
- 3. 通过上一步创建的Fetch MCP Client获取这个MCP Server中全部的tools,并转换成LLM服务使用的Tools。
publicstaticList<ChatCompletionTool>prepareChatCompletionTools(McpSyncClient mcpClient){
// 列出对应的MCP Server上全部的tools McpSchema.ListToolsResulttools=mcpClient.listTools();
// 将其转换成OpenAI Client上的Tools参数 returntools .tools() .stream() .map(tool -> {
returnChatCompletionTool .builder() .function(FunctionDefinition.builder() .name(tool.name()) .description(tool.description()) .parameters(prepareFunctionParameters(tool)) .build() ) .build();
}) .toList();
}
/** * 将工具的入参定义进行转换 */ privatestaticFunctionParametersprepareFunctionParameters(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);
});
returnparamsBuilder.build();
}catch(JsonProcessingException e) { thrownewRuntimeException(e); }
}
- 4. 将MCP Client得到的Tools信息转换成LLM服务使用的Tools,并提供给大模型,大模型就会根据tools calling的机制进行思考和输出,最终再通过MCP Client去调用MCP Server上的服务,得到MCP Server的执行结果并提供给后续的调用。
publicvoidchatWithMcpServer(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); returnmessage.toolCalls().stream().flatMap(Collection::stream); }) .forEach(toolCall -> System.out.println(callFunction(toolCall.function()))) ) .join();
}
/** * 通过MCP Client 调用MCP Server上的方法 * *@paramfunction LLM思考得到的期望被调用的函数信息(包括函数对应的参数) *@return */ privateStringcallFunction(ChatCompletionMessageToolCall.Function function){
try{
Map<String, Object> toolParams = objectMapper.readValue(function.arguments(), HashMap.class);
McpSchema.CallToolResultresult=mcpClient.callTool(newMcpSchema.CallToolRequest(function.name(), toolParams));
// 将执行的结果返回 returnresult.content().stream().map(Object::toString).collect(Collectors.joining());
}catch(Exception ex) { returnex.getMessage(); }
}
注意: - 1. 完整的Demo代码已经上传到Github上,未来我做的其他MCP相关的一些实验也会放到这个仓库里面: https://github.com/whthomas/mcp-example
- 2. MCP官方的SDK最低支持的JDK版本是Java 17.
实践中的几个观察这几天尝试用Java来编写一个MCP的Client有几个观察: - 1. 这个Demo实现本来我是希望通过Spring AI来构建的,Spring一如既往地进行了大量的封装(甚至是过度的封装),做了几次不太成功的尝试之后,我最后还是决定使用官方的SDK手搓一个Demo。
- 2. 官方的Java文档其实写的暂时不太完善,按照这个文档的步骤,调试出来其实有点困难,我是看着官方Python的MCP Client文档把这个过程弄明白的。
- 3. MCP中最重要的Tools(至少我目前认为Tools是MCP协议中提供的最重要功能),输出的结构与OpenAI Chat API中的tools参数是兼容的,也就是MCP的tools给出描述的json结构直接赋值到OpenAI Chat API是可以直接用的。我觉得这种生态发展还是比较良性的,虽然Anthropic是OpenAI的竞争对手,但在构建生态的一些设计上,没有选择重新设计,对整个生态来说是一个很好的事情。
- 4. OpenAI官方的Java SDK是通过Kotlin实现的,我观察到不止是OpenAI其他一些厂商在Java生态中的SDK实现也逐渐采用Kotlin作为实现(比如OkHttp),不知道是基于移动端的复用考虑还是其他?OpenAI Java SDK 设计的还是比较优雅的,等待它正式release。
总结MCP这个生态目前主流还是以Python和TS为主,但随着企业端的需求逐渐增长(Java应用在企业侧的占比还是非常高的),我认为Java应用在MCP的生态位还是会逐渐变得重要,在生态构建的初期,市场上还是充满了各种竞争的机会。 |