Skip to content

Conversation

@nkaushal99
Copy link

@nkaushal99 nkaushal99 commented Aug 7, 2025

closes #1248

Motivation and Context

This change introduces support for injecting a default progress_handler into ClientSession. It solves the issue where downstream libraries (e.g., LangChain's MCP adapter) access the raw client.session and make tool calls that bypass the top-level fastmcp.Client’s progress_handler, leading to missing progress reports. With this enhancement, consistent progress reporting is ensured whether tools are called through the high-level client or the lower-level session.

How Has This Been Tested?

This feature has been tested within an async environment using:

  • Direct calls to ClientSession.call_tool(...) to ensure the default handler is triggered.
  • Calls with explicitly provided progress_callback to ensure override behavior works correctly.
  • Integration with langchain_mcp_adapters to confirm downstream compatibility and improved reporting.

Breaking Changes

No breaking changes. This enhancement is backward-compatible. Existing users who do not pass a progress_handler will see no change in behavior. Users who want consistent progress reporting can optionally provide a handler to ClientSession.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

This feature enables clean integration with ecosystem libraries like LangChain without requiring redundant progress callback plumbing at every call site.

@nkaushal99 nkaushal99 requested review from a team and dsp-ant August 7, 2025 23:46
@nkaushal99
Copy link
Author

link to issue #1248

Copy link
Contributor

@felixweinberger felixweinberger left a comment

Choose a reason for hiding this comment

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

I don't think we want to change internal implementation details of the SDK here in response to what other downstream tools like LangChain might or might not do unless this is a very common use case.

Also if I follow here, you're attempting to set a progress callback on the session as a whole - however, progress callbacks are internally associated with request_id in BaseSession as different requests might require different progress handling within the same session:

_in_flight: dict[RequestId, RequestResponder[ReceiveRequestT, SendResultT]]
_progress_callbacks: dict[RequestId, ProgressFnT]

fastmcp seems to allow setting a default progress_handler for a Client as a whole, but that's not necessarily supported in this lower level API. Internally fastmcp also explicitly passes the progress_handler as we do here: https://github.com/jlowin/fastmcp/blob/7770e3a6bc838a1b3c04c6e543b5b804f8868c93/src/fastmcp/client/client.py#L822

The correct solution here seems to be to leverage the arguments arg allowed in lang_chain, not to modify the SDK here.

read_timeout_seconds=read_timeout_seconds,
)
self._client_info = client_info or DEFAULT_CLIENT_INFO
self._progress_callback = progress_callback
Copy link
Contributor

Choose a reason for hiding this comment

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

should this have a _default_progress_callback?

types.CallToolResult,
request_read_timeout_seconds=read_timeout_seconds,
progress_callback=progress_callback,
progress_callback=progress_callback or self._progress_callback,
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like it's just inviting hard to debug behavior where we make a call_tool call without any progress_callback yet there still somehow ends up being one via some separate state object.

@felixweinberger
Copy link
Contributor

Hi @nkaushal99 thank you for this contribution!

I'm closing this PR based on the reasoning provided above for now - please feel free to ping here again though if you disagree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Request for a new feature that's not currently supported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: support progress_callback propagation in ClientSession

2 participants