LangChain4j集成MCP
本文最后更新于 2026年8月14日
概述
本文基于LangChain4j 1.10.0,还是以12306-mcp为例,演示加载调用MCP,关于12306-mcp安装运行的前置准备,已经在以下文章提到:
使用LangChain4j调用MCP需要引入MCP的依赖langchain4j-mcp
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.4</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.10.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!-- MCP -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
</dependency>
</dependencies>同其他Agent框架一样,LangChain4j也是通过注入为工具来调用MCP。
1.加载
LangChain4j加载MCP,并不像Spring AI或LangChain那么简单,如加载外部mcp.json文件,需要自己完成加载MCP为工具的逻辑。
例:自定义加载逻辑,Stdio/HTTP通用
classpath:mcp-server.json
{
"mcpServers": {
"12306-mcp": {
"transport": "stdio",
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"12306-mcp"
]
}
}
}{
"mcpServers": {
"12306-mcp-http": {
"transport": "http",
"url": "https://mcp.api-inference.modelscope.net/************/mcp"
}
}
}org.example.config.McpConfig
所有MCP工具加载进McpToolProvider对象
package org.example.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.http.StreamableHttpMcpTransport;
import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import java.util.*;
@Configuration
@Slf4j
public class McpConfig {
@Value("classpath:mcp-server.json")
private Resource configFile;
@Data
static class McpServerConfig {
private String name;
private String transport;
private String command;
private List<String> args; // for stdio
private String url; // for http
}
@Bean
public McpToolProvider mcpToolProvider() {
// 3. 用所有 MCP Client 创建 ToolProvider
return McpToolProvider.builder()
.mcpClients(this.loadConfig())
// 设置为 false(默认)允许部分服务器启动失败,继续使用其他服务器
.failIfOneServerFails(false)
.build();
}
private List<McpClient> loadConfig() {
// 1. 解析 JSON 配置文件
ObjectMapper mapper = new ObjectMapper();
List<McpServerConfig> configs = new ArrayList<>();
try {
JsonNode root = mapper.readTree(configFile.getFile() );
JsonNode serversNode = root.get("mcpServers");
if (serversNode != null) {
Iterator<Map.Entry<String, JsonNode>> fields = serversNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
McpServerConfig config = parseServerConfig(entry.getKey(), entry.getValue());
configs.add(config);
}
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
// 2. 为每个服务器配置创建 MCP Client
List<McpClient> mcpClients = new ArrayList<>();
for (McpServerConfig serverConfig : configs ) {
McpTransport transport = this.createTransport(serverConfig);
if (transport != null) {
DefaultMcpClient client = new DefaultMcpClient.Builder()
.transport(transport)
.build();
mcpClients.add(client);
}
}
return mcpClients;
}
private McpServerConfig parseServerConfig(String name, JsonNode node) {
McpServerConfig config = new McpServerConfig();
config.setName(name);
config.setTransport(node.get("transport") != null ? node.get("transport").asText() : null);
config.setCommand(node.get("command") != null ? node.get("command").asText() : null);
config.setUrl(node.get("url") != null ? node.get("url").asText() : null);
// 解析 args
JsonNode argsNode = node.get("args");
if (argsNode != null && argsNode.isArray()) {
List<String> args = new ArrayList<>();
argsNode.forEach(arg -> args.add(arg.asText()));
config.setArgs(args);
}
return config;
}
/*
* 根据配置创建对应的 Transport
*/
private McpTransport createTransport(McpServerConfig config) {
if ("stdio".equalsIgnoreCase(config.getTransport()) && StringUtils.hasText(config.getCommand()) ) {
List<String> commandAndArgs = new ArrayList<>();
commandAndArgs.add(config.getCommand());
commandAndArgs.addAll(config.getArgs());
StdioMcpTransport transport = new StdioMcpTransport.Builder()
.command(commandAndArgs)
.build();
log.info("Using stdio transport {}", transport);
return transport;
}
else if ("http".equalsIgnoreCase(config.getTransport()) && StringUtils.hasText(config.getUrl()) ) {
StreamableHttpMcpTransport transport = new StreamableHttpMcpTransport.Builder()
.url(config.getUrl())
.build();
log.info("Using http transport {}", transport);
return transport;
}
else {
log.info("未知的传输类型或配置错误");
return null;
}
}
}
2.调用
ModelConfig配置类,将加载好的MCP作为工具给大模型使用,Stdio/HTTP通用。
org.example.config.ModelConfig
注入McpToolProvider,将加载的所有MCP工具注入,供大模型调用
package org.example.config;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.TestAssistant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class ModelConfig {
@Resource
private McpToolProvider mcpToolProvider;
@Bean
public ChatModel chatModel() {
//暂时关闭日志/思考
return OpenAiChatModel.builder()
.baseUrl("https://api.deepseek.com/v1")
.apiKey(System.getenv("DEEPSEEK_API_KEY"))
.modelName("deepseek-v4-pro")
.maxRetries(3)
.logRequests(false)
.logResponses(false)
.returnThinking(false)
.build();
}
@Bean
public TestAssistant testAssistant () {
return AiServices.builder(TestAssistant.class)
.chatModel(chatModel())
.toolProvider(mcpToolProvider) // 关键:注入包含所有 MCP 工具的提供者
.build();
}
}
org.example.TestAssistant
package org.example;
import dev.langchain4j.service.SystemMessage;
public interface TestAssistant {
@SystemMessage("你是一个AI助手,可以使用所有可用的工具来帮助用户。")
String chat(String userMessage);
}org.example.test.McpTest
package org.example.test;
import jakarta.annotation.Resource;
import org.example.Main;
import org.example.TestAssistant;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = Main.class)
public class McpTest {
@Resource
private TestAssistant testAssistant;
@Test
public void test() {
String res = testAssistant.chat("帮我查询明天北京到保定的高铁");
System.out.println(res);
}
}
明天是 **2026-08-15**,北京到保定的高铁(G字头)车次很多,全天从凌晨到深夜都有,主要从 **北京西、北京丰台** 发车,终点多为 **保定东**。以下选取部分代表车次供参考:
| 车次 | 出发站 → 到达站 | 出发 → 到达 | 历时 | 二等座 |
|------|----------------|------------|------|--------|
| G651 | 北京丰台 → 保定东 | 06:38 → 07:15 | 37分 | 61元(有票) |
| G8859 | 北京西 → 保定东 | 06:48 → 07:23 | 35分 | 65元(有票) |
| G601 | 北京丰台 → 保定东 | 07:26 → 08:03 | 37分 | 73元(有票) |
| G1025 | 北京西 → 保定东 | 07:26 → 08:07 | 41分 | 72元(有票) |
| G969 | 北京西 → 保定东 | 09:10 → 09:51 | 41分 | 68元(有票) |
| G1043 | 北京西 → 保定东 | 10:15 → 10:56 | 41分 | 72元(有票) |
| G521 | 北京西 → 保定东 | 13:10 → 13:51 | 41分 | 69元(有票) |
| G611 | 北京丰台 → 保定东 | 15:18 → 15:55 | 37分 | 73元(有票) |
| G345 | 北京西 → 保定东 | 16:00 → 16:35 | 35分 | 76元(有票) |
| G527 | 北京西 → 保定东 | 17:20 → 18:01 | 41分 | 69元(有票) |
| G6733 | 北京丰台 → 保定东 | 21:14 → 21:51 | 37分 | 62元(有票) |
另外,还有部分 **C字头城际**(如 C4093 北京西→保定,二等座33元)也可到达保定站,速度稍慢但更便宜。
如果你有偏好的出发时间(比如上午/下午/晚上)或预算,我可以帮你进一步筛选。LangChain4j除了支持Stdio调用本地MCP软件包,还支持调用Docker容器中的MCP软件包,实现进程隔离,防止模型失控调用高权限MCP为宿主机系统带来风险。
"如果文章对您有帮助,可以请作者喝杯咖啡吗?"
微信支付
支付宝
LangChain4j集成MCP
https://blog.liuzijian.com/post/langchain4j/2025/12/30/langchain4j-mcp/