org.springframework.ai.mcp.server.McpServer
The McpServer class serves as a factory for creating Model Context Protocol (MCP) servers. It provides the main entry point for establishing MCP servers, offering both synchronous and asynchronous server implementations.
The server factory uses a builder pattern for flexible configuration, allowing you to customize various aspects of the server including server information, capabilities, tools, resource providers, and prompt providers.
The factory can create two types of servers:
McpAsyncServerfor non-blocking operationsMcpSyncServerfor blocking operations
McpServer.using(transport)
.serverInfo("my-server", "1.0.0")
.addTool(new MyToolHandler())
.async(); // or .sync()public static Builder using(McpTransport transport)Start building an MCP server with the specified transport.
public Builder serverInfo(McpSchema.Implementation serverInfo)Set the server implementation information.
public Builder serverInfo(String name, String version)Set the server implementation information using name and version.
public Builder serverCapabilities(McpSchema.ServerCapabilities serverCapabilities)Set the server capabilities configuration.
public <T extends McpAsyncServer.ToolHandler> Builder addTool(T toolHandler)Add a tool handler to the server.
public Builder tool(McpSchema.Tool tool, Function<Map<String, Object>, McpSchema.CallToolResult> handler)Add a tool with its handler function.
public Builder addTools(List<ToolHandler> toolHandlers)Add multiple tool handlers to the server.
public Builder resourcesProvider(Function<String, List<McpSchema.Resource>> resourcesProvider)Set the resources provider function.
public Builder promptsProvider(Function<String, List<McpSchema.Prompt>> promptsProvider)Set the prompts provider function.
public McpSyncServer sync()Build and return a synchronous MCP server.
public AsyncServerBuilder async()Build and return an asynchronous server builder.
McpTransport transport = // obtain transport instance
McpServer.using(transport)
.serverInfo("my-server", "1.0.0")
.sync();McpServer.using(transport)
.serverInfo("calculation-server", "1.0.0")
.tool(
new McpSchema.Tool("calculate", "Performs calculations", Map.of(
"operation", Map.of("type", "string"),
"numbers", Map.of("type", "array")
)),
args -> {
// Handle calculation
return new McpSchema.CallToolResult(/* result */);
}
)
.async();McpServer.using(transport)
.serverInfo("content-server", "1.0.0")
.resourcesProvider(cursor -> {
// Return list of resources based on cursor
return List.of(/* resources */);
})
.promptsProvider(cursor -> {
// Return list of prompts based on cursor
return List.of(/* prompts */);
})
.sync();- Tool handlers must be thread-safe as they may be called concurrently
- The synchronous server is implemented as a wrapper around the asynchronous server
- Resource and prompt providers use cursor-based pagination
- The AsyncServerBuilder allows adding tools after server creation
public interface ToolHandler {
String getName();
String getDescription();
Map<String, Object> getInputSchema();
McpSchema.CallToolResult call(Map<String, Object> arguments);
}Tool handlers implement this interface to define:
- Tool name and description
- Input schema for validation
- Execution logic in the call method
The MCP Server supports logging functionality that allows sending log messages with different severity levels to the Client. This feature can be enabled through server capabilities configuration.
McpServer.using(transport)
.serverInfo("my-server", "1.0.0")
.capabilities(ServerCapabilities.builder().logging().build())
.sync(); // or .async()The server supports the following logging levels:
- TRACE
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
For synchronous servers:
LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder()
.level(McpSchema.LoggingLevel.INFO)
.logger("my-logger")
.data("Log message")
.build();
mcpSyncServer.loggingNotification(notification);For asynchronous servers:
LoggingMessageNotification notification = McpSchema.LoggingMessageNotification.builder()
.level(McpSchema.LoggingLevel.INFO)
.logger("my-logger")
.data("Log message")
.build();
mcpAsyncServer.loggingNotification(notification)
.subscribe();- Logging works even if the logging capability is not enabled
- Null notifications are rejected with a McpError
- Log messages include:
- Level: The severity level of the message
- Logger: The name of the logger (typically identifies the source)
- Data: The actual log message content
- The server implementation is transport-agnostic, allowing different transport mechanisms to handle the log messages