一个支持 Java 8 的 MCP SDK(支持最新 2026-07-28 协议)

给 Java 应用接上 MCP:从一个小工具开始

假设你有一个用了多年的 Java 系统,里面能查订单、查库存,也能生成报表。现在想让 AI 帮忙处理这些事情。用户说一句"帮我查一下这个订单发货了没有",AI 就能去查询,再把结果告诉用户。这里先要解决一个问题:AI 怎么调用你的 Java 程序?你当然可以自己定义接口,再告诉 AI 每个接口怎么用。如果接入的工具越来越多,或者换了一个 AI 应用,这套说明和调用方式也要跟着维护。

MCP 提供了一套共同的约定:程序可以告诉调用方"我有哪些工具、每个工具需要什么参数",调用方再按约定发起请求。

AJ MCP Next 就是用 Java 实现这件事的一个小工具库。它兼容 Java 8,目前这版代码面向 2026-07-28 协议(注意不向下兼容旧版本的 MCP)。下面的例子使用配套的客户端和服务端,先把调用过程走通。

先分清客户端和服务端

名字听起来有点正式,其实很好理解。

提供工具的程序是服务端。比如,你把"查订单"这个功能开放出去,这个 Java 程序就承担服务端的角色。

发起调用的程序是客户端。它先了解有哪些工具,再选择一个工具,带上参数去调用。

我们先做一个最简单的工具:你发什么文字,它就返回什么文字。这个工具叫 echo,很适合用来确认整条链路是否正常。

整个过程只有三步:

  1. 服务端注册 echo 工具。
  2. 客户端告诉服务端,要调用 echo,参数是 "你好"。
  3. 服务端执行工具,返回 "你好"。

这里暂时用不到大模型。先把工具调用跑通,后面接 AI 应用时就容易定位问题了。

准备一下工程

准备一个 Java 8 或更高版本的 Maven 工程,把需要的依赖加到 pom.xml 中。

如果你要提供工具,让其他程序来调用,添加服务端依赖:

xml 复制代码
<dependency>
    <groupId>com.ajaxjs</groupId>
    <artifactId>aj-mcp-next-server</artifactId>
    <version>1.0</version>
</dependency>

如果你要调用别人的 MCP 服务,添加客户端依赖:

xml 复制代码
<dependency>
    <groupId>com.ajaxjs</groupId>
    <artifactId>aj-mcp-next-client</artifactId>
    <version>1.0</version>
</dependency>

本文会分别编写服务端和客户端。如果把两个示例放在同一个工程里,上面两个依赖都加上即可;如果分成两个工程,就各自添加对应的依赖。

项目还有一个 aj-mcp-next-core 模块,里面放着双方共用的消息、参数校验和编解码代码。Maven 会随客户端或服务端一起引入它,通常不用单独添加。

源码在哪里?

源码放在 GitHub 的 aj-mcp 仓库,本篇使用的是其中的 aj-mcp-2026 目录。进入以后,可以看到三个工程:

text 复制代码
aj-mcp-2026/
├── mcp-core          共用的消息与协议处理
├── mcp-client        调用 MCP 服务
├── mcp-server        提供 MCP 工具和服务
└── sample
    ├── server        Spring Boot 服务端
    └── client        独立 Java 客户端

仓库里也保留着此前版本的实现,阅读本文时,记得进入 aj-mcp-2026 目录。

如果访问 GitHub 不方便,也可以使用 Gitee 仓库 或 GitCode 仓库。

写一个提供工具的 Java 程序

下面是一个完整的本地 HTTP 服务端示例:

java 复制代码
import com.ajaxjs.mcp2026.core.ToolDefinition;
import com.ajaxjs.mcp2026.core.ToolResults;
import com.ajaxjs.mcp2026.server.HttpServerTransport;
import com.ajaxjs.mcp2026.server.McpServer;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

public class EchoHttpServer {
    public static void main(String[] args) throws Exception {
        Map<String, Object> schema = new LinkedHashMap<>();
        schema.put("type", "object");
        schema.put("properties", Collections.singletonMap(
                "text", Collections.singletonMap("type", "string")));
        schema.put("required", Collections.singletonList("text"));

        try (McpServer server = new McpServer("my-first-server", "1.0");
             HttpServerTransport http =
                     new HttpServerTransport(server, 8080)) {

            ToolDefinition echo = ToolDefinition
                    .create("echo", schema)
                    .with("description", "返回收到的文字");

            server.tool(echo, context -> {
                Map<?, ?> arguments = (Map<?, ?>)
                        context.request().getParams().get("arguments");

                String text = (String) arguments.get("text");
                return ToolResults.text(text);
            });

            http.start();
            System.err.println("服务已启动:http://127.0.0.1:8080/mcp");

            new CountDownLatch(1).await();
        }
    }
}

代码稍微有点长,主要是 Java 8 构建 Map 时比较啰嗦。真正与业务有关的,是中间注册工具的那几行。

先看这段:

java 复制代码
schema.put("type", "object");
schema.put("properties", Collections.singletonMap(
        "text", Collections.singletonMap("type", "string")));
schema.put("required", Collections.singletonList("text"));

它相当于工具的参数说明书:调用时要传一个对象,对象里有一个叫 text 的字符串,而且这个参数必须填写。对应的参数长这样:

