用spring ai开发一个MCP server,用langchain4j调用。由于langchain4j目前对于开发mcp server还没有更好的支持,所以使用spring ai实现mcp server,供langchain4j的mcp client调用
mcp server模块
用spring ai开发一个MCP server。
1、在mcp server项目模块中引入依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.lovecto</groupId>
<artifactId>yuen-agents</artifactId>
<version>${yuen.version}</version>
</parent>
<artifactId>yuen-agents-mcp</artifactId>
<dependencies>
<!-- 引入mcp webflux 依赖, 不需要引入 spring boot web依赖-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
<version>2.0.0-M1</version>
</dependency>
<!-- 引入测试模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
</dependencies>
</project>
2、配置
我这里protocol选择STATELESS(无状态),type为SYNC。
server:
port: 9988
spring:
application:
name: yuen-mcp-service
ai:
mcp:
server:
enabled: true
version: 1.0.0
type: SYNC
protocol: STATELESS
streamable-http:
mcpEndpoint: /mcp
3、创建订单查询工具
此处只是距离,随机返回订单状态。
package cn.lovecto.yuen.mcp.service;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import cn.hutool.core.util.RandomUtil;
import java.util.List;
@Service
public class OrderService {
@Tool(description = "根据订单号查询订单状态")
public String getOrderState(String ordrNo) {
List<String> stateList = List.of("待付款", "待发货", "已发货", "待签收", "已收货",
"待评价", "已完成", "待退款", "退款中", "已退款", "已取消");
return stateList.get(RandomUtil.randomInt(stateList.size()));
}
}
4、mcp工具配置
package cn.lovecto.yuen.mcp.config;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.lovecto.yuen.mcp.service.OrderService;
@Configuration
public class ToolsConfig {
@Bean
public ToolCallbackProvider expressTools(OrderService orderService) {
return MethodToolCallbackProvider.builder()
.toolObjects(orderService)
.build();
}
}
这里使用ToolCallbackProvider,会自动扫描OrderService类的含@Tool注解的方法并把它们注册为MCP Tool,供客户端的大模型调用。
6、启动类:
package cn.lovecto.yuen.mcp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class YuenMcpApplication {
public static void main(String[] args) {
SpringApplication.run(YuenMcpApplication.class, args);
}
}
启动运行mcp 服务端。
mcp client模块
1、引入依赖
<!-- 多智能体支持 -->
<!--LangChain4j 针对 open ai 的 Spring Boot starter-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.10.0-beta18</version>
</dependency>
<!-- AiService的相关依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.10.0-beta18</version>
</dependency>
<!--LangChain4j 针对 ollama 的 Spring Boot starter-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
<version>1.10.0-beta18</version>
</dependency>
<!-- 多智能体支持 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-agentic</artifactId>
<version>1.10.0-beta18</version>
</dependency>
<!-- 引入mcp依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
<version>1.10.0-beta18</version>
</dependency>
2、写智能体接口
package cn.lovecto.yuen.agents.agent;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface OrderAgent {
@UserMessage("你是一名订单售后助手。可根据订单号查询订单状态。订单号是:{{orderNo}}。")
@Agent(description = "根据物流状态查询无论信息")
String getExpressByState(@V("orderNo") String orderNo);
}
3、智能体配置类
package cn.lovecto.yuen.agents.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.lovecto.yuen.agents.agent.OrderAgent;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.model.ollama.OllamaChatModel;
@Configuration
public class OrderAgentConfig {
@Autowired
private OllamaChatModel chatModel;
@Bean
public OrderAgent orderAgent(McpToolProvider toolProvider) {
return AgenticServices.agentBuilder(OrderAgent.class)
.chatModel(chatModel)
.toolProvider(toolProvider)
.outputKey("orderState")
.build();
}
@Bean
public UntypedAgent orderPipeline(OrderAgent orderAgent) {
return AgenticServices.sequenceBuilder()
.subAgents(orderAgent)
.outputKey("orderState")
.build();
}
}
4、Langchain4j MCP配置类
package cn.lovecto.yuen.agents.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
@Configuration
public class Langchain4jMcpConfig {
@Bean
public McpTransport mcpTransport() {
McpTransport transport = StreamableHttpMcpTransport.builder()
.url("http://192.168.2.131:9988/mcp")
.logRequests(true) // 打印日志
.logResponses(true)
.build();
return transport;
}
@Bean
public McpClient mcpClient(McpTransport mcpTransport) {
McpClient mcpClient = DefaultMcpClient.builder()
.key("MyMCPClient")
.transport(mcpTransport)
.build();
return mcpClient;
}
@Bean
public McpToolProvider toolProvider(McpClient mcpClient) {
McpToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(mcpClient)
.build();
return toolProvider;
}
}
5、对话入口
package cn.lovecto.yuen.agents.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.annotation.SaIgnore;
import dev.langchain4j.agentic.UntypedAgent;
@SaIgnore
@RestController
public class OrderController {
@Qualifier("orderPipeline")
@Autowired
private UntypedAgent orderPipeline;
@GetMapping("/getOrderState")
public String getOrderState(String msg, String orderNo) {
return (String)orderPipeline.invoke(Map.of("msg", msg, "orderNo", orderNo));
}
}
6、配置
server:
port: 9999
langchain4j:
ollama:
chat-model:
base-url: http://192.168.2.131:11434
model-name: qwen3:0.6b
log-requests: true
log-responses: true
演示
在浏览器中输入
http://192.168.2.131:9999/getOrderState?msg=%E5%B8%AE%E6%88%91%E6%9F%A5%E4%B8%8B%E8%AE%A2%E5%8D%95%E7%8A%B6%E6%80%81&orderNo=88800098
结果如下:

