由于篇幅问题,源码部分在这里新建了一篇文章,完整的文章在这里:juejin.cn/spost/75709...。
3.1 客户端
3.1.1 入口层
MCP 客户端入口层涉及到的类包括 McpClient 、McpClient.AsyncSpc (内部类)、McpClient.SyncSpec(内部类),如下图所示:

在入口层中,McpClient 是创建 MCP 客户端的统一入口,通过静态方法 sync() 和 async() 提供了同步和异步两种模式的构建方式,分别返回 SyncSpec 和 AsyncSpec 这两个内部构建器类,用于配置客户端实例的各项参数并最终生成对应的 McpSyncClient 和 McpAsyncClient。
其中,AsyncSpec 和 SyncSpec 的设计非常相似,都封装了配置信息,且它们内部的方法(如 requestTimeout()、initializationTimeout()、capabilities())都只是对构建器内成员变量的简单赋值。而不同的是,异步模式在处理服务端的变更通知时,是基于 Reactor 的 Mono 进行响应式调用的,而同步模式则使用传统的 Consumer 回调方式。
核心的参数描述如下:
transport:传输层实现对象。requestTimeout:请求超时时间,默认 20s。initializationTimeout:初始化超时时间,默认 20s。capabilities:客户端能力配置,包含实验性功能、根功能、采样能力等配置。clientInfo:客户端基本信息,包含客户端名字和版本。toolsChangeConsumers:工具变更通知的消费者列表,用于保存当服务端工具列表变化时要异步执行的回调函数列表。
核心的源码及注释如下所示:
Java
/**
* 创建 MCP 客户端的工厂类
*/
public interface McpClient {
/**
* 创建 MCP 同步客户端
*
* @param transport 传输层对象
* @return 同步客户端构建器
*/
static SyncSpec sync(McpClientTransport transport) {
return new SyncSpec(transport);
}
/**
* 创建 MCP 异步客户端
*
* @param transport 传输层对象
* @return 异步客户端构建器
*/
static AsyncSpec async(McpClientTransport transport) {
return new AsyncSpec(transport);
}
/**
* 同步客户端构建器
*/
class SyncSpec {
// 客户端传输层对象
private final McpClientTransport transport;
// 请求超时时间
private Duration requestTimeout = Duration.ofSeconds(20);
// 初始化超时时间
private Duration initializationTimeout = Duration.ofSeconds(20);
// 客户端能力配置
private ClientCapabilities capabilities;
// 客户端实现信息
private Implementation clientInfo = new Implementation("Java SDK MCP Client", "1.0.0");
// 工具变更通知的消费者列表
private final List<Consumer<List<McpSchema.Tool>>> toolsChangeConsumers = new ArrayList<>();
// 其他属性省略...
private SyncSpec(McpClientTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
}
/**
* 设置请求超时时间
*/
public SyncSpec requestTimeout(Duration requestTimeout) {
Assert.notNull(requestTimeout, "Request timeout must not be null");
this.requestTimeout = requestTimeout;
return this;
}
/**
* 设置初始化超时时间
*/
public SyncSpec initializationTimeout(Duration initializationTimeout) {
Assert.notNull(initializationTimeout, "Initialization timeout must not be null");
this.initializationTimeout = initializationTimeout;
return this;
}
/**
* 设置客户端能力配置
*/
public SyncSpec capabilities(ClientCapabilities capabilities) {
Assert.notNull(capabilities, "Capabilities must not be null");
this.capabilities = capabilities;
return this;
}
/**
* 设置客户端实现信息
*/
public SyncSpec clientInfo(Implementation clientInfo) {
Assert.notNull(clientInfo, "Client info must not be null");
this.clientInfo = clientInfo;
return this;
}
/**
* 设置客户端工具变更通知的消费者列表
*/
public SyncSpec toolsChangeConsumer(Consumer<List<McpSchema.Tool>> toolsChangeConsumer) {
Assert.notNull(toolsChangeConsumer, "Tools change consumer must not be null");
this.toolsChangeConsumers.add(toolsChangeConsumer);
return this;
}
/**
* 构建同步客户端实例
*/
public McpSyncClient build() {
// 由于「同步」客户端依赖于「异步」客户端,因此这里会先创建「异步」客户端,再将其作为「同步」客户端的属性
McpClientFeatures.Sync syncFeatures = new McpClientFeatures.Sync(this.clientInfo, this.capabilities,
this.roots, this.toolsChangeConsumers, this.resourcesChangeConsumers, this.promptsChangeConsumers,
this.loggingConsumers, this.samplingHandler);
McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures);
return new McpSyncClient(
new McpAsyncClient(transport, this.requestTimeout, this.initializationTimeout, asyncFeatures));
}
// 其他方法省略...
}
/**
* 异步客户端构建器
*/
class AsyncSpec {
// 异步构建器的属性和方法也是类似的
private final McpClientTransport transport;
private Duration requestTimeout = Duration.ofSeconds(20);
private Duration initializationTimeout = Duration.ofSeconds(20);
private ClientCapabilities capabilities;
private Implementation clientInfo = new Implementation("Spring AI MCP Client", "0.3.1");
private final List<Function<List<McpSchema.Tool>, Mono<Void>>> toolsChangeConsumers = new ArrayList<>();
// 其他属性省略...
private AsyncSpec(McpClientTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
}
public AsyncSpec requestTimeout(Duration requestTimeout) {
Assert.notNull(requestTimeout, "Request timeout must not be null");
this.requestTimeout = requestTimeout;
return this;
}
public AsyncSpec initializationTimeout(Duration initializationTimeout) {
Assert.notNull(initializationTimeout, "Initialization timeout must not be null");
this.initializationTimeout = initializationTimeout;
return this;
}
public AsyncSpec capabilities(ClientCapabilities capabilities) {
Assert.notNull(capabilities, "Capabilities must not be null");
this.capabilities = capabilities;
return this;
}
public AsyncSpec clientInfo(Implementation clientInfo) {
Assert.notNull(clientInfo, "Client info must not be null");
this.clientInfo = clientInfo;
return this;
}
public AsyncSpec toolsChangeConsumer(Function<List<McpSchema.Tool>, Mono<Void>> toolsChangeConsumer) {
Assert.notNull(toolsChangeConsumer, "Tools change consumer must not be null");
this.toolsChangeConsumers.add(toolsChangeConsumer);
return this;
}
public McpAsyncClient build() {
return new McpAsyncClient(this.transport, this.requestTimeout, this.initializationTimeout,
new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots,
this.toolsChangeConsumers, this.resourcesChangeConsumers, this.promptsChangeConsumers,
this.loggingConsumers, this.samplingHandler));
}
// 其他方法省略...
}
}
3.1.2 运行层
MCP 客户端运行层涉及到的类包括 McpSyncClient 、McpAsyncClient,如下图所示:

在运行层中,McpSyncClient 和 McpAsyncClient 分别是 MCP 同步客户端和异步客户端的执行核心,它们共同承担了与服务端交互的实际逻辑。从类图中可以看出,同步客户端并没有独立实现实际的业务逻辑,而是通过组合的方式持有一个异步客户端实例,并将所有核心方法调用委托给它执行 。在其源码中,initialize()、ping()、callTool() 等方法都是通过调用异步客户端对应的方法,再通过阻塞的方式获取结果的。也就是说,同步客户端只是异步客户端的一层包装。
异步客户端是整个运行层的逻辑核心,内部封装了 MCP 会话、能力配置、传输层等多个核心对象:
initialized:表示是否初始化完成。mcpSession:客户端与服务端通信的上下文对象,封装了消息发送、传输通道关闭等底层逻辑。clientCapabilities/serverCapabilities:分别表示客户端与服务端的功能能力,如客户端是否支持采样,服务端是否支持工具调用、Prompt 管理、资源同步等。clientInfo/serverInfo:分别表示客户端与服务端的基本信息,如名称和版本。transport:底层传输通道(如 Stdio、SSE 等),屏蔽了具体的协议细节。
主要方法包括:
initialize():负责完成 MCP 客户端的初始化过程,建议通信会话、同步能力信息。ping():发送一个心跳请求以验证连接状态,用于检测服务端是否仍处于可用状态。callTool():调用服务端注册的某个工具。listTools():向服务端请求来获取可用的工具列表。close():立即关闭客户端连接和会话资源。closeGracefully():执行优雅关闭操作,确保未完成的请求正常结束。
核心的源码及注释如下所示:
Java
/**
* MCP 异步客户端
*/
public class McpAsyncClient {
// 是否初始化完成
private AtomicBoolean initialized = new AtomicBoolean(false);
// 会话层对象
private final McpClientSession mcpSession;
// 客户端能力配置
private final McpSchema.ClientCapabilities clientCapabilities;
// 服务端能力配置
private McpSchema.ServerCapabilities serverCapabilities;
// 传输层对象
private final McpTransport transport;
// 其他属性省略...
/**
* MCP 异步客户端构造方法
*
* @param transport 传输层对象
* @param requestTimeout 会话中请求-响应的超时时间
* @param initializationTimeout 客户端-服务器等待的最大超时时间
* @param features MCP 客户端支持的特性
*/
McpAsyncClient(McpClientTransport transport, Duration requestTimeout, Duration initializationTimeout,
McpClientFeatures.Async features) {
Assert.notNull(transport, "Transport must not be null");
Assert.notNull(requestTimeout, "Request timeout must not be null");
Assert.notNull(initializationTimeout, "Initialization timeout must not be null");
this.clientInfo = features.clientInfo();
this.clientCapabilities = features.clientCapabilities();
this.transport = transport;
this.roots = new ConcurrentHashMap<>(features.roots());
this.initializationTimeout = initializationTimeout;
// 请求处理器 key: 方法名,value: 处理器
Map<String, RequestHandler<?>> requestHandlers = new HashMap<>();
if (this.clientCapabilities.roots() != null) {
requestHandlers.put(McpSchema.METHOD_ROOTS_LIST, rootsListRequestHandler());
}
if (this.clientCapabilities.sampling() != null) {
if (features.samplingHandler() == null) {
throw new McpError("Sampling handler must not be null when client capabilities include sampling");
}
this.samplingHandler = features.samplingHandler();
requestHandlers.put(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE, samplingCreateMessageHandler());
}
// 通知处理器,key: 方法名,value: 处理器
Map<String, NotificationHandler> notificationHandlers = new HashMap<>();
// Tools Change Notification
// 工具变更通知消费者
List<Function<List<McpSchema.Tool>, Mono<Void>>> toolsChangeConsumersFinal = new ArrayList<>();
// 添加默认的调试日志消费者
toolsChangeConsumersFinal
.add((notification) -> Mono.fromRunnable(() -> logger.debug("Tools changed: {}", notification)));
// 添加用户自定义的消费者
if (!Utils.isEmpty(features.toolsChangeConsumers())) {
toolsChangeConsumersFinal.addAll(features.toolsChangeConsumers());
}
// 注册工具变更通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED,
asyncToolsChangeNotificationHandler(toolsChangeConsumersFinal));
// 资源变更通知消费者
List<Function<List<McpSchema.Resource>, Mono<Void>>> resourcesChangeConsumersFinal = new ArrayList<>();
resourcesChangeConsumersFinal
.add((notification) -> Mono.fromRunnable(() -> logger.debug("Resources changed: {}", notification)));
if (!Utils.isEmpty(features.resourcesChangeConsumers())) {
resourcesChangeConsumersFinal.addAll(features.resourcesChangeConsumers());
}
// 注册资源变更通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED,
asyncResourcesChangeNotificationHandler(resourcesChangeConsumersFinal));
// 提示词变更通知消费者
List<Function<List<McpSchema.Prompt>, Mono<Void>>> promptsChangeConsumersFinal = new ArrayList<>();
promptsChangeConsumersFinal
.add((notification) -> Mono.fromRunnable(() -> logger.debug("Prompts changed: {}", notification)));
if (!Utils.isEmpty(features.promptsChangeConsumers())) {
promptsChangeConsumersFinal.addAll(features.promptsChangeConsumers());
}
// 注册提示词变更通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED,
asyncPromptsChangeNotificationHandler(promptsChangeConsumersFinal));
// 日志记录变更通知消费者
List<Function<LoggingMessageNotification, Mono<Void>>> loggingConsumersFinal = new ArrayList<>();
loggingConsumersFinal.add((notification) -> Mono.fromRunnable(() -> logger.debug("Logging: {}", notification)));
if (!Utils.isEmpty(features.loggingConsumers())) {
loggingConsumersFinal.addAll(features.loggingConsumers());
}
// 注册日志记录变更通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_MESSAGE,
asyncLoggingNotificationHandler(loggingConsumersFinal));
// 创建客户端会话
this.mcpSession = new McpClientSession(requestTimeout, transport, requestHandlers, notificationHandlers);
}
/**
* 立刻关闭客户端连接
*/
public void close() {
this.mcpSession.close();
}
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
public Mono<Void> closeGracefully() {
return this.mcpSession.closeGracefully();
}
/**
* 初始化阶段
*
* @return Mono,初始化后完成
*/
public Mono<McpSchema.InitializeResult> initialize() {
String latestVersion = this.protocolVersions.get(this.protocolVersions.size() - 1);
// 构建初始化请求
McpSchema.InitializeRequest initializeRequest = new McpSchema.InitializeRequest(// @formatter:off
latestVersion,
this.clientCapabilities,
this.clientInfo); // @formatter:on
// 向服务端发送初始化请求
Mono<McpSchema.InitializeResult> result = this.mcpSession.sendRequest(McpSchema.METHOD_INITIALIZE,
initializeRequest, new TypeReference<McpSchema.InitializeResult>() {
});
return result.flatMap(initializeResult -> {
// 存放服务端配置信息
this.serverCapabilities = initializeResult.capabilities();
this.serverInstructions = initializeResult.instructions();
this.serverInfo = initializeResult.serverInfo();
logger.info("Server response with Protocol: {}, Capabilities: {}, Info: {} and Instructions {}",
initializeResult.protocolVersion(), initializeResult.capabilities(), initializeResult.serverInfo(),
initializeResult.instructions());
if (!this.protocolVersions.contains(initializeResult.protocolVersion())) {
// 客户端不支持服务端协议版本,返回错误信息
return Mono.error(new McpError(
"Unsupported protocol version from the server: " + initializeResult.protocolVersion()));
}
// 向服务端发送通知,告知初始化完成
return this.mcpSession.sendNotification(McpSchema.METHOD_NOTIFICATION_INITIALIZED, null).doOnSuccess(v -> {
// 标记初始化完成
this.initialized.set(true);
this.initializedSink.tryEmitValue(initializeResult);
}).thenReturn(initializeResult);
});
}
/**
* 在执行操作之前,确保客户端已经初始化完成
*
* @param actionName 执行的操作名
* @param operation 具体的操作
* @return Mono,操作执行后完成
*/
private <T> Mono<T> withInitializationCheck(String actionName,
Function<McpSchema.InitializeResult, Mono<T>> operation) {
return this.initializedSink.asMono()
.timeout(this.initializationTimeout)
.onErrorResume(TimeoutException.class,
ex -> Mono.error(new McpError("Client must be initialized before " + actionName)))
.flatMap(operation);
}
/**
* 向服务端发送 ping
*
* @return Mono,服务器响应后完成
*/
public Mono<Object> ping() {
return this.withInitializationCheck("pinging the server", initializedResult -> this.mcpSession
.sendRequest(McpSchema.METHOD_PING, null, new TypeReference<Object>() {
}));
}
/**
* 向服务端调用指定的工具
*
* @param callToolRequest 请求,包括工具名、参数
* @return Mono,服务端响应后完成
*/
public Mono<McpSchema.CallToolResult> callTool(McpSchema.CallToolRequest callToolRequest) {
return this.withInitializationCheck("calling tools", initializedResult -> {
if (this.serverCapabilities.tools() == null) {
return Mono.error(new McpError("Server does not provide tools capability"));
}
// 向服务端发送请求调用工具
return this.mcpSession.sendRequest(McpSchema.METHOD_TOOLS_CALL, callToolRequest, CALL_TOOL_RESULT_TYPE_REF);
});
}
/**
* 检索服务端提供的所有工具列表
*
* @return Mono,服务端响应后完成
*/
public Mono<McpSchema.ListToolsResult> listTools() {
return this.listTools(null);
}
/**
* 检索服务端提供的所有工具列表
*
* @param cursor 分页游标(可选)
* @return Mono,服务端响应后完成
*/
public Mono<McpSchema.ListToolsResult> listTools(String cursor) {
return this.withInitializationCheck("listing tools", initializedResult -> {
if (this.serverCapabilities.tools() == null) {
return Mono.error(new McpError("Server does not provide tools capability"));
}
// 向服务端发送请求获取工具列表
return this.mcpSession.sendRequest(McpSchema.METHOD_TOOLS_LIST, new McpSchema.PaginatedRequest(cursor),
LIST_TOOLS_RESULT_TYPE_REF);
});
}
/**
* 构建工具变更通知处理器
* @param toolsChangeConsumers 消费者
* @return 处理器
*/
private NotificationHandler asyncToolsChangeNotificationHandler(
List<Function<List<McpSchema.Tool>, Mono<Void>>> toolsChangeConsumers) {
return params -> this.listTools()
// 将工具广播给所有消费者,并执行每个消费者的逻辑
.flatMap(listToolsResult -> Flux.fromIterable(toolsChangeConsumers)
.flatMap(consumer -> consumer.apply(listToolsResult.tools()))
.onErrorResume(error -> {
logger.error("Error handling tools list change notification", error);
return Mono.empty();
})
.then());
}
// 其他方法省略...
}
Java
/**
* MCP 同步客户端,封装了 MCPAsyncClient 来提供阻塞操作的 API
*/
public class McpSyncClient implements AutoCloseable {
// 代理,MCP 异步客户端
private final McpAsyncClient delegate;
/**
* MCP 同步客户端构造方法
*
* @param delegate 代理,实际为 MCP 异步客户端
*/
McpSyncClient(McpAsyncClient delegate) {
Assert.notNull(delegate, "The delegate can not be null");
this.delegate = delegate;
}
// 方法与异步客户端类似,只是内部逻辑都交由异步客户端来完成,且为阻塞过程
@Override
public void close() {
this.delegate.close();
}
public boolean closeGracefully() {
try {
this.delegate.closeGracefully().block(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));
}
catch (RuntimeException e) {
logger.warn("Client didn't close within timeout of {} ms.", DEFAULT_CLOSE_TIMEOUT_MS, e);
return false;
}
return true;
}
public McpSchema.InitializeResult initialize() {
return this.delegate.initialize().block();
}
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();
}
}
3.1.3 会话层
MCP 客户端会话层涉及到的类包括 McpSession 、McpClientSession,如下图所示:

会话层是 MCP 架构中负责消息收发和事件处理的核心部分,它将客户端与底层传输通道解耦,使上层逻辑无需关心具体通信细节。其通过 McpSession 接口定义统一操作规范,并在 McpClientSession 提供了具体实现。其核心方法包括:
sendRequest():向服务端发送请求消息并等待响应,返回 Mono 表示支持异步处理。sendNotification():向服务端发送无响应的通知消息,返回 Mono 表示支持异步处理。close():立即关闭客户端连接和会话资源。closeGracefully():执行优雅关闭操作,确保未完成的请求正常结束,返回 Mono 表示支持异步处理。
McpClientSession 实现了上述的方法,其内部核心的成员变量包括:
requestTimeout:请求超时时间,用于控制请求等待时长,避免长时间阻塞。transport:传输层对象,屏蔽了实际的传输协议实现。pendingResponses:并发哈希表,保存所有待处理的请求响应,通过 MonoSink 与异步流绑定,实现请求-响应的异步匹配。requestHandlers/notification:分别表示请求处理器和通知处理器,用于动态处理服务端请求或通知,当服务端向客户端发送请求或通知时,则调用对应的处理器进行处理。connection:表示底层连接的生命周期管理对象,用于控制会话的启动与关闭。
核心的源码及注释如下所示:
Java
/**
* MCP 会话,用户处理客户端与服务端之间的通信
* 提供了消息交互和会话生命周期管理的方法
*/
public interface McpSession {
/**
* 向服务端发送请求并返回响应结果
*
* @param method 调用的方法名
* @param requestParams 请求参数
* @param typeRef 反序列化响应结果所需的类型
* @return Mono,服务端响应后完成
*/
<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef);
/**
* 向服务端发送不带参数的通知
*
* @param method 方法名
* @return Mono,通知发送后完成
*/
default Mono<Void> sendNotification(String method) {
return sendNotification(method, null);
}
/**
* 向服务端发送带参数的通知
*
* @param method 通知方法名
* @param params 方法参数
* @return Mono,通知发送后完成
*/
Mono<Void> sendNotification(String method, Object params);
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
Mono<Void> closeGracefully();
/**
* 立刻关闭客户端连接
*/
void close();
}
Java
/**
* MCP 客户端会话实现类,用于管理客户端和服务端之间的双向 JSON-RPC 通信
*/
public class McpClientSession implements McpSession {
// 请求超时时间
private final Duration requestTimeout;
// 传输层对象
private final McpClientTransport transport;
// 待处理的请求响应
private final ConcurrentHashMap<Object, MonoSink<McpSchema.JSONRPCResponse>> pendingResponses = new ConcurrentHashMap<>();
// 请求处理器
private final ConcurrentHashMap<String, RequestHandler<?>> requestHandlers = new ConcurrentHashMap<>();
// 通知处理器
private final ConcurrentHashMap<String, NotificationHandler> notificationHandlers = new ConcurrentHashMap<>();
// 请求 id 的会话前缀
private final String sessionPrefix = UUID.randomUUID().toString().substring(0, 8);
// 用于生成唯一请求 id 的原子计数器
private final AtomicLong requestCounter = new AtomicLong(0);
// 底层连接对象
private final Disposable connection;
/**
* 创建客户端会话对象
*
* @param requestTimeout 请求超时时间
* @param transport 传输层对象
* @param requestHandlers 请求处理器
* @param notificationHandlers 通知处理器
*/
public McpClientSession(Duration requestTimeout, McpClientTransport transport,
Map<String, RequestHandler<?>> requestHandlers, Map<String, NotificationHandler> notificationHandlers) {
Assert.notNull(requestTimeout, "The requestTimeout can not be null");
Assert.notNull(transport, "The transport can not be null");
Assert.notNull(requestHandlers, "The requestHandlers can not be null");
Assert.notNull(notificationHandlers, "The notificationHandlers can not be null");
this.requestTimeout = requestTimeout;
this.transport = transport;
this.requestHandlers.putAll(requestHandlers);
this.notificationHandlers.putAll(notificationHandlers);
// 使用传输层对象建立连接
this.connection = this.transport.connect(mono -> mono.doOnNext(this::handle)).subscribe();
}
/**
* 处理接收到的 JSON-RPC 消息
*
* @param message JSON-RPC 消息
*/
private void handle(McpSchema.JSONRPCMessage message) {
if (message instanceof McpSchema.JSONRPCResponse response) {
// 处理响应消息
logger.debug("Received Response: {}", response);
// 根据响应 id 取出对应的 MonoSink(等待结果的响应对象)
var sink = pendingResponses.remove(response.id());
if (sink == null) {
logger.warn("Unexpected response for unknown id {}", response.id());
}
else {
// 将响应结果推送给订阅者
sink.success(response);
}
}
else if (message instanceof McpSchema.JSONRPCRequest request) {
// 处理请求消息
logger.debug("Received request: {}", request);
handleIncomingRequest(request).onErrorResume(error -> {
// 处理请求时发生错误,则构造 JSON-RPC 错误响应发送给服务端
var errorResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), null,
new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR,
error.getMessage(), null));
return this.transport.sendMessage(errorResponse).then(Mono.empty());
}).flatMap(this.transport::sendMessage).subscribe();
}
else if (message instanceof McpSchema.JSONRPCNotification notification) {
// 处理通知消息
logger.debug("Received notification: {}", notification);
handleIncomingNotification(notification)
.doOnError(error -> logger.error("Error handling notification: {}", error.getMessage()))
.subscribe();
}
else {
logger.warn("Received unknown message type: {}", message);
}
}
/**
* 处理 JSON-RPC 请求消息,将其路由到对应的处理器
*
* @param request JSON-RPC 请求
* @return Mono,处理后完成
*/
private Mono<McpSchema.JSONRPCResponse> handleIncomingRequest(McpSchema.JSONRPCRequest request) {
return Mono.defer(() -> {
// 根据方法名获取处理器
var handler = this.requestHandlers.get(request.method());
if (handler == null) {
// 不存在处理器时,返回 JSON-RPC 错误消息
MethodNotFoundError error = getMethodNotFoundError(request.method());
return Mono.just(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), null,
new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.METHOD_NOT_FOUND,
error.message(), error.data())));
}
// 调用处理器,并将结果封装成 JSON-RPC 消息
return handler.handle(request.params())
.map(result -> new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), result, null))
.onErrorResume(error -> Mono.just(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
null, new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR,
error.getMessage(), null))));
});
}
/**
* 表示方法未找到的错误数据结构
*
* @param method 方法名
* @param message 异常信息
* @param data 附加数据
*/
record MethodNotFoundError(String method, String message, Object data) {
}
/**
* 根据方法名返回对应的 MethodNotFoundError 对象
*
* @param method 方法名
* @return MethodNotFoundError 对象
*/
private MethodNotFoundError getMethodNotFoundError(String method) {
switch (method) {
case McpSchema.METHOD_ROOTS_LIST:
return new MethodNotFoundError(method, "Roots not supported",
Map.of("reason", "Client does not have roots capability"));
default:
return new MethodNotFoundError(method, "Method not found: " + method, null);
}
}
/**
* 处理 JSON-RPC 通知消息,将其路由到对应的处理器
*
* @param notification JSON-RPC 融资股
* @return Mono,处理后完成
*/
private Mono<Void> handleIncomingNotification(McpSchema.JSONRPCNotification notification) {
return Mono.defer(() -> {
// 根据方法名获取处理器
var handler = notificationHandlers.get(notification.method());
if (handler == null) {
// 不存在处理器时直接返回
logger.error("No handler registered for notification method: {}", notification.method());
return Mono.empty();
}
// 调用处理器
return handler.handle(notification.params());
});
}
/**
* 生成唯一的请求 id
*
* @return 请求 id
*/
private String generateRequestId() {
return this.sessionPrefix + "-" + this.requestCounter.getAndIncrement();
}
/**
* 发送 JSON-RPC 请求并返回响应结果
*
* @param method 调用的方法名
* @param requestParams 请求参数
* @param typeRef 响应反序列化所需的类型
* @return Mono,包含响应结果
*/
@Override
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
// 生成请求 id
String requestId = this.generateRequestId();
return Mono.deferContextual(ctx -> Mono.<McpSchema.JSONRPCResponse>create(sink -> {
// 缓存当前请求
this.pendingResponses.put(requestId, sink);
// 构建 JSON-RPC 请求对象
McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, method,
requestId, requestParams);
// 发送消息
this.transport.sendMessage(jsonrpcRequest)
.contextWrite(ctx)
.subscribe(v -> {
}, error -> {
this.pendingResponses.remove(requestId);
sink.error(error);
});
})).timeout(this.requestTimeout).handle((jsonRpcResponse, sink) -> {
// 处理响应
if (jsonRpcResponse.error() != null) {
// 出现异常
logger.error("Error handling request: {}", jsonRpcResponse.error());
sink.error(new McpError(jsonRpcResponse.error()));
}
else {
if (typeRef.getType().equals(Void.class)) {
// 返回结果类型为空时直接结束
sink.complete();
}
else {
// 返回结果类型不为空时将结果转换为 typeRef 类型对象并返回
sink.next(this.transport.unmarshalFrom(jsonRpcResponse.result(), typeRef));
}
}
});
}
/**
* 发送 JSON-RPC 通知
*
* @param method 通知方法名
* @param params 方法参数
* @return Mono,发送后完成
*/
@Override
public Mono<Void> sendNotification(String method, Object params) {
// 构建 JSON-RPC 消息
McpSchema.JSONRPCNotification jsonrpcNotification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
method, params);
// 发送消息
return this.transport.sendMessage(jsonrpcNotification);
}
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
@Override
public Mono<Void> closeGracefully() {
return Mono.defer(() -> {
this.connection.dispose();
return transport.closeGracefully();
});
}
/**
* 立刻关闭客户端连接
*/
@Override
public void close() {
this.connection.dispose();
transport.close();
}
}
3.1.4 传输层
MCP 客户端传输层涉及到的类包括:McpTransport 、McpClientTransport 、HttpClientSseClientTransport 、StdioClientTransport 等,其中 HttpClientSseClientTransport 和 StdioClientTransport 为 McpClientTransport 实现类,分别对应 SSE 和 Stdio 的具体实现,这里仅列出两种,实际上不同的传输协议都会有对应的实现类。其类图如下所示:

传输层承担着所有消息的实际发送与接收职责,无论上层如何组织会话或封装客户端逻辑,最终都必须通过这一层将 JSON-RPC 消息序列化、发送并接收响应。核心接口是 McpTransport 和其子接口 McpClientTransport:
McpTransport接口定义了基础通信能力:sendMessage():向服务端异步发送 JSON-RPC 消息。unmarshalFrom():将数据转化为指定类型的对象。close():立刻关闭传输连接。closeGracefully():优雅关闭传输连接,将阻止新的消息发送,但允许正在进行的操作完成。
McpClientTransport则扩展了客户端的连接行为:connect():建立与服务端的连接,同时会将消息流与客户端的处理逻辑绑定起来。
核心的源码及注释如下所示(实现类中仅给出 HttpClientSseClientTransport 的具体实现,其他的实现类是类似的):
Java
/**
* MCP 异步传输层
*/
public interface McpTransport {
/**
* 立刻关闭客户端连接
*/
default void close() {
this.closeGracefully().subscribe();
}
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
Mono<Void> closeGracefully();
/**
* 异步发送 JSON-RPC 消息
*
* @param message JSON-RPC 消息
* @return Mono,发送后完成
*/
Mono<Void> sendMessage(JSONRPCMessage message);
/**
* 将数据转换为指定类型的对象
*
* @param data 数据
* @param typeRef 指定类型
* @return 指定类型的对象
*/
<T> T unmarshalFrom(Object data, TypeReference<T> typeRef);
}
Java
/**
* MCP 客户端传输层
*/
public interface McpClientTransport extends McpTransport {
/**
* 与服务端建立连接
*
* @param handler 处理器,用于处理从服务端接收到的消息
* @return Mono,连接建立时完成
*/
Mono<Void> connect(Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchema.JSONRPCMessage>> handler);
}
Java
/**
* SSE 传输层实现类
*/
public class HttpClientSseClientTransport implements McpClientTransport {
private static final Logger logger = LoggerFactory.getLogger(HttpClientSseClientTransport.class);
// 消息事件类型
private static final String MESSAGE_EVENT_TYPE = "message";
// 端点事件类型
private static final String ENDPOINT_EVENT_TYPE = "endpoint";
// SSE 端点默认值
private static final String DEFAULT_SSE_ENDPOINT = "/sse";
// MCP 服务端 uri
private final URI baseUri;
// SSE 端点
private final String sseEndpoint;
// SSE 客户端,用于处理服务端发送的事件
private final FlowSseClient sseClient;
// HTTP 客户端,用于向服务端发送消息,使用 HTTP/POST 方法
private final HttpClient httpClient;
// HTTP 请求构建器,用于构建向服务端发送消息的请求
private final HttpRequest.Builder requestBuilder;
// JSON 对象映射器,用于消息序列化/反序列化
protected ObjectMapper objectMapper;
// 标志传输是否处于关闭状态
private volatile boolean isClosing = false;
// 协调端点发现的锁
private final CountDownLatch closeLatch = new CountDownLatch(1);
// 消息端点
private final AtomicReference<String> messageEndpoint = new AtomicReference<>();
// SSE 连接
private final AtomicReference<CompletableFuture<Void>> connectionFuture = new AtomicReference<>();
/**
* 创建传输层对象
*
* @param httpClient HTTP 客户端
* @param requestBuilder HTTP 请求构建器
* @param baseUri MCP 服务端 uri
* @param sseEndpoint SSE 端点
* @param objectMapper JSON 对象映射器
*/
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
String sseEndpoint, ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
Assert.hasText(baseUri, "baseUri must not be empty");
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
Assert.notNull(httpClient, "httpClient must not be null");
Assert.notNull(requestBuilder, "requestBuilder must not be null");
this.baseUri = URI.create(baseUri);
this.sseEndpoint = sseEndpoint;
this.objectMapper = objectMapper;
this.httpClient = httpClient;
this.requestBuilder = requestBuilder;
this.sseClient = new FlowSseClient(this.httpClient, requestBuilder);
}
/**
* 与服务端建立 SSE 连接并设置消息处理
*
* @param handler 处理接收到的 JSON-RPC 消息
* @return Mono,当连接建立时完成
*/
@Override
public Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler) {
CompletableFuture<Void> future = new CompletableFuture<>();
connectionFuture.set(future);
// 拼接 SSE 服务端的完整 URI(baseUri + sseEndpoint)
URI clientUri = Utils.resolveUri(this.baseUri, this.sseEndpoint);
// 发起订阅,监听服务端的 SSE 事件
sseClient.subscribe(clientUri.toString(), new FlowSseClient.SseEventHandler() {
@Override
public void onEvent(SseEvent event) {
if (isClosing) {
// 若传输关闭则直接退出
return;
}
try {
if (ENDPOINT_EVENT_TYPE.equals(event.type())) {
// endpoint 事件,接收服务端返回的消息发送端点地址
String endpoint = event.data();
messageEndpoint.set(endpoint);
closeLatch.countDown();
future.complete(null);
}
else if (MESSAGE_EVENT_TYPE.equals(event.type())) {
// message 事件,接收服务端推送的 JSON-RPC 消息
// 反序列化数据为 JSON-RPC 格式数据
JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, event.data());
// 调用处理器来处理服务端返回的消息
handler.apply(Mono.just(message)).subscribe();
}
else {
logger.error("Received unrecognized SSE event type: {}", event.type());
}
}
catch (IOException e) {
logger.error("Error processing SSE event", e);
future.completeExceptionally(e);
}
}
@Override
public void onError(Throwable error) {
if (!isClosing) {
logger.error("SSE connection error", error);
future.completeExceptionally(error);
}
}
});
return Mono.fromFuture(future);
}
/**
* 向服务端发送 JSON-RPC 消息
*
* @param message 发送的 JSON-RPC 消息
* @return Mono,当消息发送成功时完成
*/
@Override
public Mono<Void> sendMessage(JSONRPCMessage message) {
if (isClosing) {
return Mono.empty();
}
try {
if (!closeLatch.await(10, TimeUnit.SECONDS)) {
// 确保连接已经建立
return Mono.error(new McpError("Failed to wait for the message endpoint"));
}
}
catch (InterruptedException e) {
return Mono.error(new McpError("Failed to wait for the message endpoint"));
}
// 获取发送消息的端点
String endpoint = messageEndpoint.get();
if (endpoint == null) {
return Mono.error(new McpError("No message endpoint available"));
}
try {
// 序列化消息,将 JSON-RPC 消息转化为字符串
String jsonText = this.objectMapper.writeValueAsString(message);
// 拼接 URI(baseUri + messageEndpoint)
URI requestUri = Utils.resolveUri(baseUri, endpoint);
// 构建 POST 请求
HttpRequest request = this.requestBuilder.uri(requestUri)
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
.build();
return Mono.fromFuture(
// 异步发送 HTTP 请求
httpClient.sendAsync(request, HttpResponse.BodyHandlers.discarding()).thenAccept(response -> {
if (response.statusCode() != 200 && response.statusCode() != 201 && response.statusCode() != 202
&& response.statusCode() != 206) {
logger.error("Error sending message: {}", response.statusCode());
}
}));
}
catch (IOException e) {
if (!isClosing) {
return Mono.error(new RuntimeException("Failed to serialize message", e));
}
return Mono.empty();
}
}
/**
* 优雅地关闭传输连接,将阻止新的消息发送,并允许正在进行的操作完成
*
* @return Mono,当关闭成功时完成
*/
@Override
public Mono<Void> closeGracefully() {
return Mono.fromRunnable(() -> {
// 设置关闭标志
isClosing = true;
CompletableFuture<Void> future = connectionFuture.get();
if (future != null && !future.isDone()) {
// 关闭连接
future.cancel(true);
}
});
}
/**
* 使用配置的对象映射器将数据解析为指定类型
*
* @param data 解析的数据
* @param typeRef 转换的目标类型
* @return 解析后的对象
*/
@Override
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
return this.objectMapper.convertValue(data, typeRef);
}
}
3.2 服务端
3.2.1 入口层
MCP 服务端入口层涉及到的类包括 McpServer 、McpServer.AsyncSpecification (内部类)、McpClient.SyncSpecification(内部类),如下图所示:

