SSE mode MCP tools always fail with TimeoutError — HTTP 400 misclassified as transient, blocking SSE fallback
Bug Description
When a Langflow flow uses a Custom MCP Tools component with Connection Type = SSE, the connection always fails with a ConnectionError / timeout even though the MCP server is running and reachable. The underlying cause is that lfx routes SSE-mode connections through MCPStreamableHttpClient, which tries the newer Streamable HTTP transport first. When the server correctly responds HTTP 400 (because it only understands the legacy SSE handshake), _is_transient_streamable_http_error classifies 400 as a transient error (retry), not as a transport-mismatch signal. SSE fallback is therefore never triggered, and after three failed attempts the 20-second timeout fires.
Root cause
File: lfx/base/mcp/util.py
Bug 1 (primary) — SSE mode still enters the Streamable HTTP path:
~line 2662
elif mode in ["Streamable_HTTP", "SSE"]: tools = await mcp_streamable_http_client.connect_to_server(url, ...)
Both modes call the same client. _create_streamable_http_session only skips Streamable HTTP when preferred_transport == "sse", but update_tools never sets that preference for mode == "SSE", so Streamable HTTP is always attempted first.
Bug 2 (secondary) — HTTP 400 misclassified as transient:
~line 1029-1034 in _is_transient_streamable_http_error
"404/405/406: try SSE; other 4xx: retry Streamable HTTP"
return leaf.response.status_code not in ( HTTP_NOT_FOUND, # 404 HTTP_METHOD_NOT_ALLOWED, # 405 HTTP_NOT_ACCEPTABLE, # 406 )
HTTP 400 is not in the SSE-fallback set, so it's treated as transient → retried 3 times → no SSE fallback → timeout.
Reproduction
Steps to reproduce
- Run any legacy SSE MCP server — one using the original SSE transport (GET → event: endpoint\ndata: ?sessionId= → POST /?sessionId=). Any server built with the pre-Streamable-HTTP mcp Python SDK that has not been updated will reproduce this.
- In Langflow, add a Custom MCP Tools component with URL = that server's URL and Connection Type = SSE.
- Run the flow or click Check & Update Tools.
Expected behavior
Expected behaviour
When Connection Type = SSE is selected, sse_client should be used directly without probing Streamable HTTP first. At minimum, an HTTP 400 from a Streamable HTTP probe should trigger an SSE fallback — 400 means the server rejected the transport, which is structurally identical to 404/405/406.
Who can help?
No response
Operating System
macOS 15
Langflow Version
1.12.0
Python Version
3.12
Screenshot
No response
Flow File
No response
Source: langflow-ai/langflow