Skip to content

Support Streamable HTTP MCP endpoints#1300

Merged
Hmbown merged 1 commit intoHmbown:mainfrom
reidliu41:fix/mcp-streamable-http
May 9, 2026
Merged

Support Streamable HTTP MCP endpoints#1300
Hmbown merged 1 commit intoHmbown:mainfrom
reidliu41:fix/mcp-streamable-http

Conversation

@reidliu41
Copy link
Copy Markdown
Contributor

@reidliu41 reidliu41 commented May 9, 2026

Summary

This fixes MCP servers that use Streamable HTTP endpoints, such as DeepWiki at
https://mcp.deepwiki.com/mcp.

Previously, URL-based MCP connections only used the older SSE endpoint discovery
flow: open the URL with GET, wait for an endpoint event, then send requests
there. Streamable HTTP servers expect JSON-RPC requests to be POSTed directly to
the MCP URL and may return responses as text/event-stream, so validation failed
before any tools could be discovered.

This change adds Streamable HTTP support for URL MCP servers and preserves the
existing SSE discovery behavior as a fallback for older servers.

deepseek doctor
DeepSeek TUI Doctor
==================
...

MCP Servers:
  ✓ MCP feature flag enabled
  ✓ MCP config found at ~/.deepseek/mcp.json
  · 2 server(s) configured
  ✓ deepwiki: HTTP/SSE server at https://mcp.deepwiki.com/mcp
  ✓ example: stdio server (node ./path/to/your-mcp-server.js)

deepseek mcp validate
MCP config is valid. All enabled servers connected.

fixes: #1266

Testing

  • cargo test --all-features
  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features

Checklist

  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes

  Add direct POST-based MCP transport for Streamable HTTP servers while keeping
  the existing SSE endpoint-discovery path as a fallback. Parse both JSON and
  text/event-stream responses so servers like DeepWiki can be validated and used.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces HttpTransport, a new transport layer for the Model Context Protocol (MCP) that supports streamable HTTP responses with a fallback to Server-Sent Events (SSE). It includes logic for parsing SSE messages and handling various HTTP status codes. Feedback highlights a potential issue where an empty message queue in StreamableHttpTransport::recv could lead to unintended connection closures. Additionally, the SSE parser's memory efficiency could be improved, and the global reqwest::Client timeout might prematurely terminate long-running tool executions if it is set lower than the application-level execution timeout.

Comment thread crates/tui/src/mcp.rs
Comment on lines +715 to +719
async fn recv(&mut self) -> Result<serde_json::Value> {
self.pending_messages
.pop_front()
.context("MCP Streamable HTTP response queue is empty")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The recv implementation for StreamableHttpTransport returns an error immediately if the pending_messages queue is empty. While this transport is primarily request-response, McpConnection::recv (line 1307) treats any error from transport.recv() as a fatal disconnection. If a server returns a 202 Accepted or 204 No Content status (handled at line 683), the queue will be empty and subsequent calls to recv will cause the connection to be marked as Disconnected. Ensure that recv behavior aligns with the expected lifecycle of the connection, perhaps by returning an empty result or waiting if appropriate.

Comment thread crates/tui/src/mcp.rs
}

fn parse_sse_json_messages(body: &str) -> Result<Vec<serde_json::Value>> {
let normalized = body.replace("\r\n", "\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The SSE parser is quite naive and may fail on large responses or non-standard line endings. Using body.replace("\r\n", "\n") creates a full copy of the response body in memory, which could be inefficient for large payloads. Consider using a more robust SSE parsing library or an incremental parser that operates on the byte stream directly.

Comment thread crates/tui/src/mcp.rs
Comment on lines 875 to 877
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(connect_timeout_secs))
.build()?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The reqwest::Client is built with a global timeout set to connect_timeout_secs. This timeout applies to all requests made by the client, including tool executions. If connect_timeout (default 10s) is significantly shorter than execute_timeout (default 60s), tool calls will time out prematurely at the HTTP layer before the application-level timeout at line 1232 is reached. Consider configuring the client without a global timeout and applying specific timeouts per request, or using the maximum of the configured timeouts.

@Hmbown Hmbown merged commit e50eac0 into Hmbown:main May 9, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Streamable HTTP MCP 服务器 (deepwiki) 报 SSE endpoint not yet discovered 错误

2 participants