From 2c698cbddcd1e50e9cb9a0c52aa1ee20bd9e567b Mon Sep 17 00:00:00 2001 From: Daniel Garnier-Moiroux Date: Thu, 22 Oct 2026 16:11:50 +0200 Subject: [PATCH] Fix race condition in tools list filter - McpSyncListFilteringIntegrationTests#multipleFilters would flake sometimes in CI. This is a symptom of a race condition when multiple tool-list filters run in a .all() and one filter cancels the whole operation. Signed-off-by: Daniel Garnier-Moiroux --- .../io/modelcontextprotocol/server/McpAsyncListFilter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncListFilter.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncListFilter.java index d6b1858bf..6a72a97f7 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncListFilter.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncListFilter.java @@ -52,7 +52,10 @@ public interface McpAsyncListFilter { static McpAsyncListFilter fromSync(McpSyncListFilter filter, boolean immediateExecution) { Assert.notNull(filter, "filter must not be null"); return (transportContext, primitive) -> { - var visible = Mono.fromCallable(() -> filter.isVisible(transportContext, primitive)); + // Not fromCallable: subscribeOn would fuse it into MonoSubscribeOnCallable, + // which can interrupt the worker thread after a downstream all() cancelled it + // from that thread, e.g. while that thread writes the HTTP response + var visible = Mono.defer(() -> Mono.just(filter.isVisible(transportContext, primitive))); return immediateExecution ? visible : visible.subscribeOn(Schedulers.boundedElastic()); }; }