跳到主要内容
Spring AI MCP Server 核心机制与实战指南 | 极客日志
Java AI java
Spring AI MCP Server 核心机制与实战指南 Spring AI MCP Server 基于 Model Context Protocol 标准,为 Java 应用提供大模型工具调用能力。通过集成 Spring Boot Starter,开发者可快速定义工具(Tools)、资源(Resources)及提示词(Prompts)。本文深入分析了 SDK 依赖配置、自动装配原理及同步/异步客户端实现,结合 Weather Service 示例展示了从服务端暴露接口到客户端调用的完整链路。重点探讨了 McpSchema 协议定义、McpSyncClient 封装机制以及 McpServerAutoConfiguration 的核心逻辑,帮助理解 Spring AI 如何桥接传统后端服务与大模型生态。
基础依赖:MCP Java SDK
Model Context Protocol (MCP) 提供了标准的 Java SDK,支持 SSE 传输层。在引入 Spring AI 之前,可以先了解底层的 SDK 实现。
<dependencyManagement >
<dependencies >
<dependency >
<groupId > io.modelcontextprotocol.sdk</groupId >
<artifactId > mcp-bom</artifactId >
<version > 0.8.0</version >
<type > pom</type >
<scope > import</scope >
</dependency >
</dependencies >
</dependencyManagement >
<dependency >
<groupId > io.modelcontextprotocol.sdk</groupId >
<artifactId > mcp</artifactId >
</dependency >
<dependency >
<groupId > io.modelcontextprotocol.sdk</groupId >
mcp-spring-webflux
io.modelcontextprotocol.sdk
mcp-spring-webmvc
<artifactId >
</artifactId >
</dependency >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
</dependency >
Spring AI 集成扩展 Spring AI MCP 模块进一步封装了上述 SDK,提供了便捷的 Spring Boot Starter 集成。它屏蔽了底层协议细节,让开发者能像使用普通 Bean 一样管理工具和服务。
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-client</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-client-webflux</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-server</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-server-webmvc</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-server-webflux</artifactId >
</dependency >
其中 mcp-server 系列 Starter 分别对应 WebMVC 和 WebFlux 两种传输方式,可根据项目架构选择。
实战:构建一个天气工具服务
1. 引入依赖 以 WebMVC 为例,只需在 pom.xml 中添加服务端 Starter。
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-starter-mcp-server-webmvc</artifactId >
</dependency >
2. 定义工具回调 我们需要将业务逻辑暴露为 MCP Tool。这里通过 ToolCallbackProvider 注册方法级工具,同时手动构建一个简单的文本处理函数。
@Bean
public ToolCallbackProvider weatherTools (WeatherService weatherService) {
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService)
.build();
}
@Bean
public ToolCallback toUpperCase () {
return FunctionToolCallback.builder("toUpperCase" , (TextInput input) ->
input.input().toUpperCase())
.inputType(TextInput.class)
.description("Put the text to upper case" )
.build();
}
3. 实现业务服务 WeatherService 利用 Spring 的 RestClient 调用外部 API,并通过 @Tool 注解标记可被大模型调用的方法。
@Service
public class WeatherService {
private static final String BASE_URL = "https://api.weather.gov" ;
private final RestClient restClient;
public WeatherService () {
this .restClient = RestClient.builder()
.baseUrl(BASE_URL)
.defaultHeader("Accept" , "application/geo+json" )
.defaultHeader("User-Agent" , "WeatherApiClient/1.0 ([email protected] )" )
.build();
}
@JsonIgnoreProperties(ignoreUnknown = true)
public record Points (@JsonProperty("properties") Props properties) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Props (@JsonProperty("forecast") String forecast) { }
}
@JsonIgnoreProperties(ignoreUnknown = true)
public record Forecast (@JsonProperty("properties") Props properties) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Props (@JsonProperty("periods") List<Period> periods) { }
@JsonIgnoreProperties(ignoreUnknown = true)
public record Period (
@JsonProperty("number") Integer number,
@JsonProperty("name") String name,
@JsonProperty("startTime") String startTime,
@JsonProperty("endTime") String endTime,
@JsonProperty("isDaytime") Boolean isDayTime,
@JsonProperty("temperature") Integer temperature,
@JsonProperty("temperatureUnit") String temperatureUnit,
@JsonProperty("temperatureTrend") String temperatureTrend,
@JsonProperty("probabilityOfPrecipitation") Map probabilityOfPrecipitation,
@JsonProperty("windSpeed") String windSpeed,
@JsonProperty("windDirection") String windDirection,
@JsonProperty("icon") String icon,
@JsonProperty("shortForecast") String shortForecast,
@JsonProperty("detailedForecast") String detailedForecast) { }
}
@JsonIgnoreProperties(ignoreUnknown = true)
public record Alert (@JsonProperty("features") List<Feature> features) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Feature (@JsonProperty("properties") Properties properties) { }
@JsonIgnoreProperties(ignoreUnknown = true)
public record Properties (
@JsonProperty("event") String event,
@JsonProperty("areaDesc") String areaDesc,
@JsonProperty("severity") String severity,
@JsonProperty("description") String description,
@JsonProperty("instruction") String instruction) { }
}
@Tool(description = "Get weather forecast for a specific latitude/longitude")
public String getWeatherForecastByLocation (double latitude, double longitude) {
var points = restClient.get()
.uri("/points/{latitude},{longitude}" , latitude, longitude)
.retrieve()
.body(Points.class);
var forecast = restClient.get()
.uri(points.properties().forecast())
.retrieve()
.body(Forecast.class);
String forecastText = forecast.properties().periods().stream()
.map(p -> String.format("""
%s: Temperature: %s %s Wind: %s %s Forecast: %s
""" ,
p.name(), p.temperature(), p.temperatureUnit(),
p.windSpeed(), p.windDirection(), p.detailedForecast()))
.collect(Collectors.joining());
return forecastText;
}
@Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)")
public String getAlerts (String state) {
Alert alert = restClient.get()
.uri("/alerts/active/area/{state}" , state)
.retrieve()
.body(Alert.class);
return alert.features().stream()
.map(f -> String.format("""
Event: %s Area: %s Severity: %s Description: %s Instructions: %s
""" ,
f.properties().event(), f.properties().areaDesc(),
f.properties().severity(), f.properties().description(),
f.properties().instruction()))
.collect(Collectors.joining("\n" ));
}
}
4. 客户端调用示例 客户端通过 HttpClientSseClientTransport 建立连接,初始化后即可发现并调用服务器提供的工具。
public class SampleClient {
public static void main (String[] args) {
var transport = new HttpClientSseClientTransport ("http://localhost:8080" );
var client = McpClient.sync(transport).build();
client.initialize();
client.ping();
ListToolsResult toolsList = client.listTools();
System.out.println("Available Tools = " + toolsList);
CallToolResult weatherForcastResult = client.callTool(
new CallToolRequest ("getWeatherForecastByLocation" ,
Map.of("latitude" , "47.6062" , "longitude" , "-122.3321" )));
System.out.println("Weather Forcast: " + weatherForcastResult);
CallToolResult alertResult = client.callTool(
new CallToolRequest ("getAlerts" , Map.of("state" , "NY" )));
System.out.println("Alert Response = " + alertResult);
client.closeGracefully();
}
}
运行后可以看到服务器返回的工具列表及执行结果,包括详细的天气预报数据。
源码深度解析
协议定义:McpSchema McpSchema 类集中定义了协议层面的常量和方法名,涵盖了生命周期、工具、资源、提示词等核心交互点。
public final class McpSchema {
private static final Logger logger = LoggerFactory.getLogger(McpSchema.class);
private McpSchema () { }
public static final String LATEST_PROTOCOL_VERSION = "2024-11-05" ;
public static final String JSONRPC_VERSION = "2.0" ;
public static final String METHOD_INITIALIZE = "initialize" ;
public static final String METHOD_NOTIFICATION_INITIALIZED = "notifications/initialized" ;
public static final String METHOD_PING = "ping" ;
public static final String METHOD_TOOLS_LIST = "tools/list" ;
public static final String METHOD_TOOLS_CALL = "tools/call" ;
public static final String METHOD_NOTIFICATION_TOOLS_LIST_CHANGED = "notifications/tools/list_changed" ;
public static final String METHOD_RESOURCES_LIST = "resources/list" ;
public static final String METHOD_RESOURCES_READ = "resources/read" ;
public static final String METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED = "notifications/resources/list_changed" ;
public static final String METHOD_RESOURCES_TEMPLATES_LIST = "resources/templates/list" ;
public static final String METHOD_RESOURCES_SUBSCRIBE = "resources/subscribe" ;
public static final String METHOD_RESOURCES_UNSUBSCRIBE = "resources/unsubscribe" ;
public static final String METHOD_PROMPT_LIST = "prompts/list" ;
public static final String METHOD_PROMPT_GET = "prompts/get" ;
public static final String METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED = "notifications/prompts/list_changed" ;
public static final String METHOD_LOGGING_SET_LEVEL = "logging/setLevel" ;
public static final String METHOD_NOTIFICATION_MESSAGE = "notifications/message" ;
public static final String METHOD_ROOTS_LIST = "roots/list" ;
public static final String METHOD_NOTIFICATION_ROOTS_LIST_CHANGED = "notifications/roots/list_changed" ;
public static final String METHOD_SAMPLING_CREATE_MESSAGE = "sampling/createMessage" ;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
}
同步客户端:McpSyncClient McpSyncClient 是对异步客户端的同步包装,实现了 AutoCloseable 接口,方便资源管理。其内部委托给 McpAsyncClient 执行阻塞操作。
public class McpSyncClient implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(McpSyncClient.class);
private static final long DEFAULT_CLOSE_TIMEOUT_MS = 10_000L ;
private final McpAsyncClient delegate;
public McpSchema.ServerCapabilities getServerCapabilities () {
return this .delegate.getServerCapabilities();
}
public Object ping () {
return this .delegate.ping().block();
}
public McpSchema.CallToolResult callTool (McpSchema.CallToolRequest callToolRequest) {
return this .delegate.callTool(callToolRequest).block();
}
public McpSchema.ListToolsResult listTools () {
return this .delegate.listTools().block();
}
}
自动装配:McpServerAutoConfiguration 这是 Spring Boot 集成的核心。它根据配置决定创建同步还是异步服务器,并自动注册 Transport Provider、工具规格及能力声明。
@AutoConfiguration(after = { McpWebMvcServerAutoConfiguration.class, McpWebFluxServerAutoConfiguration.class })
@ConditionalOnClass({ McpSchema.class, McpSyncServer.class })
@EnableConfigurationProperties(McpServerProperties.class)
public class McpServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public McpServerTransportProvider stdioServerTransport () {
return new StdioServerTransportProvider ();
}
@Bean
@ConditionalOnProperty(prefix = McServerProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC", matchIfMissing = true)
public McpSyncServer mcpSyncServer (...) {
McpSchema.Implementation serverInfo = new Implementation (...);
AsyncSpecification serverBuilder = McpServer.async(transportProvider).serverInfo(serverInfo);
serverBuilder.capabilities(capabilitiesBuilder.build());
return serverBuilder.build();
}
@Bean
@ConditionalOnProperty(prefix = McServerProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC", matchIfMissing = false)
public McpAsyncServer mcpAsyncServer (...) {
}
}
WebMvc 传输层:McpWebMvcServerAutoConfiguration 负责将 MCP 协议映射到 Spring MVC 的 SSE 端点。
@AutoConfiguration
@ConditionalOnClass({ WebMvcSseServerTransportProvider.class })
public class McpWebMvcServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public WebMvcSseServerTransportProvider webMvcSseServerTransportProvider (...) {
return new WebMvcSseServerTransportProvider (objectMapper, serverProperties.getSseMessageEndpoint());
}
@Bean
public RouterFunction<ServerResponse> mvcMcpRouterFunction (WebMvcSseServerTransportProvider transportProvider) {
return transportProvider.getRouterFunction();
}
}
小结 MCP Java SDK 提供了基础的协议支持,而 Spring AI MCP 则将其转化为易于使用的 Spring Boot 组件。核心流程是:通过 AutoConfiguration 初始化 McpServer,注册 ToolCallback 或 ResourceSpecification,并由 WebMvcSseServerTransportProvider 处理 HTTP 连接。客户端通过 McpClient 发起请求,完成从发现工具到执行调用的闭环。
参考文档 相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online