与客户端类似,入口层也是创建 MCP 服务端的统一入口,通过静态方法 sync() 和 async() 提供了同步和异步两种模式的构建方式,分别返回 SyncSpecification 和 AyncSpecification 这两个内部构建器类,用于配置客户端实例的各项参数并最终生成对应的 McpSyncServer 和 McpAsyncServer。
并且,AyncSpecification 和 SyncSpecification 的设计也十分相似,都封装了配置信息,且它们内部的方法(如 serverInfo()、capabilities())都只是对构建器内成员变量和的简单赋值。而不同的是,异步模式在处理服务端的变更通知时,是基于 Reactor 的 Mono 进行响应式调用的,而同步模式则使用传统的 Consumer 回调方式。
核心的参数描述如下:
transportProvider:会话管理层实现对象。objectMappe:对象映射器,用于序列化和反序列化 JSON 消息。serverInfo:服务端基本信息,包含服务端名字和版本,capabilities:服务端能力配置,包含补全、日志、工具等配置。tools:服务端可调用的工具列表。requestTimeout:请求超时时间,默认 10s。
核心的源码及注释如下所示:
Java
/**
* 创建 MCP 服务端的工厂类
*/
public interface McpServer {
/**
* 构建一个提供阻塞操作的同步 MCP 服务端
*
* @param transportProvider MCP 传输层实现
* @return 同步 MCP 服务端构建器
*/
static SyncSpecification sync(McpServerTransportProvider transportProvider) {
return new SyncSpecification(transportProvider);
}
/**
* 提供一个非阻塞操作的异步 MCP 服务端
*
* @param transportProvider MCP 会话管理对象
* @return 异步 MCP 服务端构建器
*/
static AsyncSpecification async(McpServerTransportProvider transportProvider) {
return new AsyncSpecification(transportProvider);
}
/**
* 异步 MCP 服务端构建器
*/
class AsyncSpecification {
// 默认服务端基本信息
private static final McpSchema.Implementation DEFAULT_SERVER_INFO = new McpSchema.Implementation("mcp-server",
"1.0.0");
// 会话管理对象
private final McpServerTransportProvider transportProvider;
// JSON 对象映射器,用于消息序列化/反序列化
private ObjectMapper objectMapper;
// 服务端基本信息
private McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
// 服务端支持的功能
private McpSchema.ServerCapabilities serverCapabilities;
// 服务端可调用的工具列表
private final List<McpServerFeatures.AsyncToolSpecification> tools = new ArrayList<>();
// 请求超时时间
private Duration requestTimeout = Duration.ofSeconds(10);
// 其他属性省略...
private AsyncSpecification(McpServerTransportProvider transportProvider) {
Assert.notNull(transportProvider, "Transport provider must not be null");
this.transportProvider = transportProvider;
}
/**
* 设置对象映射器
*/
public AsyncSpecification objectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
return this;
}
/**
* 设置服务端基本信息
*/
public AsyncSpecification serverInfo(McpSchema.Implementation serverInfo) {
Assert.notNull(serverInfo, "Server info must not be null");
this.serverInfo = serverInfo;
return this;
}
/**
* 设置服务端支持的功能
*/
public AsyncSpecification capabilities(McpSchema.ServerCapabilities serverCapabilities) {
Assert.notNull(serverCapabilities, "Server capabilities must not be null");
this.serverCapabilities = serverCapabilities;
return this;
}
/**
* 添加工具
*/
public AsyncSpecification tools(List<McpServerFeatures.AsyncToolSpecification> toolSpecifications) {
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
this.tools.addAll(toolSpecifications);
return this;
}
/**
* 设置超时时间
*/
public AsyncSpecification requestTimeout(Duration requestTimeout) {
Assert.notNull(requestTimeout, "Request timeout must not be null");
this.requestTimeout = requestTimeout;
return this;
}
/**
* 构建异步 MCP 服务端
*/
public McpAsyncServer build() {
var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools,
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
this.instructions);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout,
this.uriTemplateManagerFactory);
}
// 其他方法省略...
}
/**
* 同步 MCP 服务端构建器
*/
class SyncSpecification {
// 异步构建器的属性和方法也是类似的
private static final McpSchema.Implementation DEFAULT_SERVER_INFO = new McpSchema.Implementation("mcp-server",
"1.0.0");
private final McpServerTransportProvider transportProvider;
private ObjectMapper objectMapper;
private McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
private McpSchema.ServerCapabilities serverCapabilities;
private final List<McpServerFeatures.SyncToolSpecification> tools = new ArrayList<>();
private Duration requestTimeout = Duration.ofSeconds(10);
// 其他属性省略...
private SyncSpecification(McpServerTransportProvider transportProvider) {
Assert.notNull(transportProvider, "Transport provider must not be null");
this.transportProvider = transportProvider;
}
public SyncSpecification objectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
return this;
}
public SyncSpecification serverInfo(McpSchema.Implementation serverInfo) {
Assert.notNull(serverInfo, "Server info must not be null");
this.serverInfo = serverInfo;
return this;
}
public SyncSpecification capabilities(McpSchema.ServerCapabilities serverCapabilities) {
Assert.notNull(serverCapabilities, "Server capabilities must not be null");
this.serverCapabilities = serverCapabilities;
return this;
}
public SyncSpecification tools(List<McpServerFeatures.SyncToolSpecification> toolSpecifications) {
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
this.tools.addAll(toolSpecifications);
return this;
}
public SyncSpecification requestTimeout(Duration requestTimeout) {
Assert.notNull(requestTimeout, "Request timeout must not be null");
this.requestTimeout = requestTimeout;
return this;
}
public McpSyncServer build() {
// 由于「同步」服务端依赖于「异步」服务端,因此这里会先创建「异步」服务端,再将其作为「同步」服务端的属性
McpServerFeatures.Sync syncFeatures = new McpServerFeatures.Sync(this.serverInfo, this.serverCapabilities,
this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions,
this.rootsChangeHandlers, this.instructions);
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout,
this.uriTemplateManagerFactory);
return new McpSyncServer(asyncServer);
}
// 其他方法省略...
}
}
3.2.2 运行层
MCP 服务端运行层涉及到的类包括 McpSyncServer 、McpAsyncServer,如下图所示:

