Skip to content

Adopt streamable_http_client API from MCP SDK#2620

Merged
jlowin merged 4 commits intomainfrom
adopt-streamable-http-client-api
Dec 15, 2025
Merged

Adopt streamable_http_client API from MCP SDK#2620
jlowin merged 4 commits intomainfrom
adopt-streamable-http-client-api

Conversation

@jlowin
Copy link
Copy Markdown
Member

@jlowin jlowin commented Dec 15, 2025

Adopts the new streamable_http_client API from the MCP Python SDK while maintaining backward compatibility.

Changes

  • Updated import: Switched from deprecated streamablehttp_client to streamable_http_client
  • Factory to client conversion: Converts httpx_client_factory to httpx.AsyncClient instances before passing to the new API
  • Backward compatibility: Continues accepting factories (needed for OAuth) but converts them at the SDK boundary
  • Deprecation warning: Added warning for sse_read_timeout parameter which is no longer supported by the new API

Implementation Details

The new API accepts httpx.AsyncClient directly instead of factories. FastMCP maintains its factory-based API for OAuth compatibility, creating clients from factories only when calling the MCP SDK:

# FastMCP still accepts factories
transport = StreamableHttpTransport(
    url="https://api.example.com/mcp",
    httpx_client_factory=lambda **kwargs: httpx.AsyncClient(verify=False, **kwargs)
)

# Internally converts to client for new API
http_client = self.httpx_client_factory(**httpx_client_kwargs)
async with streamable_http_client(self.url, http_client=http_client) as transport:
    ...

Closes #2594

- Update import to use new streamable_http_client function
- Convert httpx_client_factory to httpx.AsyncClient before passing to new API
- Maintain backward compatibility by continuing to accept factories
- Add deprecation warning for sse_read_timeout parameter

The new API accepts httpx.AsyncClient directly instead of factories.
We continue accepting factories for OAuth compatibility, converting
them to clients at the boundary with the MCP SDK.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 15, 2025

Warning

Rate limit exceeded

@jlowin has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 38 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between aac639b and 0ec61ae.

📒 Files selected for processing (1)
  • src/fastmcp/client/transports.py (3 hunks)

Walkthrough

The changes update HTTP client configuration in the transport layer. The import statement corrects the module name to streamable_http_client. The code now constructs an httpx.AsyncClient either through a provided factory or with default configuration, then passes it directly to streamable_http_client. A deprecation warning was added for the sse_read_timeout parameter. The read_timeout_seconds parameter is converted to httpx timeout format, and headers and authentication configuration are consolidated into a dedicated structure.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Adopt streamable_http_client API from MCP SDK' clearly summarizes the main change of updating to the new SDK API.
Description check ✅ Passed The PR description covers the main changes, implementation details, backward compatibility approach, and includes closure of linked issue #2594.
Linked Issues check ✅ Passed The PR changes fully implement the objectives from #2594: imports are corrected, httpx_client_factory is converted to httpx.AsyncClient, backward compatibility is maintained, and deprecation warning is added.
Out of Scope Changes check ✅ Passed All changes in src/fastmcp/client/transports.py are directly aligned with adopting the new streamable_http_client API and maintaining backward compatibility as specified in issue #2594.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@marvin-context-protocol marvin-context-protocol Bot added enhancement Improvement to existing functionality. For issues and smaller PR improvements. client Related to the FastMCP client SDK or client-side functionality. http Related to HTTP transport, networking, or web server functionality. labels Dec 15, 2025
Convert read_timeout_seconds from timedelta to float before passing
to httpx, matching the pattern used in the SSE transport.
@marvin-context-protocol
Copy link
Copy Markdown
Contributor

Test Failure Analysis

Summary: Two timeout-related tests are failing because the is passing a object directly to httpx's timeout parameter, which expects a float (seconds).

Root Cause: In , the code passes read_timeout_seconds directly from session_kwargs to httpx without converting it from a datetime.timedelta to a float. The SSETransport handles this correctly at line 215 by calling .total_seconds(), but this conversion was missed in the StreamableHttpTransport when adopting the new API.

Suggested Solution: Convert the timedelta to seconds before passing to httpx, following the same pattern as the SSE transport:

# In src/fastmcp/client/transports.py around line 294-295
if session_kwargs.get("read_timeout_seconds") is not None:
    read_timeout_seconds = cast(
        datetime.timedelta, session_kwargs.get("read_timeout_seconds")
    )
    httpx_client_kwargs["timeout"] = read_timeout_seconds.total_seconds()
Detailed Analysis

Failing Tests

  • tests/client/test_streamable_http.py::TestTimeout::test_timeout
  • tests/client/test_streamable_http.py::TestTimeout::test_timeout_tool_call_overrides_client_timeout

Error Traceback

