Describe the bug
The C# SDK's StreamableHttpClientSessionTransport only handles SSE streams but does not support single JSON responses, which are explicitly allowed by the Streamable HTTP transport specification.
According to the spec:
Server Responses: The server can respond either with:
- A single JSON response (
Content-Type: application/json)
- An SSE stream (
Content-Type: text/event-stream) for multiple messages
The SDK unconditionally uses a streaming parser regardless of the response Content-Type, causing failures with spec-compliant MCP servers that return single JSON responses instead of SSE streams.
To Reproduce
Steps to reproduce the behavior:
-
Connect to a server that returns single JSON responses (e.g., Microsoft Dataverse MCP at https://d365catalyst.crm.dynamics.com/api/mcp)
-
Send an initialize request using the C# SDK:
var transportOptions = new HttpClientTransportOptions
{
Name = "test",
Endpoint = new Uri("https://d365catalyst.crm.dynamics.com/api/mcp"),
AdditionalHeaders = new Dictionary<string, string>
{
["Authorization"] = "Bearer <valid-token>"
}
};
var clientTransport = new HttpClientTransport(transportOptions, httpClient);
var mcpClient = await McpClient.CreateAsync(clientTransport, clientOptions, cancellationToken);
var tools = await mcpClient.ListToolsAsync(cancellationToken);
- Observe the error:
Streamable HTTP POST response completed without a reply to request with ID: 1
- Verify server is working correctly using direct HTTP:
var jsonContent = JsonSerializer.Serialize(new
{
jsonrpc = "2.0",
id = 1,
method = "initialize",
@params = new
{
protocolVersion = "2024-11-05",
capabilities = new { },
clientInfo = new { name = "TestClient", version = "1.0.0" }
}
});
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(url, content);
// ✅ Returns 200 OK
// ✅ Content-Type: application/json; charset=utf-8
// ✅ Body: {"jsonrpc":"2.0","id":1,"result":{...}}
Expected behavior
The SDK should:
- Check the response
Content-Type header
- If
application/json: Parse the complete response body as a single JSON-RPC message
- If
text/event-stream: Use the streaming parser for SSE events
Both response formats are valid per the MCP Streamable HTTP spec and should be supported.
Logs
Server Response (Spec-Compliant):
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 167
Mcp-Session-Id: a9259a04-549e-4abb-97d4-92b042362686
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"Microsoft Dataverse MCP Server","version":"1.0.0"}}}
SDK Error:
Streamable HTTP POST response completed without a reply to request with ID: 1
Root Cause (from AutoDetectingClientSessionTransport.cs lines 65-77):
using var response = await streamableHttpTransport.SendHttpRequestAsync(message, cancellationToken);
if (response.IsSuccessStatusCode) // ← Only checks HTTP status, not Content-Type
{
LogUsingStreamableHttp(_name);
ActiveTransport = streamableHttpTransport; // ← Assumes it works without validating response format
}
The AutoDetect logic:
- Sees
200 OK and assumes Streamable HTTP works ✓
- Sets
StreamableHttpClientSessionTransport as active transport ✓
- Later, when parsing the response, the streaming parser fails because the response is
application/json, not text/event-stream ✗
- No fallback mechanism exists at this point ✗
Additional context
Test Results:
| Test Method |
Result |
Details |
| Direct HTTP POST |
✅ Works |
Receives valid JSON-RPC response |
| VS Code MCP Extension |
✅ Works |
JavaScript SDK handles single JSON responses |
| C# SDK AutoDetect |
❌ Fails |
False positive: detects "working" then fails to parse |
Affected Servers:
- Microsoft Dataverse MCP (
https://d365catalyst.crm.dynamics.com/api/mcp)
- Any MCP server using Streamable HTTP with single JSON responses (spec-compliant behavior)
Environment:
- Package:
ModelContextProtocol versions 0.8.0-preview.1 and 1.1.0 (both affected)
- .NET: 8.0
- Platform: Windows, Azure
Impact:
- SDK claims to support Streamable HTTP but only implements half of the spec (SSE streams only)
- AutoDetect mode gives false positives
- No workaround available within the SDK
Proposed Fix:
StreamableHttpClientSessionTransport.SendHttpRequestAsync() should check the response Content-Type:
var contentType = response.Content.Headers.ContentType?.MediaType;
if (contentType == "application/json")
{
// Single JSON response - parse directly
var body = await response.Content.ReadAsStringAsync(cancellationToken);
var jsonMessage = JsonSerializer.Deserialize<JsonRpcMessage>(body);
await _messageChannel.Writer.WriteAsync(jsonMessage, cancellationToken);
}
else if (contentType == "text/event-stream")
{
// SSE stream - use existing streaming parser
// ... existing logic ...
}
Why This Matters:
Single JSON responses are simpler and more efficient for:
- Request-response patterns (most MCP operations)
- Servers that don't need server-to-client push notifications
- Simplified server implementation (no SSE infrastructure needed)
The MCP spec explicitly allows this mode, and the C# SDK should support it.
References:
Describe the bug
The C# SDK's
StreamableHttpClientSessionTransportonly handles SSE streams but does not support single JSON responses, which are explicitly allowed by the Streamable HTTP transport specification.According to the spec:
The SDK unconditionally uses a streaming parser regardless of the response
Content-Type, causing failures with spec-compliant MCP servers that return single JSON responses instead of SSE streams.To Reproduce
Steps to reproduce the behavior:
Connect to a server that returns single JSON responses (e.g., Microsoft Dataverse MCP at
https://d365catalyst.crm.dynamics.com/api/mcp)Send an initialize request using the C# SDK:
Expected behavior
The SDK should:
Content-Typeheaderapplication/json: Parse the complete response body as a single JSON-RPC messagetext/event-stream: Use the streaming parser for SSE eventsBoth response formats are valid per the MCP Streamable HTTP spec and should be supported.
Logs
Server Response (Spec-Compliant):
SDK Error:
Root Cause (from
AutoDetectingClientSessionTransport.cslines 65-77):The AutoDetect logic:
200 OKand assumes Streamable HTTP works ✓StreamableHttpClientSessionTransportas active transport ✓application/json, nottext/event-stream✗Additional context
Test Results:
Affected Servers:
https://d365catalyst.crm.dynamics.com/api/mcp)Environment:
ModelContextProtocolversions0.8.0-preview.1and1.1.0(both affected)Impact:
Proposed Fix:
StreamableHttpClientSessionTransport.SendHttpRequestAsync()should check the responseContent-Type:Why This Matters:
Single JSON responses are simpler and more efficient for:
The MCP spec explicitly allows this mode, and the C# SDK should support it.
References:
AutoDetectingClientSessionTransport.cs