json 复制代码
{
  "text": "你好"
}

这份说明也叫 Schema。刚接触时,记住它是在描述"工具需要什么输入"就够了。SDK 会据此检查参数,检查通过后才执行你的业务代码。

接着创建工具:

java 复制代码
ToolDefinition echo = ToolDefinition
        .create("echo", schema)
        .with("description", "返回收到的文字");

echo 是调用时使用的名字,description 说明工具的用途。以后换成查订单这样的功能,描述可以写得更具体,例如"根据订单号查询发货状态"。

最后注册处理逻辑:

java 复制代码
server.tool(echo, context -> {
    // 读取参数,执行操作,返回结果
});

这里就是接入现有业务的地方。你可以在里面调用已经写好的 Service,读取数据库,或者访问其他接口。示例末尾的 await() 是为了让这个独立运行的程序继续等待请求。如果接入已有的 Web 应用,就由应用自身管理启动和关闭。

再写一个客户端调用它

保持服务端运行,另开一个 Java 程序:

java 复制代码
import com.ajaxjs.mcp2026.client.HttpClientTransport;
import com.ajaxjs.mcp2026.client.McpClient;
import com.ajaxjs.mcp2026.core.McpResult;
import com.ajaxjs.mcp2026.core.ToolDefinition;

import java.util.Collections;

public class EchoHttpClient {
    public static void main(String[] args) {
        try (McpClient client = new McpClient(
                new HttpClientTransport(
                        "http://127.0.0.1:8080/mcp"))) {

            for (ToolDefinition tool : client.listTools()) {
                System.out.println("发现工具:" + tool.getName());
            }

            McpResult result = client.callTool(
                    "echo",
                    Collections.singletonMap("text", "你好,MCP!"));

            System.out.println(result.toMap());
        }
    }
}

客户端先通过 listTools() 查看服务端提供了哪些工具,再调用 echo。

结果中会包含一段文字内容:

json 复制代码
{
  "type": "text",
  "text": "你好,MCP!"
}

实际返回值还带有结果类型等信息。这些信息由 SDK 按协议组织,我们写工具时使用 ToolResults.text(...) 就可以了。

到这里,一次完整的 MCP 工具调用就跑通了。

把 echo 换成自己的业务

接下来可以把 echo 改成 query_order,参数从 text 改成 orderId,处理逻辑换成现有的订单查询方法。工具需要做的事情仍然差不多:读取参数,调用业务方法,把结果整理成调用方能理解的内容。比如查到订单以后,可以返回:

订单 A20261015001 已于今天上午发货,承运方为某某快递,运单号为......

如果订单不存在,也可以给出明确的业务结果:

java 复制代码
return ToolResults.error("没有找到这个订单,请检查订单号");

ToolResults.error() 表示工具已经执行,但业务上没能完成用户想做的事。像订单不存在、库存不足,都可以用这种方式说明原因。

AI 在哪里?

前面的客户端是我们自己写的 Java 程序,所以工具名和参数也是写在代码里的。

接入支持对应协议的 AI 应用以后,通常由应用里的 MCP 客户端获取工具说明,再交给模型判断什么时候需要调用、该填写什么参数。实际执行仍然由你的 Java 服务负责。因此,工具的名字、描述和参数说明值得认真写。一个叫 query_order、描述清楚用途的工具,比一个叫 execute、只写着"执行操作"的工具容易理解得多。

还有一点需要留意:不同客户端支持的 MCP 协议版本可能不同。接入前,要确认对方支持当前项目使用的版本。

先在本地把一个工具用起来

这个示例默认只监听 127.0.0.1,适合本机练习。准备开放给其他机器访问时,还需要配置监听地址、身份认证,并通过 HTTPS 提供服务。

第一次尝试,可以先挑一个现成的查询功能:查一条订单、读一份配置,或者获取一份报表。业务逻辑已经有了,只要补上工具说明和处理入口,就能看到 MCP 在自己的系统里怎么用。

等这个工具用顺手,再考虑进度通知、订阅,以及需要用户补充信息才能继续的调用过程,会自然得多。

相关推荐
站大爷IP1 小时前
Python的字符串查找把我坑惨了,原来find和index的区别这么大
后端
Gopher_HBo1 小时前
HTTP2传输层与流控
后端
Bazingga1 小时前
同一个脑子,不同的身体:桌面办公智能体全景拆解
后端
用户302822530681 小时前
你的 API 只返回 30 条,为什么数据库还是被打满了?
数据库·后端·架构
Hespethorn1 小时前
MQTT 的四个工程暗礁:遗嘱、保留消息、ACL 与主题设计
后端·物联网
打工仔折腾 AI1 小时前
Spring AI + Qwen 周报生成实战:从原始日志到人工确认卡
人工智能·后端·python·spring·elasticsearch·ai agent 实战
杨文说AI与数字化1 小时前
分时预约系统的库存模型:为什么'加个预约功能'必然出现超卖与假满
后端
Darling噜啦啦1 小时前
# MySQL + Milvus = PostgreSQL?一张表搞定 AI Agent 的长时记忆(附完整代码)
后端·postgresql·orm
用户713874229001 小时前
在 .NET 中使用 AWS Secrets Manager:Config 与 Client 详解
后端