Skip to content

Bug: Streamable HTTP MCP client sends duplicate initialize request, causing 400 Bad Request and connection drop on remote servers #8411

Description

@shawnstory

Description

When connecting to a remote MCP server using the streamable-http (or type: "http") transport, Jan's MCP client sends the initialize JSON-RPC request twice in immediate succession, with identical parameters and the same request id. The first initialize call succeeds and receives a valid response from the server, but the duplicate second call is rejected by the server with 400 Bad Request, causing the overall connection to fail.

This appears to be a bug in Jan's Streamable HTTP client (built on the rmcp Rust crate), not an issue with the remote server, since the same endpoint connects successfully from other MCP clients (verified via direct curl testing and the hosting provider's own reference client examples).

Environment

  • Jan version: 0.8.3
  • OS: Windows 11
  • MCP server tested: ihor-sokoliuk/mcp-searxng v1.1.1, hosted remotely via Glama's MCP hosting/gateway (https://glama.ai/endpoints//mcp)
  • Transport: Streamable HTTP with Authorization: Bearer header

MCP Server Configuration Used

{
"searxng-http": {
"active": true,
"args": [],
"command": "",
"env": {},
"type": "http",
"url": "https://glama.ai/endpoints//mcp",
"headers": {
"Authorization": "Bearer "
}
}
}

Error Reported by Jan

Failed to connect to server: Send message error Transport [rmcp::transport::worker::WorkerTransport<rmcp::transport::streamable_http_client::StreamableHttpClientWorkerreqwest::async_impl::client::Client>] error: Client error: HTTP status client error (400 Bad Request) for url (https://glama.ai/endpoints//mcp), when send initialize request

Secondary Symptom: Brief "Connected" State Followed by Immediate Disconnect

In addition to the outright 400 error above, on some attempts the server briefly shows as connected in Jan's UI (green connection indicator lights up), but then a few seconds later the indicator disappears and the server becomes unusable, without any further action from the user. Once this happens, the connection does not recover on its own and the server has to be manually restarted/re-enabled to attempt reconnecting.

This is very likely the same underlying bug manifesting differently: the first initialize call succeeds (which is presumably why the UI briefly shows "connected"), but the duplicate second initialize call sent immediately afterward gets rejected by the server, which likely causes Jan to tear down the session or mark the connection as failed shortly after — even though the connection had, for a moment, actually been established correctly.

Evidence from Server-Side Request Logs

The hosting provider (Glama) logs raw JSON-RPC traffic hitting the endpoint. Inspecting these logs during a failed connection attempt from Jan shows the following sequence:

1st request received (initialize):
{
"id": 0,
"method": "initialize",
"params": {
"clientInfo": {
"name": "Jan Streamable Client",
"version": "0.0.1"
},
"capabilities": {},
"protocolVersion": "2025-03-26"
},
"jsonrpc": "2.0"
}

Server's response to the 1st request (successful):
{
"id": 0,
"result": {
"serverInfo": {
"name": "ihor-sokoliuk/mcp-searxng",
"version": "1.1.1"
},
"capabilities": {
"tools": {},
"logging": {},
"resources": {}
},
"protocolVersion": "2025-03-26"
},
"jsonrpc": "2.0"
}

3rd request received — an exact duplicate of the 1st, sent immediately after:
{
"id": 0,
"method": "initialize",
"params": {
"clientInfo": {
"name": "Jan Streamable Client",
"version": "0.0.1"
},
"capabilities": {},
"protocolVersion": "2025-03-26"
},
"jsonrpc": "2.0"
}

This duplicate initialize call, sent with the same id: 0 and identical payload, is rejected by the server with 400 Bad Request since a session had already been established by the first successful call. Jan then surfaces this as a fatal "Failed to connect to server" error, even though the initial handshake actually succeeded. This same duplicate-call behavior is the likely cause of the brief "connected then disconnected" UI state described above as well.

Steps to Reproduce

  1. Set up (or use) a remote MCP server that speaks Streamable HTTP and requires an Authorization: Bearer header.
  2. In Jan, add a new MCP server via JSON config using "type": "http", a valid url, and a headers object containing a valid bearer token.
  3. Enable/start the server in Jan.
  4. Observe one of two failure modes:
    a) An immediate "Failed to connect to server... 400 Bad Request... when send initialize request" error, OR
    b) The connection indicator briefly turns green ("connected"), then a few seconds later disappears on its own, leaving the server unusable and unable to reconnect without manual intervention.
  5. (Optional, to confirm root cause) Inspect server-side request logs, if your hosting provider exposes them, and observe that Jan sends the initialize request twice with an identical payload and id, and that only the second, duplicate call is rejected.

Expected Behavior

Jan's Streamable HTTP client should send the initialize request exactly once per connection attempt, correctly capture the resulting session (e.g., via the Mcp-Session-Id response header if present), and proceed directly to sending notifications/initialized followed by normal MCP calls (tools/list, etc.), without re-sending initialize a second time. The connection should remain stable and usable once established, rather than dropping shortly after appearing to succeed.

Actual Behavior

Jan sends initialize twice with identical parameters and the same JSON-RPC id. The first call succeeds; the second is rejected by the server as invalid/malformed for an already-initialized session. Depending on timing, this either causes Jan to report the connection attempt as failed outright with a 400 error, or causes the connection to briefly appear successful in the UI before dropping a few seconds later and becoming unusable — despite the underlying handshake having actually succeeded on the first attempt in both cases.

Additional Notes

  • This is not a server-side or configuration issue: the same endpoint, token, and header format connect successfully using other MCP clients and using manual curl testing following the MCP Streamable HTTP spec.
  • This suggests a bug in the retry/connection-establishment logic of Jan's rmcp-based Streamable HTTP transport worker, possibly related to how it detects a successful initialize response or how/whether it reads and stores the session identifier before deciding whether to retry.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

No fields configured for Bug.

Projects

Status
Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions