Cannot authorize streamable-http MCP servers when URL path's last segment isn't mcp/sse - SSE-first fallback never triggers (httpx.ReadTimeout not caught)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 74/100
Research direction
Start in api/core/mcp/mcp_client.py at MCPClient._initialize and reproduce authorization against a streamable-http endpoint whose final path segment is not mcp or sse. Verify that streamable-http initialization succeeds without waiting for SSE, SSE fallback still works when needed, and MCPAuthError is not retried as another transport.
Written by the indexing model from the issue text.
Description
Title: Cannot authorize streamable-http MCP servers when URL path's last segment isn't mcp/sse — SSE-first fallback never triggers (httpx.ReadTimeout not caught)
Dify version: 1.15.0
Cloud or Self Hosted: Self Hosted (Docker)
Steps to reproduce
- Run Dify 1.15.0 via Docker (
langgenius/dify-api:1.15.0). - Go to Tools → MCP and add an MCP server whose endpoint is a streamable-http server and whose URL path does not end with
/mcpor/sse.
Example: a PandaWiki MCP share endpoint:
Here the last path segment is thehttp://<host>:8089/share/v1/mcp/<share_id>share_id, notmcp. - Confirm the server is a healthy streamable-http MCP server. A direct
POST .../initializereturns200+Mcp-Session-Idand a valid JSON-RPC initialize response:
A{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"pandawiki-mcp","version":"1.0.0"}}}GET(SSE-style) to the same URL hangs and returns nothing. - Click Authorize on the provider.
✔️ Expected Behavior
Dify detects that the server speaks streamable-http, performs the initialize handshake, fetches the tool list, and marks the provider as authorized.
❌ Actual Behavior
Clicking Authorize appears to do nothing in the UI.
- nginx access log:
(POST /console/api/workspaces/current/tool-provider/mcp/auth -> 499499= client closed the connection before the backend responded.) - api log:
core/mcp/client/sse_client.py:301 Error connecting to SSE endpoint httpcore.ReadTimeout: timed out tool_providers.py:1120 Failed to fetch MCP tools after creation - The provider stays
authed=falseintool_mcp_providers. The backend blocks up tosse_read_timeout(default 300s); the browser gives up first →499→ no feedback in the UI.
Root cause
In api/core/mcp/mcp_client.py, MCPClient._initialize picks the transport by the last segment of the URL path:
method_name = path.rstrip("/").split("/")[-1] if path else ""
if method_name in {"mcp", "sse"}:
client_factory = connection_methods[method_name]
self.connect_server(client_factory, method_name)
else:
try:
self.connect_server(sse_client, "sse") # tries SSE first
except (MCPConnectionError, ValueError): # cannot catch httpx.ReadTimeout
self.connect_server(streamablehttp_client, "mcp")
Two problems combine:
- The
elsebranch tries SSE first. A streamable-http server does not respond to the SSE GET, so the connect hangs untilsse_read_timeoutand raiseshttpx.ReadTimeout. except (MCPConnectionError, ValueError)does not catchhttpx.ReadTimeout(norhttpx.ConnectError), so the fallback tostreamablehttp_clientnever triggers. The timeout propagates and the auth call fails after a long block.
Also note the method docstring says "Initialize the client with fallback to SSE if streamable connection fails" — i.e. streamable-http is supposed to be the default — but the else branch actually tries SSE first, the opposite of the documented intent.
Impact
Any streamable-http MCP server whose URL path's last segment is not exactly mcp or sse (URLs ending with an id / token / share_id, or carrying a query string) cannot be authorized in Dify 1.15.0. This is a broad class of servers, not specific to PandaWiki.
Related: #24297 reported the same 300s symptom in 1.7.2 (attributed to the sse_client thread pool) and was closed as cant-reproduce. In 1.15.0 the 300s has a different, clearly identifiable root cause: the protocol-detection heuristic above + the except (MCPConnectionError, ValueError) that cannot catch httpx.ReadTimeout, so the SSE -> streamable fallback never runs.
Suggested fix
In the else branch, try streamable-http first and fall back to SSE on any connection failure, while letting MCPAuthError (HTTP 401) propagate so it isn't retried as a different transport:
else:
try:
self.connect_server(streamablehttp_client, "mcp")
except MCPAuthError:
raise
except Exception:
logger.debug("MCP connection failed with 'mcp', falling back to 'sse' method.")
self.connect_server(sse_client, "sse")
Notes:
MCPAuthErroris a subclass ofMCPConnectionError, so it must be caught and re-raised separately before the genericexcept Exception(otherwise a 401 would be silently retried over SSE).- Verified locally: with this change, the PandaWiki server authorizes in a couple of seconds and
list_toolsreturns correctly.
Environment
- Dify 1.15.0, Self Hosted (Docker).
SSRF_PROXY_HTTP_URL/SSRF_PROXY_HTTPS_URLare unset, so the MCP client connects directly (not via the squid SSRF proxy); the issue is unrelated to thedeny to_private_networkssquid rule.- MCP server: PandaWiki, streamable-http, public share endpoint (no auth).
- Dominant language
- TypeScript
- Stars
- 157k
- Forks
- 24.7k
- Avg merge
- 22h 32m
- Merged PRs (30d)
- 611
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from langgenius/dify
-
Annotation Reply: a stored score threshold of 0.0 is silently replaced with 1, disabling the feature Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42639 · 1 comment · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
langgenius/dify#42468 · 1 comment · 1 reaction ·
-
🐞 bug
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
langgenius/dify#42446 · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42355 · 1 comment · 1 reaction ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
langgenius/dify#42350 · 1 comment · 1 reaction ·
Similar issues
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100