LangChain4j学习笔记(五):模型上下文协议MCP

LangChain4j学习笔记(五):模型上下文协议MCP

知识分子没文化
2026-02-05 / 0 评论 / 613 阅读 / 7,298 字数 / 正在检测是否收录...

目录

MCP 官方文档:MCP Introduction

LangChain官网:LangChain4j,官方英文文档:Get Started | LangChain4j,API 文档:Overview (LangChain4j)

非官方中文文档:快速开始 | LangChain4j 中文文档

官方示例代码仓库:langchain4j/langchain4j-examples

LangChain4j版本:1.14.0-beta24

一、MCP概述

1.1、解决什么问题

在 LangChain4j 中通过 @ToolToolProvider 可以实现函数调用,大模型能主动调 Java 方法去查数据库、调API、做计算。功能是实现了,但有个问题一直在那里:工具跟项目是强绑定的

在项目 A 里写了一套 OrderToolsPaymentTools,等到项目 B、项目 C 也需要同样的能力时,是应该把代码拷过去再改一遍,还是造个 REST API 让它们调?更尴尬的是,隔壁组的 Python 项目也想用这些工具,那时候就真没辙了——人家总不能用写好的 Java 代码吧?

所以 Function Calling 也有不少痛点:

  • 工具与应用强耦合:每个项目必须独自维护工具代码,重复造轮子
  • 跨语言不可复用:Java 写的工具,Python/Node.js 用不了,反之亦然
  • 没有统一的发现机制:每个 AI 框架(LangChain、LangChain4j、Semantic Kernel……)各搞一套,互不兼容
  • 集成成本是 M×N:有 M 个 AI 应用、N 个数据源/工具,得做 M×N 次集成

MCP(Model Context Protocol,模型上下文协议)就是为了解决这个问题而生的。它是一套开放的标准协议,定义了 AI 应用如何与外部工具和数据源进行交互。可以把它理解为"工具调用的 USB-C 接口"——不管是 Java 写的、Python 写的、还是 Go 写的,只要遵循 MCP 协议,任何 AI 应用都能插上用。

1.2、MCP定义

MCP/模型上下文协议(Model Context Protocol)是由 Anthropic 在 2024 年 11 月提出并开源的开放协议,用于统一大语言模型与外部系统的交互方式。

本质上,它解决的是"工具的定义消费分离"的问题。传统模式是:每个 AI 应用自己定义和实现工具。MCP 模式是:

  • 工具的生产者:把能力封装成标准化的 MCP Server,独立部署、按需暴露
  • 工具的消费者:任何支持 MCP 协议的 AI 应用(Claude Desktop、VS Code 插件、LangChain4j、LangChain)都能发现并调用这些工具

你可以类比成"微服务"和"SOA服务治理"的关系——把能力变成服务,让多个消费方复用。区别在于 MCP 服务是为 AI 模型特别设计的,它不仅暴露可执行函数,还暴露数据资源和提示词模板,且能被大模型自主发现和决策调用。

1.3、核心架构

MCP 的整体架构是经典的 Client-Server 模式,但扩展成了三层结构,用一个图来理解:

flowchart TB subgraph Host["MCP Host( AI 应用本身)"] H1["Claude Desktop"] H2["VS Code 插件"] H3["你的 Spring Boot 应用"] end subgraph Client["MCP Client(内嵌在 Host 里的协议客户端)"] C1["Client 1"] C2["Client 2"] C3["Client 3"] end subgraph Server["MCP Server(独立服务)"] S1["filesystem-server<br/>文件系统操作"] S2["github-server<br/>GitHub API 集成"] S3["sqlite-server<br/>数据库访问"] S4["自定义业务 Server<br/>订单/支付等"] end H1 --- C1 H1 --- C2 H2 --- C1 H2 --- C3 H3 --- C2 C1 --> S1 C1 --> S2 C2 --> S3 C3 --> S4

