feat(mcp): Implement basic support for Tasks#1475
feat(mcp): Implement basic support for Tasks#1475LucaButBoring wants to merge 9 commits intostrands-agents:mainfrom
Conversation
14da5f4 to
0411e91
Compare
0411e91 to
17d0842
Compare
17d0842 to
a26b769
Compare
a26b769 to
4d1b95c
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
4d1b95c to
4d1af11
Compare
Implements client support for MCP Tasks via an adapter model that handles both tool execution modes identically. This can later be hooked into event handlers in a more intelligent way, but this unblocks support for simply invoking task-augmented tools. Keep error handling and edge case tests (timeout, failure status, config). Also remove unused create_tool_with_task_support helper and trim task_echo_server. Reduces PR diff from 1433 to 969 lines (under 1000 limit).
4d1af11 to
ac9577b
Compare
src/strands/tools/mcp/mcp_client.py
Outdated
| tool_filters: Optional filters to apply to tools. | ||
| prefix: Optional prefix for tool names. | ||
| elicitation_callback: Optional callback function to handle elicitation requests from the MCP server. | ||
| experimental: Configuration for experimental features. Currently supports: |
There was a problem hiding this comment.
Making a note that we may want to clarify what the Strands contract will be regarding experimental features since "experimental" is overloaded.
I think the contract is akin to
"""
Implementations within Strands are stable. It would be considered breaking if we, for example, changed the ExperimentalConfig without a corresponding change to the MCP specification.
But, when there are changes made to the MCP spec, and the official MCP sdk, it is not considered breaking for to synchronize.
"""
Tagging @mkmeral just for maintainer visibility here.
This is a product question really, where we may get better adoption if we are as stable as possible
There was a problem hiding this comment.
What's DevX here? Why do we have experimental here? Is this strands experimental or MCP experimental?
I agree on experimental being overloaded. I'd like a bit more explanation on this one tbh.
There was a problem hiding this comment.
Just a comment on this one, I'd rather not have the experimental field here that contains task config. Once MCP makes this stable, we'll need to move it around, and it'll impact customers, even if/when the task definition is stable (i.e. no changes from MCP)
Instead we should get rid of experimental field (move TaskConfig to top), and add warnings on TaskConfig (when taskconfig exists) saying something like "this is experimental feature from MCP spec. Along with the MCP spec changes, Strands Agents implementation of this feature might change."
There was a problem hiding this comment.
Is this strands experimental or MCP experimental?
Instead we should get rid of experimental field (move TaskConfig to top), and add warnings on TaskConfig (when taskconfig exists) saying something like "this is experimental feature from MCP spec. Along with the MCP spec changes, Strands Agents implementation of this feature might change."
I think this makes sense, I'll adjust this accordingly.
There was a problem hiding this comment.
Updated in the latest commit, and made the other fixes as well
src/strands/tools/mcp/mcp_client.py
Outdated
| """Convert a timedelta timeout to seconds for task polling. | ||
|
|
||
| When task-augmented execution is used, the read_timeout_seconds parameter | ||
| (which is a timedelta) needs to be converted to a float for the polling timeout. |
There was a problem hiding this comment.
this is an unfortunate typo...apologies from the team
There was a problem hiding this comment.
/strands create a follow up issue with a v2 label to update this naming
mkmeral
left a comment
There was a problem hiding this comment.
So I ran my review and API bar raising agent, couple of callouts
- Delete ExperimentalConfig
- Add missing
_get_tool_task_support()method or fix tests - Export
TasksConfigfromstrands.tools.mcp - Nit: Fix type inconsistency in unit tests
Full code review
Quality Checks
- ✅ Formatting and linting pass
- ✅ All 129 MCP unit tests pass
- ✅ 94.95% patch coverage
What's Good
- Clean opt-in design via
experimental.tasks - Excellent error handling (timeout, failed, cancelled states)
- Follows MCP spec correctly
- Backwards compatible
Issues Found
Critical: Missing _get_tool_task_support() method
# tests_integ/mcp/test_mcp_client_tasks.py:114-117
assert task_mcp_client._get_tool_task_support("task_required_echo") == "required"The implementation only has _tool_task_support_cache dict. Either add the method or fix the tests.
Type inconsistency in tests
TasksConfig expects timedelta but tests pass integers:
{"ttl": 120000} # Wrong
{"ttl": timedelta(milliseconds=120000)} # CorrectAPI bar raising review
Tenet Alignment
| Tenet | Status |
|---|---|
| Simple at any scale | |
| Extensible by design | ✅ |
| Composability | ✅ |
| Obvious path is happy path | {"tasks": {}} not intuitive |
| Accessible to humans/agents | |
| Embrace common standards | ✅ |
Decision Record Compliance
- Flat Namespaces — ❌ Violated. Types not exported.
- Low/High Level APIs —
⚠️ No simpleenable_tasks=Trueoption.
Confusing Semantics
experimental={} # tasks DISABLED
experimental={"tasks": {}} # tasks ENABLEDThis is subtle and error-prone.
Public API changes
New Types
class TasksConfig(TypedDict, total=False):
ttl: timedelta # Default: 1 minute
poll_timeout: timedelta # Default: 5 minutes
class ExperimentalConfig(TypedDict, total=False):
tasks: TasksConfigNew Constructor Parameter
MCPClient(transport, experimental: ExperimentalConfig | None = None)Usage
# Disabled (default)
client = MCPClient(transport)
# Enabled with defaults
client = MCPClient(transport, experimental={"tasks": {}})
# Custom config
client = MCPClient(transport, experimental={
"tasks": {"ttl": timedelta(minutes=2), "poll_timeout": timedelta(minutes=10)}
})…odule - Create mcp_tasks.py module with TasksConfig and task-related constants - Remove ExperimentalConfig wrapper class from mcp_client.py - Change MCPClient parameter from experimental to tasks (direct TasksConfig) - Export TasksConfig at module level in __init__.py - Update all unit and integration tests to use simplified API
Description
Implements client support for MCP Tasks via an adapter model that handles both tool execution modes identically. This can later be hooked into event handlers in a more intelligent way, but this unblocks support for simply invoking task-augmented tools.
Note that unlike strands-agents/sdk-typescript#357, this PR handles the capability/executionMode logic explicitly, as the MCP Python SDK's implementation of Tasks does not encapsulate that logic, unlike the MCP TS SDK.
Related Issues
#1260
Documentation PR
N/A
Type of Change
New feature
Testing
How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli
hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.