<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><!-- Spring WebFlux-based SSE client and server transport --><dependency><groupId>io.modelcontextprotocol.sdk</groupId><artifactId>mcp-spring-webflux</artifactId></dependency><!-- Spring WebMVC-based SSE server transport --><dependency><groupId>io.modelcontextprotocol.sdk</groupId><artifactId>mcp-spring-webmvc</artifactId></dependency>
Spring AI MCP
Spring AI MCP 扩展了 MCP Java SDK,提供了 Spring Boot 的集成。
16:18:34.707 [HttpClient-1-Worker-0] INFO io.modelcontextprotocol.client.McpAsyncClient -- Server response with Protocol: 2024-11-05, Capabilities: ServerCapabilities[experimental=null, logging=LoggingCapabilities[], prompts=null, resources=null, tools=ToolCapabilities[listChanged=true]], Info: Implementation[name=my-weather-server, version=0.0.1] and Instructions null
Available Tools = ListToolsResult[tools=[Tool[name=toUpperCase, description=Put the text to upper case, inputSchema=JsonSchema[type=object, properties={input={type=string}}, required=[input], additionalProperties=false]], Tool[name=getAlerts, description=Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY), inputSchema=JsonSchema[type=object, properties={state={type=string}}, required=[state], additionalProperties=false]], Tool[name=getWeatherForecastByLocation, description=Get weather forecast for a specific latitude/longitude, inputSchema=JsonSchema[type=object, properties={latitude={type=number, format=double}, longitude={type=number, format=double}}, required=[latitude, longitude], additionalProperties=false]]], nextCursor=null]
Weather Forcast: CallToolResult[content=[TextContent[audience=null, priority=null, text="Overnight:\nTemperature: 50 F\nWind: 5 mph N\nForecast: Mostly cloudy, with a low around 50. North wind around 5 mph.\nWednesday:\nTemperature: 70 F\nWind: 2 to 7 mph NW\nForecast: A chance of rain showers between 9am and 5pm, then showers and thunderstorms. Some of the storms could be severe. Mostly cloudy. High near 70, with temperatures falling to around 68 in the afternoon. Northwest wind 2 to 7 mph. Chance of precipitation is 100%. New rainfall amounts between a quarter and half of an inch possible.\nWednesday Night:\nTemperature: 48 F\nWind: 7 to 10 mph SSW\nForecast: Showers and thunderstorms before 5am, then rain. Some of the storms could be severe. Cloudy. Low around 48, with temperatures rising to around 50 overnight. South southwest wind 7 to 10 mph, with gusts as high as 21 mph. Chance of precipitation is 100%. New rainfall amounts between a quarter and half of an inch possible.\nThursday:\nTemperature: 59 F\nWind: 9 mph S\nForecast: Rain. Cloudy, with a high near 59. South wind around 9 mph, with gusts as high as 21 mph. Chance of precipitation is 90%. New rainfall amounts between a tenth and quarter of an inch possible.\nThursday Night:\nTemperature: 47 F\nWind: 9 mph S\nForecast: Rain. Cloudy, with a low around 47. South wind around 9 mph, with gusts as high as 22 mph. Chance of precipitation is 90%. New rainfall amounts between a quarter and half of an inch possible.\nFriday:\nTemperature: 55 F\nWind: 9 to 13 mph S\nForecast: Rain. Cloudy, with a high near 55. Chance of precipitation is 100%. New rainfall amounts between a tenth and quarter of an inch possible.\nFriday Night:\nTemperature: 44 F\nWind: 6 to 10 mph S\nForecast: Rain. Mostly cloudy, with a low around 44. Chance of precipitation is 80%.\nSaturday:\nTemperature: 55 F\nWind: 7 mph S\nForecast: Rain likely. Partly sunny, with a high near 55.\nSaturday Night:\nTemperature: 41 F\nWind: 2 to 6 mph SE\nForecast: A chance of rain before 11pm. Mostly cloudy, with a low around 41.\nSunday:\nTemperature: 59 F\nWind: 2 to 6 mph NNE\nForecast: A chance of rain after 11am. Mostly cloudy, with a high near 59.\nSunday Night:\nTemperature: 45 F\nWind: 6 mph ESE\nForecast: Rain likely. Mostly cloudy, with a low around 45.\nMonday:\nTemperature: 54 F\nWind: 5 to 8 mph S\nForecast: Rain. Mostly cloudy, with a high near 54.\nMonday Night:\nTemperature: 42 F\nWind: 5 to 8 mph S\nForecast: Rain likely. Mostly cloudy, with a low around 42.\nTuesday:\nTemperature: 54 F\nWind: 7 mph SSW\nForecast: Rain likely. Mostly cloudy, with a high near 54.\n"]], isError=false]
Alert Response = CallToolResult[content=[TextContent[audience=null, priority=null,]], isError=false]
publicclassMcpSyncClientimplementsAutoCloseable {
privatestaticfinalLoggerlogger= LoggerFactory.getLogger(McpSyncClient.class);
// TODO: Consider providing a client config to set this properly// this is currently a concern only because AutoCloseable is used - perhaps it// is not a requirement?privatestaticfinallongDEFAULT_CLOSE_TIMEOUT_MS=10_000L;
privatefinal McpAsyncClient delegate;
/**
* Create a new McpSyncClient with the given delegate.
* @param delegate the asynchronous kernel on top of which this synchronous client
* provides a blocking API.
* @deprecated This method will be removed in 0.9.0. Use
* {@link McpClient#sync(McpClientTransport)} to obtain an instance.
*/@Deprecated// TODO make the constructor package private post-deprecationpublicMcpSyncClient(McpAsyncClient delegate) {
Assert.notNull(delegate, "The delegate can not be null");
this.delegate = delegate;
}
/**
* Get the server capabilities that define the supported features and functionality.
* @return The server capabilities
*/public McpSchema.ServerCapabilities getServerCapabilities() {
returnthis.delegate.getServerCapabilities();
}
McpSchema.Implementation {
.delegate.getServerInfo();
}
ClientCapabilities {
.delegate.getClientCapabilities();
}
McpSchema.Implementation {
.delegate.getClientInfo();
}
{
.delegate.close();
}
{
{
.delegate.closeGracefully().block(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));
} (RuntimeException e) {
logger.warn(, DEFAULT_CLOSE_TIMEOUT_MS, e);
;
}
;
}
McpSchema.InitializeResult {
.delegate.initialize().block();
}
{
.delegate.rootsListChangedNotification().block();
}
{
.delegate.addRoot(root).block();
}
{
.delegate.removeRoot(rootUri).block();
}
Object {
.delegate.ping().block();
}
McpSchema.CallToolResult {
.delegate.callTool(callToolRequest).block();
}
McpSchema.ListToolsResult {
.delegate.listTools().block();
}
McpSchema.ListToolsResult {
.delegate.listTools(cursor).block();
}
McpSchema.ListResourcesResult {
.delegate.listResources(cursor).block();
}
McpSchema.ListResourcesResult {
.delegate.listResources().block();
}
McpSchema.ReadResourceResult {
.delegate.readResource(resource).block();
}
McpSchema.ReadResourceResult {
.delegate.readResource(readResourceRequest).block();
}
McpSchema.ListResourceTemplatesResult {
.delegate.listResourceTemplates(cursor).block();
}
McpSchema.ListResourceTemplatesResult {
.delegate.listResourceTemplates().block();
}
{
.delegate.subscribeResource(subscribeRequest).block();
}
{
.delegate.unsubscribeResource(unsubscribeRequest).block();
}
ListPromptsResult {
.delegate.listPrompts(cursor).block();
}
ListPromptsResult {
.delegate.listPrompts().block();
}
GetPromptResult {
.delegate.getPrompt(getPromptRequest).block();
}
{
.delegate.setLoggingLevel(loggingLevel).block();
}
}
/**
* Get forecast for a specific latitude/longitude
* @param latitude Latitude
* @param longitude Longitude
* @return The forecast for the given location
* @throws RestClientException if the request fails
*/
@Tool(description = "Get weather forecast for a specific latitude/longitude")
/**
* Get alerts for a specific area
* @param state Area code. Two-letter US state code (e.g. CA, NY)
* @return Human readable alert information
* @throws RestClientException if the request fails
*/
@Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)")
/**
* Get the server implementation information.
* @return The server implementation details
*/
public
getServerInfo
()
return
this
/**
* Get the client capabilities that define the supported features and functionality.
* @return The client capabilities
*/
public
getClientCapabilities
()
return
this
/**
* Get the client implementation information.
* @return The client implementation details
*/
public
getClientInfo
()
return
this
@Override
public
void
close
()
this
public
boolean
closeGracefully
()
try
this
catch
"Client didn't close within timeout of {} ms."
return
false
return
true
/**
* The initialization phase MUST be the first interaction between client and server.
* During this phase, the client and server:
* <ul>
* <li>Establish protocol version compatibility</li>
* <li>Exchange and negotiate capabilities</li>
* <li>Share implementation details</li>
* </ul>
* <br/>
* The client MUST initiate this phase by sending an initialize request containing:
* <ul>
* <li>The protocol version the client supports</li>
* <li>The client's capabilities</li>
* <li>Client implementation information</li>
* </ul>
*
* The server MUST respond with its own capabilities and information: {@link McpSchema.ServerCapabilities}. <br/>
* After successful initialization, the client MUST send an initialized notification
* to indicate it is ready to begin normal operations.
*
* <br/>
*
* <a href="https://github.com/modelcontextprotocol/specification/blob/main/docs/specification/basic/lifecycle.md#initialization">Initialization Spec</a>
* @return the initialize result.
*/
public
initialize
()
// TODO: block takes no argument here as we assume the async client is
// configured with a requestTimeout at all times
return
this
/**
* Send a roots/list_changed notification.
*/
public
void
rootsListChangedNotification
()
this
/**
* Add a roots dynamically.
*/
public
void
addRoot
(McpSchema.Root root)
this
/**
* Remove a root dynamically.
*/
public
void
removeRoot
(String rootUri)
this
/**
* Send a synchronous ping request.
* @return
*/
public
ping
()
return
this
// --------------------------
// Tools
// --------------------------
/**
* Calls a tool provided by the server. Tools enable servers to expose executable
* functionality that can interact with external systems, perform computations, and
* take actions in the real world.
* @param callToolRequest The request containing: - name: The name of the tool to call
* (must match a tool name from tools/list) - arguments: Arguments that conform to the
* tool's input schema
* @return The tool execution result containing: - content: List of content items
* (text, images, or embedded resources) representing the tool's output - isError:
* Boolean indicating if the execution failed (true) or succeeded (false/absent)
*/
public
callTool
(McpSchema.CallToolRequest callToolRequest)
return
this
/**
* Retrieves the list of all tools provided by the server.
* @return The list of tools result containing: - tools: List of available tools, each
* with a name, description, and input schema - nextCursor: Optional cursor for
* pagination if more tools are available
*/
public
listTools
()
return
this
/**
* Retrieves a paginated list of tools provided by the server.
* @param cursor Optional pagination cursor from a previous list request
* @return The list of tools result containing: - tools: List of available tools, each
* with a name, description, and input schema - nextCursor: Optional cursor for
* pagination if more tools are available
*/
public
listTools
(String cursor)
return
this
// --------------------------
// Resources
// --------------------------
/**
* Send a resources/list request.
* @param cursor the cursor
* @return the list of resources result.
*/
public
listResources
(String cursor)
return
this
/**
* Send a resources/list request.
* @return the list of resources result.
*/
public
listResources
()
return
this
/**
* Send a resources/read request.
* @param resource the resource to read
* @return the resource content.
*/
public
readResource
(McpSchema.Resource resource)
return
this
/**
* Send a resources/read request.
* @param readResourceRequest the read resource request.
* @return the resource content.
*/
/**
* Resource templates allow servers to expose parameterized resources using URI
* templates. Arguments may be auto-completed through the completion API.
*
* Request a list of resource templates the server has.
* @param cursor the cursor
* @return the list of resource templates result.
*/
public
listResourceTemplates
(String cursor)
return
this
/**
* Request a list of resource templates the server has.
* @return the list of resource templates result.
*/
public
listResourceTemplates
()
return
this
/**
* Subscriptions. The protocol supports optional subscriptions to resource changes.
* Clients can subscribe to specific resources and receive notifications when they
* change.
*
* Send a resources/subscribe request.
* @param subscribeRequest the subscribe request contains the uri of the resource to
* subscribe to.
*/
public
void
subscribeResource
(McpSchema.SubscribeRequest subscribeRequest)
this
/**
* Send a resources/unsubscribe request.
* @param unsubscribeRequest the unsubscribe request contains the uri of the resource
* to unsubscribe from.
*/
public
void
unsubscribeResource
(McpSchema.UnsubscribeRequest unsubscribeRequest)
this
// --------------------------
// Prompts
// --------------------------
public
listPrompts
(String cursor)
return
this
public
listPrompts
()
return
this
public
getPrompt
(GetPromptRequest getPromptRequest)
return
this
/**
* Client can set the minimum logging level it wants to receive from the server.
* @param loggingLevel the min logging level
*/