dify-plugin-tools-mcp_sse
dify-plugin-tools-mcp_sse copied to clipboard
httpx.Client timeout configuration issue causes SSE connection failures
Please confirm before submission 在提交之前,请确认
- [x] I have searched for existing issues search for existing issues, including closed ones. 我已经搜索了现有问题搜索现有问题,包括已关闭的问题。"
Dify version Dify版本
1.4.1
Plugin version 插件版本
0.1.10
HTTP with SSE or Streamable HTTP
HTTP with SSE
Problem description 问题描述
Summary
The MCP SSE client experiences timeout failures within approximately 5 seconds when connecting to slower MCP servers, even when timeout and sse_read_timeout are configured to higher values (e.g., 50+ seconds). This issue occurs because the httpx.Client is initialized without explicit timeout configuration, causing it to use httpx's default 5-second timeout.
Current Implementation
File: utils/mcp_client.py
Line: 56
def __init__(self, name: str, url: str,
headers: dict[str, Any] | None = None,
timeout: float = 50,
sse_read_timeout: float = 50,
):
self.name = name
self.url = url
self.timeout = timeout
self.sse_read_timeout = sse_read_timeout
self.endpoint_url = None
self.client = httpx.Client(headers=headers) # ← Issue: No timeout specified
# ... rest of initialization
The timeout and sse_read_timeout parameters are stored but not applied to the httpx.Client initialization. They are only used later in the connect_sse() call:
with connect_sse(
client=self.client,
method="GET",
url=self.url,
timeout=httpx.Timeout(self.timeout, read=self.sse_read_timeout),
# ... other parameters
):
Specific Issues Observed
1. Quick Timeout Failures
- Symptom: SSE connections fail within 5 seconds, regardless of configured timeout values
- Frequency: Consistently occurs with MCP servers that take longer to:
- Complete initialization
- Send the first SSE event
- Respond due to cold start delays (e.g., cloud containers)
2. Inconsistent Behavior
- Symptom: Sometimes connections work, sometimes they don't, depending on server response time
- Impact: Unreliable connections to legitimate MCP servers hosted on cloud platforms
3. Authentication-Related Timing
- Symptom: Connections with API key authentication appear to fail more frequently
- Reason: Additional authentication processing time pushes total response time over the 5-second threshold
Root Cause Analysis
Technical Cause
- httpx Default Timeout: When
httpx.Client()is initialized without explicit timeout configuration, it uses httpx's default timeout of 5 seconds for both connect and read operations - SSE Connection Flow: The initial SSE connection establishment happens through the client's default timeout, not the
connect_sse()timeout override - First Event Dependency: SSE connections must receive the first event within the client's default timeout, or the connection is terminated
Evidence
- httpx documentation specifies default timeout behavior
- The
timeoutparameter in plugin configuration affects only theconnect_sse()call, not the underlying client - Cloud-hosted MCP servers often require 5+ seconds for cold start and initial response
Proposed Solution
1. Apply Configuration Timeout to httpx.Client
Recommended Change:
def __init__(self, name: str, url: str,
headers: dict[str, Any] | None = None,
timeout: float = 50,
sse_read_timeout: float = 50,
):
self.name = name
self.url = url
self.timeout = timeout
self.sse_read_timeout = sse_read_timeout
self.endpoint_url = None
# Apply timeout configuration to the client
client_timeout = httpx.Timeout(
connect=min(timeout, 30.0), # Reasonable connect timeout
read=sse_read_timeout, # Use configured read timeout
write=30.0, # Reasonable write timeout
pool=10.0 # Pool timeout
)
self.client = httpx.Client(headers=headers, timeout=client_timeout)
# ... rest of initialization
2. Alternative Minimal Fix
If the above change is too complex, a minimal fix would be:
self.client = httpx.Client(
headers=headers,
timeout=httpx.Timeout(connect=30.0, read=max(timeout, 30.0))
)
3. Backward Compatibility
- Keep the current
timeoutandsse_read_timeoutparameters - Ensure the
connect_sse()call can still override these values if needed - Consider adding validation to prevent extremely short timeouts
Expected Benefits
- Reliability: Connections to slower MCP servers will succeed consistently
- User Experience: Plugin configuration timeouts will work as expected
- Cloud Compatibility: Better support for cloud-hosted MCP servers with cold start delays
- Consistency: Timeout behavior will match user expectations and documentation
Test Scenarios
To verify the fix:
- Connect to an MCP server that responds slowly (6+ seconds)
- Configure plugin with
timeout: 60, sse_read_timeout: 60 - Verify connection succeeds instead of timing out at 5 seconds