Fix: honor abort signal during in-flight MCP tool calls - #2373
Open
kyungseopk1m wants to merge 1 commit into
Open
Fix: honor abort signal during in-flight MCP tool calls#2373kyungseopk1m wants to merge 1 commit into
kyungseopk1m wants to merge 1 commit into
Conversation
McpClient kept running a tool call to completion after the caller's AbortSignal fired, so cancelling mid-turn only took effect on the next LLM turn. Add abort checks at the top of the tool-call loop, right after the SDK call resolves, and in its catch block, so an abort during a tool call ends the turn immediately. Also fix client.callTool() to pass the signal through RequestOptions (the SDK's third argument), not the request params, where it was silently ignored by the transport.
Member
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
McpClient.processSingleTurnWithToolsaccepts anabortSignaland checks it in a few places, but the actual MCP tool call ignores it.client.callToolwas called withsignalon the request params object:The installed
@modelcontextprotocol/sdksignature iscallTool(params, resultSchema?, options?), wheresignallives on the third argument (RequestOptions). Putting it onparamsmeans it's never forwarded to the transport, so aborting mid-tool-call has no effect on the in-flight request. It keeps running, and cancellation only takes effect a turn later, once the result comes back and the post-call abort check fires.Fix
Pass the signal through
RequestOptionsinstead:Also added abort checks at the top of the tool-call loop and in the catch block (the existing check only ran right after the
callToolawait), so an abort landing between two tool calls in the same turn, or during a tool call that rejects for another reason, still ends the turn cleanly instead of continuing or surfacing as a normal tool-failure message.Tests
McpClient.abort.spec.tscovers: a pending tool call actually receiving the signal through the SDK (fails without the params/options fix), abort landing between two tool calls in one turn, a tool that resolves normally after the caller already aborted, and that a real non-abort tool error still surfaces normally. Checked each of the three abort-check locations individually by reverting it in isolation: each has a test that fails without it.pnpm vitest runinpackages/mcp-client: 22/22 passed.tscandeslintclean.One thing this doesn't touch: when a tool call is aborted mid-turn, the assistant message with its
tool_callsis already pushed tomessages, but the matchingtoolresponse never gets appended, leaving the message list with atool_callsentry that has no correspondingtoolmessage, which most providers reject on the next turn. Is there a preferred way to handle this, e.g. drop the dangling assistant message, or push a synthetic cancelledtoolmessage?Note
Low Risk
Localized change to MCP client tool execution and cancellation; no auth or data-path changes, with dedicated test coverage.
Overview
Fixes cancellation during MCP tool execution by passing
opts.abortSignalthrough the SDK’s thirdcallToolargument (RequestOptions) instead of on the params object, so in-flight tool requests can actually be aborted.Tightens abort handling in the tool loop: checks
abortSignalbefore each tool call, aftercallToolreturns, and in the catch path so aborts stop the turn cleanly (no fake tool-failure messages, no second tool in the same turn, no extra LLM turn).Adds
McpClient.abort.spec.tswith Vitest coverage for signal forwarding, mid-turn abort between tools, tools that ignore abort, and unchanged non-abort error paths.Reviewed by Cursor Bugbot for commit 29ffca3. Bugbot is set up for automated code reviews on this repo. Configure here.