在调用入口层中构建器的 build() 方法后,就能构建出运行层的服务端对象。与客户端类似,同步服务端并没有独立实现实际的业务逻辑,而是通过组合的方式持有一个异步服务端实例,并将所有核心方法调用委托给它执行。其核心的方法包括:
addTool():注册一个可用的工具。removeTool():注销工具。notifyToolsListChanged():通知客户端可用工具列表已更改。close():立即关闭服务端连接和会话资源。closeGracefully():执行优雅关闭操作,确保未完成的请求正常结束。
核心的源码及注释如下所示:
Java
/**
* MCP 异步服务端
*/
public class McpAsyncServer {
private static final Logger logger = LoggerFactory.getLogger(McpAsyncServer.class);
// 会话管理层对象
private final McpServerTransportProvider mcpTransportProvider;
// 对象映射器
private final ObjectMapper objectMapper;
// 服务端能力配置
private final McpSchema.ServerCapabilities serverCapabilities;
// 服务端基本信息
private final McpSchema.Implementation serverInfo;
// 工具列表
private final CopyOnWriteArrayList<McpServerFeatures.AsyncToolSpecification> tools = new CopyOnWriteArrayList<>();
// 其他属性省略...
/**
* MCP 异步服务端构造方法
*
* @param mcpTransportProvider 会话管理层对象
* @param objectMapper 对象映射器
* @param features 服务端特征
* @param requestTimeout 请求超时时间
*/
McpAsyncServer(McpServerTransportProvider mcpTransportProvider, ObjectMapper objectMapper,
McpServerFeatures.Async features, Duration requestTimeout,
McpUriTemplateManagerFactory uriTemplateManagerFactory) {
this.mcpTransportProvider = mcpTransportProvider;
this.objectMapper = objectMapper;
this.serverInfo = features.serverInfo();
this.serverCapabilities = features.serverCapabilities();
this.instructions = features.instructions();
this.tools.addAll(features.tools());
this.resources.putAll(features.resources());
this.resourceTemplates.addAll(features.resourceTemplates());
this.prompts.putAll(features.prompts());
this.completions.putAll(features.completions());
this.uriTemplateManagerFactory = uriTemplateManagerFactory;
Map<String, McpServerSession.RequestHandler<?>> requestHandlers = new HashMap<>();
// 初始化每个 MCP 方法对应的处理器
// 添加 PING 方法处理器
requestHandlers.put(McpSchema.METHOD_PING, (exchange, params) -> Mono.just(Map.of()));
if (this.serverCapabilities.tools() != null) {
// 添加列出工具列表处理器
requestHandlers.put(McpSchema.METHOD_TOOLS_LIST, toolsListRequestHandler());
// 添加工具调用处理器
requestHandlers.put(McpSchema.METHOD_TOOLS_CALL, toolsCallRequestHandler());
}
// 添加资源处理器
if (this.serverCapabilities.resources() != null) {
requestHandlers.put(McpSchema.METHOD_RESOURCES_LIST, resourcesListRequestHandler());
requestHandlers.put(McpSchema.METHOD_RESOURCES_READ, resourcesReadRequestHandler());
requestHandlers.put(McpSchema.METHOD_RESOURCES_TEMPLATES_LIST, resourceTemplateListRequestHandler());
}
// 添加模板处理器
if (this.serverCapabilities.prompts() != null) {
requestHandlers.put(McpSchema.METHOD_PROMPT_LIST, promptsListRequestHandler());
requestHandlers.put(McpSchema.METHOD_PROMPT_GET, promptsGetRequestHandler());
}
// 添加日志处理器
if (this.serverCapabilities.logging() != null) {
requestHandlers.put(McpSchema.METHOD_LOGGING_SET_LEVEL, setLoggerRequestHandler());
}
// 添加自动补全处理器
if (this.serverCapabilities.completions() != null) {
requestHandlers.put(McpSchema.METHOD_COMPLETION_COMPLETE, completionCompleteRequestHandler());
}
// 初始化每个通知方法对应的处理器
Map<String, McpServerSession.NotificationHandler> notificationHandlers = new HashMap<>();
// 添加初始化完成通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_INITIALIZED, (exchange, params) -> Mono.empty());
// 根列表变更消费者
List<BiFunction<McpAsyncServerExchange, List<McpSchema.Root>, Mono<Void>>> rootsChangeConsumers = features
.rootsChangeConsumers();
if (Utils.isEmpty(rootsChangeConsumers)) {
rootsChangeConsumers = List.of((exchange, roots) -> Mono.fromRunnable(() -> logger
.warn("Roots list changed notification, but no consumers provided. Roots list changed: {}", roots)));
}
// 添加根列表变更通知处理器
notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_ROOTS_LIST_CHANGED,
asyncRootsListChangedNotificationHandler(rootsChangeConsumers));
// 设置会话工厂对象
mcpTransportProvider.setSessionFactory(
transport -> new McpServerSession(UUID.randomUUID().toString(), requestTimeout, transport,
this::asyncInitializeRequestHandler, Mono::empty, requestHandlers, notificationHandlers));
}
/**
* 初始化处理器
*
* @param initializeRequest 初始化请求
* @return Mono,初始化后完成
*/
private Mono<McpSchema.InitializeResult> asyncInitializeRequestHandler(
McpSchema.InitializeRequest initializeRequest) {
return Mono.defer(() -> {
logger.info("Client initialize request - Protocol: {}, Capabilities: {}, Info: {}",
initializeRequest.protocolVersion(), initializeRequest.capabilities(),
initializeRequest.clientInfo());
// 需要返回的服务端协议版本,为当前支持的最高协议版本
String serverProtocolVersion = this.protocolVersions.get(this.protocolVersions.size() - 1);
if (this.protocolVersions.contains(initializeRequest.protocolVersion())) {
// 如果服务端支持客户端请求时指定的协议版本,则响应相同的版本
serverProtocolVersion = initializeRequest.protocolVersion();
}
else {
logger.warn(
"Client requested unsupported protocol version: {}, so the server will suggest the {} version instead",
initializeRequest.protocolVersion(), serverProtocolVersion);
}
// 将服务端的能力配置、基本信息等返回给客户端
return Mono.just(new McpSchema.InitializeResult(serverProtocolVersion, this.serverCapabilities,
this.serverInfo, this.instructions));
});
}
/**
* 优雅关闭服务端
*/
public Mono<Void> closeGracefully() {
return this.mcpTransportProvider.closeGracefully();
}
/**
* Close the server immediately.
*/
/**
* 立即关闭服务端
*/
public void close() {
this.mcpTransportProvider.close();
}
/**
* 添加新的工具
*
* @param toolSpecification 要添加的工具规范
* @return Mono,向客户端发送通知后返回
*/
public Mono<Void> addTool(McpServerFeatures.AsyncToolSpecification toolSpecification) {
if (toolSpecification == null) {
return Mono.error(new McpError("Tool specification must not be null"));
}
if (toolSpecification.tool() == null) {
return Mono.error(new McpError("Tool must not be null"));
}
if (toolSpecification.call() == null) {
return Mono.error(new McpError("Tool call handler must not be null"));
}
if (this.serverCapabilities.tools() == null) {
return Mono.error(new McpError("Server must be configured with tool capabilities"));
}
return Mono.defer(() -> {
// 检查是否存在重复名字的工具,如果存在直接返回错误信息
if (this.tools.stream().anyMatch(th -> th.tool().name().equals(toolSpecification.tool().name()))) {
return Mono
.error(new McpError("Tool with name '" + toolSpecification.tool().name() + "' already exists"));
}
this.tools.add(toolSpecification);
logger.debug("Added tool handler: {}", toolSpecification.tool().name());
if (this.serverCapabilities.tools().listChanged()) {
// 如果开启通知配置,则通知客户端工具列表变更
return notifyToolsListChanged();
}
return Mono.empty();
});
}
/**
* 移除工具
*
* @param toolName 移除的工具名
* @return Mono,向客户端发送通知后完成
*/
public Mono<Void> removeTool(String toolName) {
if (toolName == null) {
return Mono.error(new McpError("Tool name must not be null"));
}
if (this.serverCapabilities.tools() == null) {
return Mono.error(new McpError("Server must be configured with tool capabilities"));
}
return Mono.defer(() -> {
// 移除工具
boolean removed = this.tools
.removeIf(toolSpecification -> toolSpecification.tool().name().equals(toolName));
if (removed) {
logger.debug("Removed tool handler: {}", toolName);
if (this.serverCapabilities.tools().listChanged()) {
// 如果开启通知配置,则通知客户端工具列表变更
return notifyToolsListChanged();
}
return Mono.empty();
}
// 如果不存在对应名字的工具,即移除失败,则返回错误信息
return Mono.error(new McpError("Tool with name '" + toolName + "' not found"));
});
}
/**
* 通知客户端可用工具列表已更改
*
* @return Mono,通知后完成
*/
public Mono<Void> notifyToolsListChanged() {
// 调用会话管理层对象来通知
return this.mcpTransportProvider.notifyClients(McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED, null);
}
/**
* 列出工具列表处理器
*
* @return 工具列表
*/
private McpServerSession.RequestHandler<McpSchema.ListToolsResult> toolsListRequestHandler() {
return (exchange, params) -> {
List<Tool> tools = this.tools.stream().map(McpServerFeatures.AsyncToolSpecification::tool).toList();
return Mono.just(new McpSchema.ListToolsResult(tools, null));
};
}
/**
* 工具调用处理器
*
* @return 工具调用结果
*/
private McpServerSession.RequestHandler<CallToolResult> toolsCallRequestHandler() {
return (exchange, params) -> {
// 将请求参数转换为 CallToolRequest 对象
McpSchema.CallToolRequest callToolRequest = objectMapper.convertValue(params,
new TypeReference<McpSchema.CallToolRequest>() {
});
// 获取需要调用的工具
Optional<McpServerFeatures.AsyncToolSpecification> toolSpecification = this.tools.stream()
.filter(tr -> callToolRequest.name().equals(tr.tool().name()))
.findAny();
if (toolSpecification.isEmpty()) {
// 如果没找到工具,则返回错误信息
return Mono.error(new McpError("Tool not found: " + callToolRequest.name()));
}
return toolSpecification.map(tool -> tool.call().apply(exchange, callToolRequest.arguments()))
.orElse(Mono.error(new McpError("Tool not found: " + callToolRequest.name())));
};
}
// 其他方法省略...
}
Java
/**
* MCP 同步服务端,封装了 MCPAsyncServer 来提供阻塞操作的 API
*/
public class McpSyncServer {
// 异步服务端代理,实际的调用执行者
private final McpAsyncServer asyncServer;
/**
* MCP 同步客户端构造方法
*
* @param asyncServer 代理,实际为 MCP 异步客户端
*/
public McpSyncServer(McpAsyncServer asyncServer) {
Assert.notNull(asyncServer, "Async server must not be null");
this.asyncServer = asyncServer;
}
// 方法与异步服务端类似,只是内部逻辑都交由异步服务端来完成,且为阻塞过程
public void addTool(McpServerFeatures.SyncToolSpecification toolHandler) {
this.asyncServer.addTool(McpServerFeatures.AsyncToolSpecification.fromSync(toolHandler)).block();
}
public void removeTool(String toolName) {
this.asyncServer.removeTool(toolName).block();
}
public void notifyToolsListChanged() {
this.asyncServer.notifyToolsListChanged().block();
}
public void closeGracefully() {
this.asyncServer.closeGracefully().block();
}
public void close() {
this.asyncServer.close();
}
}
3.2.3 会话管理层
MCP 服务端会话管理层涉及到的类包括 McpServerTransportProvider 、HttpServletSseServerTransportProvider 、StdioServerTransportProvider 等,其中 HttpServletSseServerTransportProvider 和 StdioServerTransportProvider 为 McpServerTransportProvider 实现类,分别对应 SSE、Stdio 的具体实现,这里仅列出两种,实际上底层使用了不同的传输协议,会对应着不同的实现类。其类图如下图所示:

