Skip to content

fix(mcp): guard against duplicate serve() on streamable-http MCP servers - #8435

Merged
thinhlpg merged 2 commits into
janhq:mainfrom
thinhlpg:fix/mcp-http-duplicate-initialize-8411
Jul 15, 2026
Merged

fix(mcp): guard against duplicate serve() on streamable-http MCP servers#8435
thinhlpg merged 2 commits into
janhq:mainfrom
thinhlpg:fix/mcp-http-duplicate-initialize-8411

Conversation

@thinhlpg

Copy link
Copy Markdown
Member

Problem

Fixes #8411

Remote streamable-HTTP MCP servers (type: "http") intermittently fail to connect with:

Failed to connect to server: ... 400 Bad Request ... when send initialize request

or connect (UI turns green) then drop a few seconds later. Server-side logs show Jan sending the initialize JSON-RPC request twice with the same request id 0; the first succeeds, the second is rejected as a duplicate on an already-initialized session.

Root cause

start_mcp_server had no idempotency guard, so a server could be serve()'d twice. rmcp's serve() creates a fresh client that sends initialize exactly once (request id starts at 0 per client) — so two initialize with id 0 means two serve() calls, not an rmcp retry.

Two starts happen in practice because restart_active_mcp_servers (helpers.rs) restarts every active server without clearing it from the running map first, and several frontend flows fire activate and a restart-all for one action (e.g. renaming a server: activate + syncServersAndRestart). The two serve() calls each POST initialize; the second gets 400.

Fix

Make start_mcp_server idempotent (3 files, +32/-2):

  • Skip if the server is already running (present in the live map).
  • Skip if a start is already in flight — tracked via a new mcp_starting: HashSet<String> on AppState; cleared when the attempt finishes (success or failure).

The reconnect path (schedule_mcp_start_task) is intentionally left unguarded so health-check auto-reconnect can still re-serve.

Verification

Tested locally against a mock streamable-HTTP server that mimics the remote (first initialize → 200 + session id, duplicate → 400), with injected latency to widen the race window:

  • Bug reproduced: two concurrent initialize200 + 400 DUPLICATE.
  • Fix confirmed: renaming a connected server (the deterministic double-start trigger) now logs MCP server <name> start already in progress; skipping duplicate start; the mock receives exactly one initialize, no 400, connection stays up.
  • No regression: fresh connect, auto-reconnect, JSON re-add, and edit+save re-activation all produce a single initialize and remain connected.

🤖 Generated with Claude Code

Remote streamable-http MCP servers (type "http") intermittently failed to
connect with `400 Bad Request ... when send initialize request`, or connected
then dropped a few seconds later.

Root cause: `start_mcp_server` had no idempotency guard, so a server could be
serve()'d twice (e.g. a rename fires activate + syncServersAndRestart, and
`restart_active_mcp_servers` restarts active servers without clearing them
first). Each serve() spins up an independent rmcp client that sends its own
`initialize` (both with request id 0); the second is rejected by the server as
a duplicate on an already-initialized session, tearing down the connection.

Fix: make `start_mcp_server` idempotent — skip if the server is already running
or a start is already in flight (tracked via a new `mcp_starting` set on
AppState), clearing the in-flight marker when the attempt completes. The
reconnect path (`schedule_mcp_start_task`) is intentionally left unguarded so
auto-reconnect can still re-serve.

Fixes janhq#8411
@thinhlpg
thinhlpg force-pushed the fix/mcp-http-duplicate-initialize-8411 branch from 674b210 to 703fc74 Compare July 15, 2026 07:43
@thinhlpg
thinhlpg requested review from jjchen01 and qnixsynapse July 15, 2026 07:43
Comment thread src-tauri/src/core/mcp/helpers.rs Outdated
Comment thread src-tauri/src/core/mcp/helpers.rs Outdated
Address review: the idempotency-guard skip messages are routine, not
noteworthy, so log them at debug instead of info.

@qnixsynapse qnixsynapse left a comment

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.

LGTM

@thinhlpg
thinhlpg merged commit 7657384 into janhq:main Jul 15, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this to QA in Jan Jul 15, 2026
@thinhlpg
thinhlpg deleted the fix/mcp-http-duplicate-initialize-8411 branch July 15, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: QA

Development

Successfully merging this pull request may close these issues.

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

3 participants