三个角色的具体职责:

  • MCP Host:最终面向用户的应用。它不直接处理MCP协议消息,而是通过内置的一个或多个MCP Client与外部Server通信。Host负责管理 Client 的生命周期、权限控制、以及将工具调用结果整合进大模型的上下文,如Claude Desktop、VS Code 插件、自己写好的 Spring Boot 服务
  • MCP Client:协议的消费端,每个 Client 与一个 Server 维持一对一的连接。负责协议层面的消息序列化/反序列化、连接保活、请求路由,如 LangChain4j 的 McpClient
  • MCP Server:轻量级服务进程,暴露出自己拥有的能力。每个 Server 通常只围绕一个主题设计——比如一个 Server 专门连接 PostgreSQL 暴露数据库查询工具,另一个专门对接文件系统,如 filesystem-server、github-server、自己写的业务 Server

一个Host可以同时连接多个Server,这是MCP强大之处——AI应用可以"即插即用"地接入各种工具和数据源。

官方文档:MCP Architecture

二、MCP核心概念

2.1、三大能力原语

MCP Server 可以暴露三种类型的"能力"(即 Primitives):

原语 类比笔记(三)中的概念 谁触发 说明
Tools @Tool 标注的方法 模型主动 可执行的函数。大模型根据用户问题自主决定是否调用、何时调用、传什么参数。这是最核心、最常用的原语
Resources 类似RAG中的知识库文档 模型按需 暴露结构化或非结构化数据(如文件内容、数据库记录),模型可以在需要时读取这些数据作为上下文参考。Resources用URI标识,支持多种MIME类型
Prompts 类似 @SystemMessage 模板 用户触发 服务器预设的提示词模板。用户可以主动选择使用(比如在Claude Desktop中输入"/summarize"这样的快捷指令),不是由模型自主决策调用的

Tools 最常用,它跟 @Tool 一样,是模型自主决策调用的。

Resources 更适合暴露知识库数据,让模型在读到用户问题后,主动要求读取某些数据来增强回答(不是模型自己发一个"我要读文件X"的请求,而是用户问题触发、模型知道该读取什么数据)。

Prompts 则是用户层面的快捷操作,比如用户输入 /translate zh-cn,Client 自动把这条消息替换成一个预设的"请将以下内容翻译成中文"的提示词模板。

需要注意的是:LangChain4j 的 MCP 客户端主要实现的是 Tools 能力,Resources 和 Prompts 支持程度有限(后面"注意事项"章节会提到)。

2.2、传输机制(Transport)

MCP 支持两种底层传输方式,在初始化 Client 或 Server 时指定:

传输方式 原理 连接方式 适用场景
stdio 标准输入/输出流 Client 作为子进程启动 Server,通过 stdin/stdout 进行 JSON-RPC 通信 本地进程间通信,无需网络配置。适合开发调试,也是Claude Desktop的默认方式
HTTP/SSE Server-Sent Events,基于 HTTP 长连接 Client通过 HTTP POST 发送请求,Server通过 SSE(Server-Sent Events)长连接推送响应和通知 远程服务通信,跨机器部署。适合生产环境,Server 可独立扩缩容

stdio 模式的优点是无需网络、无需端口配置,Client 启动 Server 就像启动一个普通子进程一样。缺点是 Server 的生命周期由 Client 管理,Server 挂了 Client 也得重连,且无法跨机器共享。

HTTP/SSE 模式的优点是服务独立部署、可被多客户端共享、便于监控和扩缩容。缺点是需要处理网络延迟、超时、断线重连等问题。

官方文档:Transport Layer

2.3、通信流程

一次完整的 MCP 工具调用流程是 JSON-RPC 协议驱动的:

sequenceDiagram participant User as 用户 participant Host as MCP Host participant Client as MCP Client participant Server as MCP Server User->>Host: 输入"北京今天天气" Host->>Client: 转发用户消息 Client->>Server: (初始化连接) JSON-RPC: initialize Server-->>Client: JSON-RPC: initialized (返回工具列表) Client->>Host: 返回工具规格 Host->>Host: 大模型决策需要调用 "get_weather" Client->>Server: JSON-RPC: tools/call { name: "get_weather", arguments: {"city": "北京"} } Server-->>Client: JSON-RPC: tools/call (返回执行结果 "25°C") Client->>Host: 返回工具结果 Host->>Host: 大模型基于结果生成最终回答 Host->>User: "北京今天温度25°C"