调用日志:
2026-01-12T18:19:23.831+08:00 INFO 18744 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: http://192.168.2.131:11434/api/chat
- headers: [Content-Type: application/json]
- body: {
"model" : "qwen3:0.6b",
"messages" : [ {
"role" : "user",
"content" : "你是一名订单售后助手。可根据订单号查询订单状态。订单号是:88800098。"
} ],
"options" : {
"stop" : [ ]
},
"stream" : false,
"tools" : [ {
"type" : "function",
"function" : {
"name" : "getOrderState",
"description" : "根据订单号查询订单状态",
"parameters" : {
"type" : "object",
"properties" : {
"ordrNo" : {
"type" : "string"
}
},
"required" : [ "ordrNo" ]
}
}
} ]
}
2026-01-12T18:19:24.636+08:00 INFO 18744 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [Content-Type: application/json; charset=utf-8], [Date: Mon, 12 Jan 2026 10:19:24 GMT], [Content-Length: 784]
- body: {"model":"qwen3:0.6b","created_at":"2026-01-12T10:19:24.635758Z","message":{"role":"assistant","content":"","thinking":"好的,用户需要查询订单状态,订单号是88800098。我需要先确认是否有相关的工具可用,根据提供的工具,有一个getOrderState函数,需要根据订单号来返回状态。所以应该直接调用这个函数,参数是ordrNo,然后将结果返回给用户。不需要额外的信息或解释,直接执行即可。\n","tool_calls":[{"id":"call_vyhjd3zt","function":{"index":0,"name":"getOrderState","arguments":{"ordrNo":"88800098"}}}]},"done":true,"done_reason":"stop","total_duration":801927600,"load_duration":91255700,"prompt_eval_count":167,"prompt_eval_duration":71498200,"eval_count":112,"eval_duration":607885200}
2026-01-12T18:19:24.636+08:00 INFO 18744 --- [yuen-ahents] [ XNIO-1 task-2] MCP : Request: {"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"getOrderState","arguments":{"ordrNo":"88800098"}}}
2026-01-12T18:19:24.638+08:00 INFO 18744 --- [yuen-ahents] [ient-2-Worker-2] MCP : Response: {"jsonrpc":"2.0","id":6,"result":{"content":[{"type":"text","text":"\"待发货\""}],"isError":false}}
2026-01-12T18:19:24.640+08:00 INFO 18744 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: http://192.168.2.131:11434/api/chat
- headers: [Content-Type: application/json]
- body: {
"model" : "qwen3:0.6b",
"messages" : [ {
"role" : "user",
"content" : "你是一名订单售后助手。可根据订单号查询订单状态。订单号是:88800098。"
}, {
"role" : "assistant",
"tool_calls" : [ {
"function" : {
"name" : "getOrderState",
"arguments" : {
"ordrNo" : "88800098"
}
}
} ]
}, {
"role" : "tool",
"content" : "\"待发货\""
} ],
"options" : {
"stop" : [ ]
},
"stream" : false,
"tools" : [ {
"type" : "function",
"function" : {
"name" : "getOrderState",
"description" : "根据订单号查询订单状态",
"parameters" : {
"type" : "object",
"properties" : {
"ordrNo" : {
"type" : "string"
}
},
"required" : [ "ordrNo" ]
}
}
} ]
}
2026-01-12T18:19:25.184+08:00 INFO 18744 --- [yuen-ahents] [ XNIO-1 task-2] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [Content-Type: application/json; charset=utf-8], [Date: Mon, 12 Jan 2026 10:19:25 GMT], [Content-Length: 915]
- body: {"model":"qwen3:0.6b","created_at":"2026-01-12T10:19:25.1838748Z","message":{"role":"assistant","content":"订单状态:待发货。如需查看订单详情或进行
LoveCTO