TypeError: unsupported operand type(s) for +: 'float' and 'datetime.timedelta'

This error occurs in httpx/httpcore when it tries to calculate a deadline by adding the timeout value to the current time. The httpx library expects timeout values as floats (seconds), but receives a timedelta object instead.

Code Comparison

SSE Transport (correct) - src/fastmcp/client/transports.py:211-215:

if session_kwargs.get("read_timeout_seconds") is not None:
    read_timeout_seconds = cast(
        datetime.timedelta, session_kwargs.get("read_timeout_seconds")
    )
    client_kwargs["timeout"] = read_timeout_seconds.total_seconds()

StreamableHttp Transport (incorrect) - src/fastmcp/client/transports.py:294-295:

if session_kwargs.get("read_timeout_seconds") is not None:
    httpx_client_kwargs["timeout"] = session_kwargs.get("read_timeout_seconds")
Related Files
  • src/fastmcp/client/transports.py:294-295 - Where the fix needs to be applied
  • src/fastmcp/client/transports.py:211-215 - Reference implementation in SSE transport
  • tests/client/test_streamable_http.py:238-263 - Failing timeout tests

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/fastmcp/client/transports.py (2)

255-267: Dead code: self.sse_read_timeout is stored but never used.

After the deprecation warning, lines 265-267 still process and store sse_read_timeout in self.sse_read_timeout, but this value is never referenced in connect_session. Since the new API doesn't support this parameter, consider removing the dead code.

         if sse_read_timeout is not None:
             if fastmcp.settings.deprecation_warnings:
                 warnings.warn(
                     "The `sse_read_timeout` parameter is deprecated and no longer used. "
                     "The new streamable_http_client API does not support this parameter. "
                     "Use `read_timeout_seconds` in session_kwargs or configure timeout on "
                     "the httpx client via `httpx_client_factory` instead.",
                     DeprecationWarning,
                     stacklevel=2,
                 )
-        if isinstance(sse_read_timeout, int | float):
-            sse_read_timeout = datetime.timedelta(seconds=float(sse_read_timeout))
-        self.sse_read_timeout = sse_read_timeout

301-302: Document the httpx_client_factory calling convention requirement.

The factory is called both with no arguments (line 232 in oauth.py) and with kwargs (headers, auth, timeout) at line 302. Custom factories must support both patterns. Add a docstring or type hint on the httpx_client_factory parameter explaining that factories should handle being called with optional kwargs, or accept **kwargs to forward unused parameters.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 577f4d1 and aac639b.

📒 Files selected for processing (1)
  • src/fastmcp/client/transports.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Write Python code with Python ≥3.10 and include full type annotations
Use specific exception types in error handling - never use bare except
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns even if they're shorter

Files:

  • src/fastmcp/client/transports.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: jlowin
Repo: jlowin/fastmcp PR: 0
File: :0-0
Timestamp: 2025-12-01T15:48:05.095Z
Learning: PR #2505 in fastmcp adds NEW functionality to get_access_token(): it now first checks request.scope["user"] for the token (which never existed before), then falls back to _sdk_get_access_token() (the only thing the original code did). This is not a reversal of order but entirely new functionality to fix stale token issues.
📚 Learning: 2025-12-13T19:58:20.851Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-13T19:58:20.851Z
Learning: Applies to tests/**/*.py : Pass FastMCP servers directly to clients using in-memory transport for testing; only use HTTP transport when explicitly testing network features

Applied to files:

  • src/fastmcp/client/transports.py
🧬 Code graph analysis (1)
src/fastmcp/client/transports.py (2)
src/fastmcp/server/server.py (1)
  • settings (357-365)
src/fastmcp/server/dependencies.py (1)
  • get_http_headers (523-566)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run tests: Python 3.10 on windows-latest
  • GitHub Check: Run tests: Python 3.13 on ubuntu-latest
  • GitHub Check: Run tests: Python 3.10 on ubuntu-latest
  • GitHub Check: Run tests with lowest-direct dependencies
🔇 Additional comments (2)
src/fastmcp/client/transports.py (2)

26-26: LGTM!

Import correctly updated to use the new streamable_http_client API from the MCP SDK.


287-298: LGTM!

Clean construction of httpx client configuration with proper timedelta-to-seconds conversion for the timeout parameter.

Comment thread src/fastmcp/client/transports.py Outdated
@jlowin jlowin merged commit 076ec0c into main Dec 15, 2025
11 checks passed
@jlowin jlowin deleted the adopt-streamable-http-client-api branch December 15, 2025 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client Related to the FastMCP client SDK or client-side functionality. enhancement Improvement to existing functionality. For issues and smaller PR improvements. http Related to HTTP transport, networking, or web server functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to streamable_http_client API from MCP SDK

1 participant