和 LangChain4j 中的 @Tool 相比,MCP 多了一层 Client 与 Server 之间的协议交互。整个通信过程可以分为四个阶段:

阶段一:初始化(Initialize)

Client启动后首先发送 initialize 请求,携带自己的协议版本和能力声明。Server 回复自己的协议版本和能力列表:

// Client → Server
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "0.1.0",
    "capabilities": {},
    "clientInfo": { "name": "my-app", "version": "1.0.0" }
  }
}

// Server → Client
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "0.1.0",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "filesystem-server", "version": "1.0.0" }
  }
}

初始化完成后,Client 发送 initialized 通知(注意:是通知,不是请求,不需要 Server 回复)。

阶段二:能力发现

Client 通过 tools/list 请求获取 Server 暴露的工具列表、资源列表、提示词列表:

// Client → Server
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }

// Server → Client
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "read_file",
        "description": "读取指定文件的内容",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": { "type": "string", "description": "文件路径" }
          },
          "required": ["path"]
        }
      }
    ]
  }
}

返回的 inputSchema 用的是 JSON Schema 格式,跟笔记(三)中 JsonObjectSchema 定义的结构本质上是同一套东西。

阶段三:工具调用

当大模型决定调用某个工具时,Client 发送 tools/call 请求:

// Client → Server
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": { "path": "/home/user/notes.txt" }
  }
}

// Server → Client
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "这是文件的内容..." }
    ]
  }
}

阶段四:关闭连接

Client 或 Server 任意一方可以发送 close 通知来终止连接。

整个流程跟 Function Calling 的"模型决定→框架执行→结果返回→模型再推理"是同一个套路,只是执行环节从"本地调用 Java 方法"变成了"通过 JSON-RPC 调用远程服务"。理解了这个对应关系,MCP 就一点都不神秘了。

官方文档:MCP Protocol

三、LangChain4j MCP客户端

官方文档:MCP | LangChain4j

3.1、Maven依赖

LangChain4j 为 MCP 提供的封装层是 langchain4j-mcp 模块,可以处理 JSON-RPC 的序列化、连接管理、Transport切换等底层细节,把 MCP Server 的工具以 ToolSpecification + ToolExecutor 的形式暴露出来,无缝对接 LangChain4j 的函数调用体系。引入这个模块:

<!-- LangChain4j-MCP 核心模块 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-mcp</artifactId>
    <!-- 版本由 BOM 管理,推荐使用与 LangChain4j 核心一致的版本 -->
</dependency>

3.2、核心类介绍

LangChain4j MCP 客户端相关的核心类:

类名 职责 官方文档
McpClient MCP客户端顶层接口,定义了连接、断开、获取工具列表、执行工具等核心操作 McpClient
DefaultMcpClient McpClient的默认实现,通过 Builder 模式构建,底层管理Transport连接 DefaultMcpClient
McpToolProvider 实现 ToolProvider 接口,把 MCP 工具桥接到 LangChain4j 的工具调用机制 McpToolProvider
McpServer MCP Server构建器,用于把 Java 端的 @Tool 方法暴露为MCP Server(服务端角色) McpServer
Transport 传输方式的抽象,有 StdioTransportSseTransport 两种实现 Transport

其中 McpToolProvider 是关键的桥接组件——它把 MCP Server 暴露的工具列表转换成 LangChain4j 的 ToolProvider 接口,大模型就能像调用 @Tool 一样调用 MCP 工具。

3.3、Stdio传输(本地进程)

Stdio 传输适合连接本地运行的 MCP Server,以 Anthropic 官方提供的 filesystem-server 为例:

首先启动 filesystem-server

确保已安装 Node.js,然后:

# 克隆官方 MCP 仓库
git clone https://github.com/modelcontextprotocol/servers.git
cd servers/src/filesystem

# 安装依赖并构建
npm install
npm run build

# 启动 Server(阻塞运行)
npm run start

默认情况下它监听标准输入输出。现在我们用 LangChain4j 连接它。

Java 代码示例
// 创建 stdio 传输方式
Transport stdioTransport = Transport.stdio();

// 构建 MCP Client
McpClient mcpClient = DefaultMcpClient.builder()
        .transport(stdioTransport)
        .build();

// 连接并初始化(发送 initialize 请求,获取 Server 的 capabilities)
mcpClient.connect();

// 打印该 Server 暴露的工具列表
List<ToolSpecification> tools = mcpClient.listTools();
System.out.println("filesystem-server 暴露了以下工具:");
tools.forEach(tool -> 
    System.out.println("  - " + tool.name() + ": " + tool.description())
);

// 输出示例:
// filesystem-server 暴露了以下工具:
//   - read_file: 指定路径的文件内容读取
//   - write_file: 向指定路径写入文件内容
//   - list_directory: 列出指定目录下的文件和子目录

// 关闭连接
mcpClient.close();

关键点McpClient.connect() 会阻塞当前线程(不能在阻塞的 HTTP 请求线程中直接调用),通常需要在独立线程里操作或使用异步 API。

如果希望 Client 自己启动 Server 进程,可以用 Transport.stdio(ProcessBuilder)

Transport stdioTransport = Transport.stdio(new ProcessBuilder("node", "/path/to/filescript"));
McpClient client = DefaultMcpClient.builder()
        .transport(stdioTransport)
        .build();
client.connect(); // 这会自动启动 filesystem-server 并建立连接

3.4、HTTP/SSE传输(远程服务)

HTTP/SSE 传输适用于生产环境部署。假设已有一个远程 MCP Server 运行在 http://mcp-server.example.com:8080/sse

// 创建 SSE 传输方式
Transport sseTransport = Transport.sse("http://mcp-server.example.com:8080/sse");

// 构建 MCP Client,设置超时和重试策略
McpClient mcpClient = DefaultMcpClient.builder()
        .transport(sseTransport)
        .timeout(Duration.ofSeconds(30))      // 单次请求超时
        .maxRetries(3)                        // 重试次数
        .build();

// 建立连接
mcpClient.connect();

// 获取工具列表并打印
List<ToolSpecification> remoteTools = mcpClient.listTools();
remoteTools.forEach(tool -> 
    System.out.println("远程 Server 工具: " + tool.name() + " - " + tool.description())
);

// 演示手动调用一个工具(通常交给大模型自动调用)
ToolExecutionRequest request = ToolExecutionRequest.builder()
        .name("get_weather")
        .arguments("{\"city\": \"北京\"}")
        .build();

String result = mcpClient.executeTool(request);
System.out.println("工具执行结果: " + result);

// 关闭连接
mcpClient.close();

SSE模式下,Client与Server之间通过HTTP POST发送JSON-RPC请求,Server通过 /sse 端点推送响应和通知。两者之间的通信流程完全遵循2.3节中描述的JSON-RPC生命周期。

SSE模式的好处是Server可以独立部署、多Client共享、独立扩缩容,生产环境的首选。额外需要注意的就是连接保活和断线重连——网络不像进程内通信那么可靠,实战中要做好异常处理,后面第八节会细说。

四、MCP与AI Service集成

4.1、McpToolProvider

McpToolProvider 是 LangChain4j 提供的适配器,把 MCP 工具桥接到 ToolProvider 机制:

McpClient mcpClient = DefaultMcpClient.builder()
        .transport(Transport.sse("http://localhost:8080/sse"))
        .build();
mcpClient.connect();

// 创建 McpToolProvider
ToolProvider mcpToolProvider = new McpToolProvider(mcpClient);

// McpToolProvider 自动实现 ToolProvider 接口:
// - 在每次请求时调用 mcpClient.listTools() 获取最新工具列表
// - 把每个 ToolSpecification 匹配到一个 ToolExecutor
// - 当模型调用工具时,Executor 内部通过 mcpClient.executeTool() 转发请求

// 之后就可以在 AI Service 中使用了
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .toolProvider(mcpToolProvider)    // 装载 MCP 工具
        .build();

McpToolProvider 会自动维护工具的"及时性"——每次请求时重新获取工具列表,确保如果 Server 在运行时新增了工具,Client 能立即感知到。

4.2、声明式集成(@AiService)

在使用 @AiService 注解时,可以通过 toolProvider Bean 注入 MCP 工具:

先声明 ToolProvider Bean
@Configuration
public class McpToolProviderConfig {

    @Bean
    public Transport mcpTransport() {
        // 连接远程 MCP Server(如 filesystem-server 部署在 8080 端口)
        return Transport.sse("http://localhost:8080/sse");
    }

    @Bean
    public McpClient mcpClient(Transport transport) {
        McpClient client = DefaultMcpClient.builder()
                .transport(transport)
                .timeout(Duration.ofSeconds(30))
                .maxRetries(3)
                .build();
        client.connect(); // 在 Bean 初始化时建立连接
        return client;
    }

    @Bean
    @ConditionalOnBean(McpClient.class)
    public ToolProvider mcpToolProvider(McpClient mcpClient) {
        return new McpToolProvider(mcpClient);
    }
}
然后在 AI Service 中注入
@AiService(wiringMode = EXPLICIT, 
           chatModel = "qwenChatModel", 
           toolProvider = "mcpToolProvider")    // 注入 MCP 工具
public interface FileAssistant {

    @SystemMessage("你是一个文件操作助手")
    String chat(@MemoryId String memoryId, String userMessage);

}

当用户输入"帮我读取 /home/user/note.txt 的内容"时,大模型会发现 read_file 这个 MCP 工具可用,自主发起调用,McpToolProvider 会把请求转发给远程 filesystem-server 执行,最终把文件内容取回来。

完整的 Controller 调用示例
@RestController
public class ChatController {

    @Autowired
    private FileAssistant fileAssistant;

    @GetMapping("/chat")
    public String chat(@RequestParam("userId") String userId, 
                       @RequestParam("message") String message) {
        return fileAssistant.chat(userId, message);
    }
}

4.3、编程式集成(AiServices.builder)

如果不想依赖 Spring 的依赖注入机制,也可以用编程式建造者模式:

// 创建 MCP Client
McpClient mcpClient = DefaultMcpClient.builder()
        .transport(Transport.sse("http://localhost:8080/sse"))
        .build();
mcpClient.connect();

// 创建 ToolProvider
ToolProvider mcpToolProvider = new McpToolProvider(mcpClient);

// 构建 AI Service
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(qwenChatModel)
        .toolProvider(mcpToolProvider)
        .build();

// 对话
String answer = assistant.chat("帮我读取 /home/user/note.txt");
System.out.println(answer);

// 记得在应用退出时关闭 MCP Client
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    try {
        mcpClient.close();
    } catch (Exception e) {
        // ignore
    }
}));

注意:编程式集成时,McpClient 的生命周期需要你自己管理(调用 close() 以释放资源、关闭连接)。声明式集成中 Spring 会在容器销毁时自动调用 Bean 的销毁方法(如果你的 Bean 实现了 DisposableBean 或使用了 @PreDestroy)。

五、MCP Server

官方文档:MCP Servers

5.1、官方MCP Server

Anthropic 提供了一批参考 MCP Server,覆盖常见场景:

Server 功能 适用场景
filesystem-server 文件系统操作(读、写、遍历目录) 本地文件处理、配置文件读取
github-server 通过 GitHub API 操作仓库(issues、PRs、代码) 代码审查、自动化 PR 管理
sqlite-server SQLite 数据库操作 本地轻量级数据查询
postgres-server PostgreSQL 数据库操作 企业级数据库集成
slack-server Slack API 集成 聊天机器人自动化
brave-search-server, google-maps-server 外部 API 集成 搜索、地图、地理信息

这些 Server 都已用 Python SDK 或 TypeScript SDK 实现过,你可以直接拿来用,也能基于它们修改。

使用 filesystem-server 示例

官方仓库:modelcontextprotocol/servers

# 克隆并构建
git clone https://github.com/modelcontextprotocol/servers.git
cd servers/src/filesystem
npm install
npm run build

# 指定允许访问的根目录并启动(安全考虑,不要开放整个文件系统)
ALLOWED_DIRECTORIES=/home/user/docs,/home/user/data npm run start

启动后,用 LangChain4j 连接它,就能让大模型只读指定路径下的文件,不会越权访问系统其他位置。

5.2、自定义MCP Server

除了使用官方 Server,你还可以用 LangChain4j 把现有的 Java 工具类暴露为 MCP Server。好消息是——如果你的工具已经用 @Tool 注解写好了,代码基本不用改

// 已有的工具类,不需要任何修改
@Component
public class WeatherTools {

    @Tool(name = "weather_query", value = "查询指定城市的实时天气信息,参数city为城市名称")
    public String queryWeather(@P("城市名称") String city) {
        // 实际项目中这里调用天气API
        return city + "的天气:晴,温度25°C,湿度60%";
    }

    @Tool(name = "weather_forecast", value = "查询指定城市未来3天的天气预报")
    public String forecast(@P("城市名称") String city) {
        return city + "未来三天:周一晴、周二多云、周三小雨";
    }
}

然后用 McpServer 把这个工具类包装并启动:

public class WeatherMcpServerApplication {
    public static void main(String[] args) {
        WeatherTools weatherTools = new WeatherTools();

        // 构建MCP Server,注册工具
        McpServer server = McpServer.builder()
                .name("weather-server")           // Server标识名
                .version("1.0.0")                 // 版本号
                .tools(weatherTools)              // 注册包含@Tool方法的对象,可以传多个
                .build();

        // 以stdio模式启动——Server阻塞等待Client连接
        server.start(McpTransport.stdio());
    }
}

把这个程序打成JAR包,就能被任何MCP Client以stdio模式加载了。比如 Claude Desktop 配置:

{
  "mcpServers": {
    "weather": {
      "command": "java",
      "args": ["-jar", "/path/to/weather-mcp-server.jar"]
    }
  }
}

如果需要在网络上暴露,切换为SSE模式:

server.start(McpTransport.sse(8080));  // 监听8080端口,提供SSE端点

这样一个用 Java 写的工具类就成了标准的 MCP Server——任何语言的 MCP Client 都能发现并调用它。这种"写一次、到处用"的体验,说实话比之前 @Tool 单打独斗的模式舒服太多了。

LangChain4j MCP Server文档:MCP Server | LangChain4j

六、MCP与Function Calling对比

从 Function Calling 到 MCP,其实是一个从"工具内嵌"到"工具服务化"的演进。总结一下两者的差异:

维度 @Tool / ToolProvider(笔记三) MCP(笔记五)
工具位置 在应用进程内,直接调用 Java 方法 独立服务进程,通过网络或 stdio 通信
耦合度 与应用强耦合(同一 JVM) 与应用解耦(独立部署)
跨语言复用 仅限 Java 任何语言(Python、 TypeScript、Go)
调试复杂度 低,IDE 中直接打断点 中,跨进程调试需要额外工具(日志、远程断点)
性能开销 无网络开销,纯本地调用 有传输开销(stdio 可忽略,SSE 有 HTTP 延迟)
发现机制 编译期/启动时静态注册 运行时动态发现(每次请求可获取最新工具列表)
生态共享 不同框架各玩一套 统一协议,跨框架共享工具
部署运维 随应用一起宕、一起起 可独立扩缩容、独立监控
适用场景 单体应用、快速开发、对性能敏感 微服务架构、跨项目共享、构建工具生态

实际选型建议:两者不是非此即彼的关系。内部工具(比如订单查询、用户信息获取)用 @Tool 更直接;共享工具多平台工具(如天气查询、股票行情、数据库访问)用 MCP 更合适。你可以在一个项目里同时用 @Tool 和 MCP,框架会自动合并两者的工具列表。

七、注意事项

MCP 虽然强大,但在 LangChain4j 的当前版本(1.14.0-beta24)中还有一些限制和需要注意的地方:

Resources 和 Prompts 支持有限

LangChain4j 的 MCP 客户端目前主要实现的是 Tools 能力。Resources(资源读取)和 Prompts(提示词模板)的集成仍在开发中或支持不完整。这意味着:

  • 你可以从 MCP Server 获取 resources/listprompts/list 的列表
  • 但把 Resources 和 Prompts 自动注入到 AI Service 的机制可能还不完善
  • 如果你需要在 LangChain4j 中使用 Resources/Prompts,可能需要手动处理(自己调用 mcpClient.readResource()mcpClient.getPrompt(),然后手动组装到 Prompt 里)

官方 GitHub Issue: Support for Resources and Prompts

建议关注官方文档的更新,这两大原语的集成应该在后续版本逐步完善。

网络与进程管理

  • stdio 模式:MCP Server 进程的生命周期由 Client 管理,Server 挂了或手动 killed 了,Client 会失去连接。可考虑用进程管理器(systemd、supervisord)来确保 Server 自动重启
  • HTTP/SSE 模式:SSE 连接基于 HTTP 长连接,中间网络抖动或 Server 重启可能导致连接断开。建议:
    • 设置合理的 timeout(单次请求超时)和 maxRetries(重试次数)
    • 在调用层做兜底,比如工具超时时返回友好提示"服务暂时不可用,请稍后再试"
    • 使用长连接保活(HTTP Keep-Alive),减少频繁重连开销

与流式输出的兼容性

当同时启用 StreamingMCP 工具调用时,流式输出会被暂时阻塞——直到工具调用完成后、大模型生成最终答案时,才开始流式吐出文本。这是当前 LangChain4j 的设计限制,因为工具调用需要等待 Server 返回结果,无法提前开始流式生成。

如果你对"流式+工具"的体验要求很高(比如边调用工具边显示"正在调用工具..."这类提示),可能需要手动做 UI 层的提示优化,而不是依赖框架内置能力。

工具列表变化时的行为

McpToolProvider 会在每次请求时重新获取工具列表,这意味着:

  • 如果 MCP Server 在运行时新增/修改/删除了工具,Client 能立即感知到
  • 但这也带来了一些性能开销——每次请求都要发一个 JSON-RPC tools/list 请求
  • 对比 @Tool 的静态工具列表,MCP 工具是动态的,适合工具经常变化的场景(比如插件系统)

如果你的工具列表非常稳定且繁重,可以考虑缓存工具列表到内存,用一个定时任务定期刷新。

版本兼容性

MCP 协议本身在快速演进,LangChain4j 的 MCP 客户端实现也可能有 Breaking Change。使用时注意:

  • 锁定 LangChain4j 版本,频繁升级可能导致 API 变动
  • 关注 LangChain4j 的 Changelog 和 GitHub Release Notes
  • 如果遇到 DefaultMcpClient.builder() 的参数在升级后不可用了,以最新官方文档为准

安全性考虑

  • Allowed Directories:连接 filesystem-server 时务必限定允许访问的目录,不要开放整个根路径(如 ALLOWED_DIRECTORIES=/tmp/docs 而不是 /
  • 参数校验:自定义 Server 时对输入参数做校验,避免 SQL 注入、路径遍历等安全问题
  • 鉴权与限流:生产环境的 MCP Server 应考虑接入鉴权机制(API Key、OAuth),避免被滥用;对高频调用做限流

参考资料:

官方英文文档:Get Started | LangChain4j,API 文档:Overview (LangChain4j)

非官方中文文档:快速开始 | LangChain4j 中文文档

0

评论 (0)

取消