Where does the bug appear (feature/product)?
Cursor IDE
Describe the Bug
Two of my remote Streamable HTTP MCP servers reliably fail after Cursor idle-suspends the connection (idle-suspending transport after Ns idle). Resume attempts fail at the network layer (fetch failed / “Timed out waiting for connection”), not with an HTTP error, and Cursor retries five times with growing backoff before giving up. The server is not down — an external curl against the exact same URL, same TLS negotiation, same headers, at the same moment the exchange fails inside Cursor, returns 200 in well under 100ms every time I’ve checked.
Five other remote HTTP MCP servers in the same ~/.cursor/mcp.json / plugin setup, hit by the same Shared MCP process, do not show this failure — they resume cleanly after being idle for the same or longer.
Steps to Reproduce
- Configure a remote Streamable HTTP MCP server (either via
mcp.jsondirectly or via an Agent Plugin’smcp.json). - Use a tool from it once, successfully.
- Leave it idle for >10 minutes (Cursor’s own idle-suspend threshold).
- Call a tool from it again.
Expected Behavior
A normal reconnect — same as mcp.json-based n8n-mcp, clickup, github, Figma Desktop, and blindrelay all do for me after an equal or longer idle period.
Actual, for two specific servers only: MCP HTTP exchange failed / Transient error connecting to streamableHttp server: fetch failed, repeated 5 times with backoff, then silence until the plugin/window is reloaded.
Operating System
MacOS
Version Information
IDE:
Version: 3.18.9
Commit: (Menu → About Cursor → Copy, paste the exact commit hash here before posting)
For AI issues: which model did you use?
N/A — not a model/AI-quality issue, this is the MCP client’s remote transport layer.
For AI issues: add Request ID with privacy disabled
N/A (not applicable — no chat Request ID is associated with a background MCP transport failure).
Additional Information
What I ruled out
- Server down / slow / misconfigured — ruled out.
curl --http1.1andcurl --http2both succeed in <500ms at every timestamp I checked, including deliberately reproducing 125s/150s/190s idle gaps against the live server from a standalone script.GET /mcpcorrectly 405s (stateless JSON-only server, no SSE), staleMcp-Session-Idis ignored rather than erroring, DNS has a single A record (no IPv6 blackhole). - HTTP/2 vs HTTP/1.1 — ruled out. Set
cursor.general.disableHttp2: true, fully quit and reopened Cursor, same failure recurred at the next idle-suspend (16:42 and 17:12 in the log above). - Stdio vs Streamable HTTP — ruled out as the fix. I run this server as
type: "streamable-http"; a teammate/prior session in this same setup tried bridging it through a local stdio wrapper process specifically to work around this bug, which just traded a clean remote failure for local spawn-path breakage (Cannot find module,${PLUGIN_ROOT}not resolving, cwd resolving to the workspace instead of the plugin install dir) without touching the underlying resume issue. - Registered via Agent Plugin vs directly in
mcp.json— ruled out as the differentiator. A second, unrelated server (different host, different cloud provider, Google-hosted vs. GCE VM behind Traefik) shows the same class of failure (Timed out waiting for connection to "...") even though it’s registered as a plain entry in~/.cursor/mcp.json, not through a plugin.
What’s different about the two affected servers
Both of the affected servers require the client to authenticate and return a 401 with a WWW-Authenticate/challenge response when the credential is missing or invalid — one implements the full MCP OAuth discovery flow (resource_metadata, /authorize, /token), the other just checks a static x-api-key header and 403s. All five servers that resume cleanly for me (ClickUp, GitHub, n8n, Figma Desktop, a Blindrelay API) either use a credential Cursor already has cached from a completed OAuth flow, or send a static header that’s accepted unconditionally.
My best guess, offered as a hint rather than a diagnosis: something in Cursor’s transport-resume path after idle-suspend/stopped connection behaves differently when the server enforces a 401 challenge than when it doesn’t — possibly retrying with a stale credential/session state in a way that surfaces as a network-layer failure (fetch failed, connection timeout) instead of a clean 401, on some but not all reconnect attempts. I was not able to capture the actual request/response bytes during a live failure to confirm this further.
Log sample (from the affected server’s MCP output channel)
2026-09-03 16:22:46.184 [info] [Shared MCP process] Successfully connected to streamableHttp server
2026-09-03 16:22:46.208 [warning] [Shared MCP process] MCP HTTP exchange completed
2026-09-03 16:36:21.681 [info] [Shared MCP process] idle-suspending transport after 635s idle: plugin-talsec-opencti-opencti
2026-09-03 16:42:51.541 [warning] [Shared MCP process] MCP HTTP exchange failed
2026-09-03 16:42:51.541 [warning] [Shared MCP process] Transient error connecting to streamableHttp server: fetch failed
2026-09-03 16:42:58.200 [warning] [Shared MCP process] MCP HTTP exchange failed
2026-09-03 16:42:58.200 [warning] [Shared MCP process] Transient error connecting to streamableHttp server: fetch failed
2026-09-03 16:43:12.058 [warning] [Shared MCP process] MCP HTTP exchange failed
2026-09-03 16:43:12.058 [warning] [Shared MCP process] Transient error connecting to streamableHttp server: fetch failed
2026-09-03 16:43:41.813 [warning] [Shared MCP process] MCP HTTP exchange failed
2026-09-03 16:43:41.813 [warning] [Shared MCP process] Transient error connecting to streamableHttp server: fetch failed
2026-09-03 16:44:29.101 [warning] [Shared MCP process] MCP HTTP exchange failed
2026-09-03 16:44:29.102 [warning] [Shared MCP process] Transient error connecting to streamableHttp server: fetch failed
A curl against the same URL, from the same machine, one second after the 15:54:14 occurrence of this same failure earlier in the session, returned HTTP 200.
Aggregated over 3 days of logs for this one server: 1,165 fetch failed occurrences, always immediately preceded by either an idle-suspending transport line or a stopped connection / reconnect cycle, never a bare timeout with no preceding lifecycle event.
Does this stop you from using Cursor
No - Cursor works, but with this issue