这一层是 MCP 服务端特有的部分,用于管理多个客户端会话。其中 McpServerTransportProvider 定义了相关的核心方法:
setSessionFactory():设置工厂对象,用于为新客户端创建会话的工厂对象。notifyClients():向所有已连接的客户端发送通知。close():立即关闭所有已连接客户端的传输并释放所有关联资源。closeGracefully():优雅地关闭所有已连接客户端的传输并异步释放所有关联资源。
核心的源码及注释如下所示(实现类中仅给出 HttpServletSseServerTransportProvider 的具体实现,其他的实现类是类似的):
Java
/**
* 用于桥接服务端和 MCP 服务器传输层
*/
public interface McpServerTransportProvider {
/**
* 设置工厂对象,用于为新客户端创建会话的工厂对象
*
* @param sessionFactory 会话工厂
*/
void setSessionFactory(McpServerSession.Factory sessionFactory);
/**
* 向所有已连接的客户端发送通知
*
* @param method 通知方法名
* @param params 通知方法对应的参数
* @return Mono,通知后完成
*/
Mono<Void> notifyClients(String method, Object params);
/**
* 立即关闭所有已连接客户端的传输并释放所有关联资源
*/
default void close() {
this.closeGracefully().subscribe();
}
/**
* 优雅地关闭所有已连接客户端的传输并异步释放所有关联资源
*
* @return Mono,当关闭成功时完成
*/
Mono<Void> closeGracefully();
}
Java
@WebServlet(asyncSupported = true)
public class HttpServletSseServerTransportProvider extends HttpServlet implements McpServerTransportProvider {
private static final Logger logger = LoggerFactory.getLogger(HttpServletSseServerTransportProvider.class);
public static final String UTF_8 = "UTF-8";
public static final String APPLICATION_JSON = "application/json";
public static final String FAILED_TO_SEND_ERROR_RESPONSE = "Failed to send error response: {}";
// 默认的 SSE 连接端点
public static final String DEFAULT_SSE_ENDPOINT = "/sse";
// 消息事件类型
public static final String MESSAGE_EVENT_TYPE = "message";
// 端点事件类型
public static final String ENDPOINT_EVENT_TYPE = "endpoint";
public static final String DEFAULT_BASE_URL = "";
// 对象映射器
private final ObjectMapper objectMapper;
// 服务端传输基本 url
private final String baseUrl;
// 消息端点,用于处理服务端发送的消息
private final String messageEndpoint;
// SSE 端点,用于处理 SSE 连接
private final String sseEndpoint;
// 活跃会话 map,key 为会话 id
private final Map<String, McpServerSession> sessions = new ConcurrentHashMap<>();
// 标记传输是否正在关闭
private final AtomicBoolean isClosing = new AtomicBoolean(false);
// 会话工厂,用于创建新的会话
private McpServerSession.Factory sessionFactory;
/**
* 构造方法,使用默认的 baseUrl
*/
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint,
String sseEndpoint) {
this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint);
}
/**
* 构造方法
*
* @param objectMapper 对象映射器
* @param baseUrl 服务端基本 url
* @param messageEndpoint 消息端点
* @param sseEndpoint SSE 端点
*/
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
String sseEndpoint) {
this.objectMapper = objectMapper;
this.baseUrl = baseUrl;
this.messageEndpoint = messageEndpoint;
this.sseEndpoint = sseEndpoint;
}
/**
* 设置工厂对象,用于为新客户端创建会话的工厂对象
*
* @param sessionFactory 会话工厂
*/
@Override
public void setSessionFactory(McpServerSession.Factory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* 向所有已连接的客户端发送通知
*
* @param method 通知方法名
* @param params 通知方法对应的参数
* @return Mono,通知后完成
*/
@Override
public Mono<Void> notifyClients(String method, Object params) {
if (sessions.isEmpty()) {
// 无连接中的会话,直接返回
logger.debug("No active sessions to broadcast message to");
return Mono.empty();
}
logger.debug("Attempting to broadcast message to {} active sessions", sessions.size());
return Flux.fromIterable(sessions.values())
// 调用会话对象的方法来发送通知
.flatMap(session -> session.sendNotification(method, params)
.doOnError(
e -> logger.error("Failed to send message to session {}: {}", session.getId(), e.getMessage()))
.onErrorComplete())
.then();
}
/**
* 处理 GET 请求来建立 SSE 连接
* @param request HTTP Servlet 请求
* @param response HTTP Servlet 响应
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取 uri
String requestURI = request.getRequestURI();
if (!requestURI.endsWith(sseEndpoint)) {
// 只允许 SSE 端点连接请求
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (isClosing.get()) {
// 连接正在被关闭时拒绝新的请求
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Server is shutting down");
return;
}
// 设置 SSE 响应头
response.setContentType("text/event-stream");
response.setCharacterEncoding(UTF_8);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
response.setHeader("Access-Control-Allow-Origin", "*");
// 生成唯一 sessionId
String sessionId = UUID.randomUUID().toString();
// 开启异步上下文
AsyncContext asyncContext = request.startAsync();
// 设置连接永不过期,即 SSE 连接可长时间保持
asyncContext.setTimeout(0);
PrintWriter writer = response.getWriter();
// 将 sessionId、异步上下文、响应输出流封装进传输层对象
HttpServletMcpSessionTransport sessionTransport = new HttpServletMcpSessionTransport(sessionId, asyncContext,
writer);
// 使用会话工厂创建一个新的 session 并注册进 sessions
McpServerSession session = sessionFactory.create(sessionTransport);
this.sessions.put(sessionId, session);
// 向客户端发送 endpoint 事件,内容包含 baseUrl、消息端点、sessionId 组成的消息端点 url
this.sendEvent(writer, ENDPOINT_EVENT_TYPE, this.baseUrl + this.messageEndpoint + "?sessionId=" + sessionId);
}
/**
* 处理客户端的 POST 请求消息
*
* @param request HTTP Servlet 请求
* @param response HTTP Servlet 响应
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (isClosing.get()) {
// 连接正在被关闭时拒绝新的请求
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Server is shutting down");
return;
}
// 获取 uri
String requestURI = request.getRequestURI();
if (!requestURI.endsWith(messageEndpoint)) {
// 只允许消息端点请求
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 从请求参数中获取 sessionId
String sessionId = request.getParameter("sessionId");
if (sessionId == null) {
// 如果 sessionId 为空,返回异常信息
response.setContentType(APPLICATION_JSON);
response.setCharacterEncoding(UTF_8);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
String jsonError = objectMapper.writeValueAsString(new McpError("Session ID missing in message endpoint"));
PrintWriter writer = response.getWriter();
writer.write(jsonError);
writer.flush();
return;
}
// 从 sessions 集合中获取当前 session
McpServerSession session = sessions.get(sessionId);
if (session == null) {
// 如果不包含当前 sessionId 对应的 session,返回异常信息
response.setContentType(APPLICATION_JSON);
response.setCharacterEncoding(UTF_8);
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
String jsonError = objectMapper.writeValueAsString(new McpError("Session not found: " + sessionId));
PrintWriter writer = response.getWriter();
writer.write(jsonError);
writer.flush();
return;
}
try {
// 读取请求体内容,拼接为字符串
BufferedReader reader = request.getReader();
StringBuilder body = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
body.append(line);
}
// 将拼接后的内容反序列化为 JSON-RPC 消息对象
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body.toString());
// 使用 session 执行当前消息,并阻塞直到执行完成
session.handle(message).block();
// 设置响应码 200,表示请求成功
response.setStatus(HttpServletResponse.SC_OK);
}
catch (Exception e) {
logger.error("Error processing message: {}", e.getMessage());
try {
McpError mcpError = new McpError(e.getMessage());
response.setContentType(APPLICATION_JSON);
response.setCharacterEncoding(UTF_8);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
String jsonError = objectMapper.writeValueAsString(mcpError);
PrintWriter writer = response.getWriter();
writer.write(jsonError);
writer.flush();
}
catch (IOException ex) {
logger.error(FAILED_TO_SEND_ERROR_RESPONSE, ex.getMessage());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error processing message");
}
}
}
/**
* 优雅地关闭所有已连接客户端的传输并异步释放所有关联资源
*
* @return Mono,当关闭成功时完成
*/
@Override
public Mono<Void> closeGracefully() {
// 设置关闭传输标志
isClosing.set(true);
logger.debug("Initiating graceful shutdown with {} active sessions", sessions.size());
// 调用会话层对象关闭传输
return Flux.fromIterable(sessions.values()).flatMap(McpServerSession::closeGracefully).then();
}
/**
* 向客户端发送 SSE 事件
*
* @param writer 发送事件的 writer
* @param eventType 事件类型(消息或端点)
* @param data 事件数据
*/
private void sendEvent(PrintWriter writer, String eventType, String data) throws IOException {
writer.write("event: " + eventType + "\n");
writer.write("data: " + data + "\n\n");
writer.flush();
if (writer.checkError()) {
throw new IOException("Client disconnected");
}
}
/**
* 在 servlet 被销毁时清理资源
*/
@Override
public void destroy() {
closeGracefully().block();
super.destroy();
}
}
3.2.4 会话层
MCP 服务端会话层涉及到的类包括 McpSession 、McpServerSession 、McpServerSession.Factory(内部类),如下图所示:

