Skip to content

feat(mcp): Implement basic support for Tasks#1475

Open
LucaButBoring wants to merge 9 commits intostrands-agents:mainfrom
LucaButBoring:feat/mcp-tasks
Open

feat(mcp): Implement basic support for Tasks#1475
LucaButBoring wants to merge 9 commits intostrands-agents:mainfrom
LucaButBoring:feat/mcp-tasks

Conversation

@LucaButBoring
Copy link

@LucaButBoring LucaButBoring commented Jan 13, 2026

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

  • I ran hatch run prepare
  • I spot-checked against an MCP server that supports Tasks

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link

codecov bot commented Jan 21, 2026

Codecov Report

❌ Patch coverage is 94.94949% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/strands/tools/mcp/mcp_client.py 94.94% 2 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

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).
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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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."

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this strands experimental or MCP experimental?

MCP experimental:

image

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in the latest commit, and made the other fixes as well

"""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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an unfortunate typo...apologies from the team

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/strands create a follow up issue with a v2 label to update this naming

@github-actions github-actions bot added size/l and removed size/l labels Feb 3, 2026
dbschmigelski
dbschmigelski previously approved these changes Feb 4, 2026
Copy link
Contributor

@mkmeral mkmeral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I ran my review and API bar raising agent, couple of callouts

  1. Delete ExperimentalConfig
  2. Add missing _get_tool_task_support() method or fix tests
  3. Export TasksConfig from strands.tools.mcp
  4. 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)}  # Correct
API bar raising review

Tenet Alignment

Tenet Status
Simple at any scale ⚠️ Empty dict semantics confusing
Extensible by design
Composability
Obvious path is happy path ⚠️ {"tasks": {}} not intuitive
Accessible to humans/agents ⚠️ Types not exported
Embrace common standards

Decision Record Compliance

  • Flat Namespaces — ❌ Violated. Types not exported.
  • Low/High Level APIs⚠️ No simple enable_tasks=True option.

Confusing Semantics

experimental={}              # tasks DISABLED
experimental={"tasks": {}}   # tasks ENABLED

This 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: TasksConfig

New 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
@github-actions github-actions bot added size/l and removed size/l labels Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants