feat(mcp): per-tool options and progress update for MCPToolset#5694
Merged
Conversation
MCPToolset now extends AsyncToolset and gains an `async_mode=True` flag. When set, MCP tools are built with an `AsyncRunContext` parameter that forwards MCP progress notifications via `ctx.update`, so the agent can narrate progress while a slow MCP tool runs in the background instead of blocking the reply loop. `AsyncToolset` no longer stores `get_running_tasks` / `cancel_task` in `_tools`; they're exposed through a `tools` property override that subclasses can condition. `MCPToolset` overrides it to expose the helpers only when `async_mode=True`, so the legacy MCP UX is unchanged when the flag is off. `MCPServer.list_tools` now caches per `async_mode`, and the example MCP server gains a long-running `book_flight` tool that emits progress updates.
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
theomonnom
reviewed
May 13, 2026
theomonnom
left a comment
Member
There was a problem hiding this comment.
lgtm, let's have async_mode enabled by default?
maybe the arguments becomes something like nonblocking_tools: list[str]?
Public API on MCPToolset becomes `nonblocking_tools: bool | list[str]` defaulting to `True`, so MCP tools run non-blocking by default and callers can opt specific tools in or out by name. Empty list / `False` falls back to the legacy blocking behavior. MCPServer.list_tools routes the per-tool decision down to _make_function_tool, which still takes a bool, and caches the resolved bool|frozenset key.
Member
|
Let's wait for #5711 |
Re-implement MCP async support on the reworked AsyncToolset API: MCPToolset extends AsyncToolset, non-blocking MCP tools carry ToolFlag.CANCELLABLE and forward progress through ctx.update(), and get_running_tasks/cancel_task are auto-exposed by the activity when a cancellable tool is present rather than added by the toolset.
Each MCP tool is configured via MCPToolOptions(flags, on_duplicate, forward_progress) keyed by name through MCPToolset(tool_options=...); tools not listed there are plain blocking calls. flags/on_duplicate mirror @function_tool and forward_progress forwards report_progress to ctx.update(), decoupling the non-blocking, cancellable, and duplicate-handling concerns that the single nonblocking_tools flag conflated. MCPServer now caches only the raw tool descriptors and rebuilds tools per resolved options.
list_tools takes the tool_options mapping directly instead of a resolver callable — MCPToolset was the only caller and just forwarded dict.get. Also tighten the MCPToolOptions/MCPToolset docstrings and comments.
theomonnom
approved these changes
Jul 17, 2026
Rename forward_progress to report_progress and resolve per-tool options against a full default map instead of inline getattr defaults.
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.
Summary
MCPToolsetnow extendsAsyncToolset. Per-tool behavior is configured withMCPToolOptions, keyed by tool name viatool_options; any tool not listed there is a plain blocking call.MCPToolOptionskeeps the three concerns independent:flags: ToolFlag— e.g.CANCELLABLE,IGNORE_ON_ENTER(mirrors@function_tool).on_duplicate: DuplicateMode— duplicate-call policy (mirrors@function_tool).forward_progress: bool— forward the MCP server'sreport_progressnotifications toctx.update(), so the tool runs in the background and the agent can narrate progress.When any tool is
ToolFlag.CANCELLABLE,lk_agents_get_running_tasks/lk_agents_cancel_taskare auto-exposed to the LLM by the activity.Example
examples/voice_agents/mcp/server.pyships a fastget_weather(sync, no progress) and a long-runningbook_flightthat emitsctx.report_progressupdates over ~70s.mcp-agent.pyconfigures onlybook_flight(cancellable + forward progress) and bumpsclient_session_timeout_seconds=120since the per-request timeout otherwise fires before it returns.