热爱技术,追求卓越
不断求索,精益求精

用spring ai开发一个MCP server,用langchain4j调用

用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

结果如下:

image

调用日志:

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":"订单状态:待发货。如需查看订单详情或进行
赞(0)
未经允许不得转载:LoveCTO » 用spring ai开发一个MCP server,用langchain4j调用

热爱技术 追求卓越 精益求精