From 825498c71c189ccd4b8e9b4415ae4fc05ba5215e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 00:51:12 +0000 Subject: [PATCH] fix(binding-mcp): settle a still-establishing toolkit client on reset/abort An mcp(client)-backed session's south connections toward each routed toolkit are established eagerly and in parallel; the north-facing session's own accept is deferred until every one of them settles (either by opening successfully or by being told to settle explicitly). McpLifecycleClient's onClientAbort/onClientReset only told the session to settle when hydration was in progress AND this client had never opened -- any other combination propagated the abort/reset to the session. That condition had no else branch, so exactly that one case did neither: a hydration session's still-establishing toolkit resetting or aborting left the session waiting on a settlement that would now never arrive, wedging the whole hydration attempt indefinitely. Both handlers now call settleLifecycle for that case instead of doing nothing, letting the session proceed without that toolkit; the existing per-kind retry/backoff already re-attempts it once the session is no longer blocked. A caller's own (non-hydration) session and an already-established toolkit's later failure keep propagating exactly as before. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01W7N8Z9vABdU8pVPGthRodY --- .../stream/McpProxyLifecycleFactory.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/runtime/binding-mcp/src/main/java/io/aklivity/zilla/runtime/binding/mcp/internal/stream/McpProxyLifecycleFactory.java b/runtime/binding-mcp/src/main/java/io/aklivity/zilla/runtime/binding/mcp/internal/stream/McpProxyLifecycleFactory.java index 16ed167581..6e3ca6ff05 100644 --- a/runtime/binding-mcp/src/main/java/io/aklivity/zilla/runtime/binding/mcp/internal/stream/McpProxyLifecycleFactory.java +++ b/runtime/binding-mcp/src/main/java/io/aklivity/zilla/runtime/binding/mcp/internal/stream/McpProxyLifecycleFactory.java @@ -1290,7 +1290,11 @@ private void onClientAbort( settleRequests(traceId); doClientAbort(traceId); server.clients.remove(routedId, this); - if (!(server.hydration && sessionId == null)) + if (server.hydration && sessionId == null) + { + settleLifecycle(traceId); + } + else { server.doServerAbort(traceId); } @@ -1338,16 +1342,13 @@ private void onClientReset( server.clients.remove(routedId, this); final boolean bearer = extension.sizeof() > 0; - if (!(server.hydration && sessionId == null)) + if (server.hydration && sessionId == null || bearer) { - if (bearer) - { - settleLifecycle(traceId); - } - else - { - server.doServerReset(traceId, extension); - } + settleLifecycle(traceId); + } + else + { + server.doServerReset(traceId, extension); } } }