会话层负责与单个客户端建立独立会话、管理请求/通知的收发、并维护连接状态,它将服务端与底层传输通道解耦,使上层逻辑无需关心具体通信细节。其通过 McpSession 接口定义统一操作规范,并在 McpServerSession 提供了具体实现。其核心方法包括:
sendRequest():向服务端发送请求消息并等待响应,返回Mono表示支持异步处理。sendNotification():向服务端发送无响应的通知消息,返回Mono表示支持异步处理。close():立即关闭客户端连接和会话资源。closeGracefully():执行优雅关闭操作,确保未完成的请求正常结束,返回Mono表示支持异步处理。
此外,可以看到这里存在工厂接口 McpServerSession.Factory,这个工厂通常由上层(会话管理层)来调用,当一个新的客户端建立连接时,就会调用 create() 方法来生成会话实例。
核心的源码及注释如下所示:
Java
/**
* MCP 会话,用户处理客户端与服务端之间的通信
* 提供了消息交互和会话生命周期管理的方法
*/
public interface McpSession {
/**
* 向服务端发送请求并返回响应结果
*
* @param method 调用的方法名
* @param requestParams 请求参数
* @param typeRef 反序列化响应结果所需的类型
* @return Mono,服务端响应后完成
*/
<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef);
/**
* 向服务端发送不带参数的通知
*
* @param method 方法名
* @return Mono,通知发送后完成
*/
default Mono<Void> sendNotification(String method) {
return sendNotification(method, null);
}
/**
* 向服务端发送带参数的通知
*
* @param method 通知方法名
* @param params 方法参数
* @return Mono,通知发送后完成
*/
Mono<Void> sendNotification(String method, Object params);
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
Mono<Void> closeGracefully();
/**
* 立刻关闭客户端连接
*/
void close();
}
Java
/**
* MCP 服务端会话实现类,管理与客户端的双向 JSON-RPC 通信
*/
public class McpServerSession implements McpSession {
private static final Logger logger = LoggerFactory.getLogger(McpServerSession.class);
// 请求缓存,用于缓存还未处理完的请求
private final ConcurrentHashMap<Object, MonoSink<McpSchema.JSONRPCResponse>> pendingResponses = new ConcurrentHashMap<>();
// 会话 id
private final String id;
/** Duration to wait for request responses before timing out */
// 请求超时时间
private final Duration requestTimeout;
// 用于生成唯一请求 id 的原子计数器
private final AtomicLong requestCounter = new AtomicLong(0);
// 初始化处理器
private final InitRequestHandler initRequestHandler;
// 初始化通知处理器
private final InitNotificationHandler initNotificationHandler;
// 请求处理器 map
private final Map<String, RequestHandler<?>> requestHandlers;
// 通知处理器 map
private final Map<String, NotificationHandler> notificationHandlers;
// 传输层对象
private final McpServerTransport transport;
private final Sinks.One<McpAsyncServerExchange> exchangeSink = Sinks.one();
// 客户端能力配置
private final AtomicReference<McpSchema.ClientCapabilities> clientCapabilities = new AtomicReference<>();
// 客户端基本信息
private final AtomicReference<McpSchema.Implementation> clientInfo = new AtomicReference<>();
private static final int STATE_UNINITIALIZED = 0;
private static final int STATE_INITIALIZING = 1;
private static final int STATE_INITIALIZED = 2;
// 初始化状态
private final AtomicInteger state = new AtomicInteger(STATE_UNINITIALIZED);
/**
* 构造方法
*
* @param id 会话 id
* @param requestTimeout 请求超时时间
* @param transport 传输层对象
* @param initHandler 初始化处理器
* @param initNotificationHandler 初始化通知处理器
* @param requestHandlers 请求处理器
* @param notificationHandlers 通知处理器
*/
public McpServerSession(String id, Duration requestTimeout, McpServerTransport transport,
InitRequestHandler initHandler, InitNotificationHandler initNotificationHandler,
Map<String, RequestHandler<?>> requestHandlers, Map<String, NotificationHandler> notificationHandlers) {
this.id = id;
this.requestTimeout = requestTimeout;
this.transport = transport;
this.initRequestHandler = initHandler;
this.initNotificationHandler = initNotificationHandler;
this.requestHandlers = requestHandlers;
this.notificationHandlers = notificationHandlers;
}
public String getId() {
return this.id;
}
/**
* 在客户端和服务端完成初始化后调用
*
* @param clientCapabilities 客户端能力配置
* @param clientInfo 客户端基本信息
*/
public void init(McpSchema.ClientCapabilities clientCapabilities, McpSchema.Implementation clientInfo) {
this.clientCapabilities.lazySet(clientCapabilities);
this.clientInfo.lazySet(clientInfo);
}
/**
* 创建唯一的请求 id
*/
private String generateRequestId() {
return this.id + "-" + this.requestCounter.getAndIncrement();
}
/**
* 向客户端发送消息
*
* @param method 方法名
* @param requestParams 方法参数
* @param typeRef 响应类型
* @return Mono,发送后完成
*/
@Override
public <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) {
// 生成请求 id
String requestId = this.generateRequestId();
return Mono.<McpSchema.JSONRPCResponse>create(sink -> {
// 缓存当前请求
this.pendingResponses.put(requestId, sink);
// 构建 JSON-RPC 请求对象
McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, method,
requestId, requestParams);
// 发送请求
this.transport.sendMessage(jsonrpcRequest).subscribe(v -> {
}, error -> {
this.pendingResponses.remove(requestId);
sink.error(error);
});
}).timeout(requestTimeout).handle((jsonRpcResponse, sink) -> {
// 处理响应逻辑
if (jsonRpcResponse.error() != null) {
// 出现异常
sink.error(new McpError(jsonRpcResponse.error()));
}
else {
if (typeRef.getType().equals(Void.class)) {
// 返回结果类型为空时直接结束
sink.complete();
}
else {
// 返回结果类型不为空时将结果转换为 typeRef 类型对象并返回
sink.next(this.transport.unmarshalFrom(jsonRpcResponse.result(), typeRef));
}
}
});
}
/**
* 向服务端发送带参数的通知
*
* @param method 通知方法名
* @param params 方法参数
* @return Mono,通知发送后完成
*/
@Override
public Mono<Void> sendNotification(String method, Object params) {
// 将方法和参数转换为 JSON-RPC 通知对象
McpSchema.JSONRPCNotification jsonrpcNotification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
method, params);
// 使用传输层对象发送消息
return this.transport.sendMessage(jsonrpcNotification);
}
/**
* 将消息分发到合适的处理程序
*
* @param message JSON-RPC 消息
* @return Mono,消息处理后完成
*/
public Mono<Void> handle(McpSchema.JSONRPCMessage message) {
return Mono.defer(() -> {
if (message instanceof McpSchema.JSONRPCResponse response) {
// 处理响应类型的消息
logger.debug("Received Response: {}", response);
// 获取响应回调并从缓存中移除当前请求,表示当前请求处理完毕
var sink = pendingResponses.remove(response.id());
if (sink == null) {
logger.warn("Unexpected response for unknown id {}", response.id());
}
else {
// 将响应传递给订阅者
sink.success(response);
}
return Mono.empty();
}
else if (message instanceof McpSchema.JSONRPCRequest request) {
// 处理请求类型的消息
logger.debug("Received request: {}", request);
return handleIncomingRequest(request).onErrorResume(error -> {
// 处理失败时返回异常类型响应
var errorResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), null,
new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR,
error.getMessage(), null));
return this.transport.sendMessage(errorResponse).then(Mono.empty());
}).flatMap(this.transport::sendMessage);
}
else if (message instanceof McpSchema.JSONRPCNotification notification) {
// 处理通知类型的消息
logger.debug("Received notification: {}", notification);
return handleIncomingNotification(notification)
.doOnError(error -> logger.error("Error handling notification: {}", error.getMessage()));
}
else {
logger.warn("Received unknown message type: {}", message);
return Mono.empty();
}
});
}
/**
* 将 JSON-RPC 通知类型消息路由到相应的处理程序来处理
*
* @param notification JSON-RPC 通知
* @return Mono,通知处理后完成
*/
private Mono<Void> handleIncomingNotification(McpSchema.JSONRPCNotification notification) {
return Mono.defer(() -> {
if (McpSchema.METHOD_NOTIFICATION_INITIALIZED.equals(notification.method())) {
// 初始化完成通知方法执行逻辑
// 状态设置为初始化完成
this.state.lazySet(STATE_INITIALIZED);
exchangeSink.tryEmitValue(new McpAsyncServerExchange(this, clientCapabilities.get(), clientInfo.get()));
return this.initNotificationHandler.handle();
}
// 根据方法名获取处理器
var handler = notificationHandlers.get(notification.method());
if (handler == null) {
// 处理器不存在时返回空信息
logger.error("No handler registered for notification method: {}", notification.method());
return Mono.empty();
}
return this.exchangeSink.asMono().flatMap(exchange -> handler.handle(exchange, notification.params()));
});
}
/**
* 表示方法未找到的错误数据结构
*
* @param method 方法名
* @param message 异常信息
* @param data 附加数据
*/
record MethodNotFoundError(String method, String message, Object data) {
}
/**
* 根据方法名返回对应的 MethodNotFoundError 对象
*
* @param method 方法名
* @return MethodNotFoundError 对象
*/
private MethodNotFoundError getMethodNotFoundError(String method) {
return new MethodNotFoundError(method, "Method not found: " + method, null);
}
/**
* 优雅关闭客户端连接
*
* @return Mono,关闭后完成
*/
@Override
public Mono<Void> closeGracefully() {
return this.transport.closeGracefully();
}
/**
* 立刻关闭客户端连接
*/
@Override
public void close() {
this.transport.close();
}
}
3.2.5 传输层
MCP 服务端传输层涉及到的类包括:McpTransport 、McpServerTransport 、HttpServletSseServerTransportProvider.HttpServletMcpSessionTransport (内部类)、StdioServerTransportProvider.StdioMcpSessionTransport (内部类) 等。其中 HttpServletMcpSessionTransport 和 StdioMcpSessionTransport 为 McpServerTransport 的实现类,分别对应 SSE 和 Stdio 的具体实现,这里仅列出两种,实际上不同的传输协议都会有对应的实现类。其类图如下所示:

核心接口是 McpTransport 和其子接口 McpServerTransport,其中 McpServerTransport 内部为空,即服务端的传输层类还没有扩展其他的功能。McpTransport 中核心方法的功能已在 MCP 客户端传输层给出,这里不再赘述。
核心的源码及注释如下所示(McpTransport 在 MCP 客户端传输层已给出,这里也不再赘述。实现类中仅给出 HttpServletMcpSessionTransport 的具体实现,其他的实现类是类似的):
Java
/**
* HttpServlet SSE 会话的 McpServerTransport 实现类,处理特定客户端会话的传输层通信
*/
private class HttpServletMcpSessionTransport implements McpServerTransport {
// 会话 id
private final String sessionId;
// 异步上下文
private final AsyncContext asyncContext;
// 写入器,用于向客户端发送消息
private final PrintWriter writer;
/**
* 构造方法
*
* @param sessionId 会话 id
* @param asyncContext 异步会话上下文
* @param writer 用于向客户端发送服务端消息的写入器
*/
HttpServletMcpSessionTransport(String sessionId, AsyncContext asyncContext, PrintWriter writer) {
this.sessionId = sessionId;
this.asyncContext = asyncContext;
this.writer = writer;
logger.debug("Session transport {} initialized with SSE writer", sessionId);
}
/**
* 通过 SSE 连接向客户端发送 JSON-RPC 消息
*
* @param message JSON-RPC 消息
* @return Mono,在消息发送完成后返回结果
*/
@Override
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
return Mono.fromRunnable(() -> {
try {
// 将消息序列化为字符串
String jsonText = objectMapper.writeValueAsString(message);
// 发送消息
sendEvent(writer, MESSAGE_EVENT_TYPE, jsonText);
logger.debug("Message sent to session {}", sessionId);
}
catch (Exception e) {
logger.error("Failed to send message to session {}: {}", sessionId, e.getMessage());
sessions.remove(sessionId);
asyncContext.complete();
}
});
}
/**
* 通过已配置的 ObjectMapper 将数据从一种类型转换为另一种类型
*
* @param data 源数据
* @param typeRef 目标类型
* @return 转换后的对象
*/
@Override
public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
return objectMapper.convertValue(data, typeRef);
}
/**
* 优雅地关闭当前传输
*
* @return Mono,关闭传输后返回结果
*/
@Override
public Mono<Void> closeGracefully() {
return Mono.fromRunnable(() -> {
logger.debug("Closing session transport: {}", sessionId);
try {
// 从已注册的 sessions 集合中移除当前 session
sessions.remove(sessionId);
// 结束异步长下文
asyncContext.complete();
logger.debug("Successfully completed async context for session {}", sessionId);
}
catch (Exception e) {
logger.warn("Failed to complete async context for session {}: {}", sessionId, e.getMessage());
}
});
}
/**
* 立刻关闭当前传输
*/
@Override
public void close() {
try {
// 从已注册的 sessions 集合中移除当前 session
sessions.remove(sessionId);
// 结束异步长下文
asyncContext.complete();
logger.debug("Successfully completed async context for session {}", sessionId);
}
catch (Exception e) {
logger.warn("Failed to complete async context for session {}: {}", sessionId, e.getMessage());
}
}
}