Conversation
…nce deployments Use NeverSessionManager + stateful_mode(false) so every POST request is handled independently. Previously the default LocalSessionManager stored sessions in memory per process, causing Cursor (and any load-balanced client) to receive 404 "Session not found" when a request landed on a different instance than the one that created the session. Clients that cache the Mcp-Session-Id then fell back to legacy SSE V1, which this server does not implement, producing a 400 error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MCP spec requires structuredContent to be a record (JSON object). Tools that return Vec<T> serialize to a JSON array, which Cursor validates strictly and rejects with "expected record, received array". Filter structured_content to None for non-object values so array responses (static_info, quote, trades, candlesticks, etc.) no longer violate the spec. The fix is centralized in tool_result so all tools are covered without per-tool changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hogan-yuan
pushed a commit
that referenced
this pull request
Jul 6, 2026
…olation (#38) ## Summary - Switch MCP server to stateless mode to fix session-not-found errors on multi-instance deployments - Fix `structuredContent` type violation that caused Cursor to reject array tool responses ## Fix 1 — Stateless mode (`src/auth/mod.rs`) **Root cause**: The server is designed for stateless multi-instance deployment, but was using `stateful_mode: true` (the rmcp default) with an in-memory `LocalSessionManager`. Under a load balancer, sessions created on Instance A are unknown to Instance B, triggering a failure chain in Cursor: 1. POST with cached `Mcp-Session-Id` → **404 Session not found** (session lives on another instance) 2. Cursor falls back to legacy SSE V1 protocol (GET without session ID) → **400 Session ID is required** Claude Code and Codex are unaffected because they re-initialize on every connection rather than caching session IDs. **Fix**: Replace `LocalSessionManager` with `NeverSessionManager` and set `stateful_mode(false)`. The `Mcp-Session-Id` header is completely ignored in stateless mode; each POST is handled independently with no session state. ## Fix 2 — `structuredContent` type (`src/tools/mod.rs`) **Root cause**: `tool_result` unconditionally assigned the parsed JSON value to `structured_content`. Tools returning `Vec<T>` (e.g. `quote`, `static_info`, `trades`, `candlesticks`, `participants`) serialize to a JSON array. The MCP spec requires `structuredContent` to be a JSON **object** (record); Cursor validates this strictly and rejects array values with: ``` Invalid input: expected record, received array ``` **Fix**: Added `.filter(serde_json::Value::is_object)` so `structured_content` is only set for JSON object responses. Array responses leave it as `None`, which is valid per spec. The fix is centralized in `tool_result` and covers all tools. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
structuredContenttype violation that caused Cursor to reject array tool responsesFix 1 — Stateless mode (
src/auth/mod.rs)Root cause: The server is designed for stateless multi-instance deployment, but was using
stateful_mode: true(the rmcp default) with an in-memoryLocalSessionManager. Under a load balancer, sessions created on Instance A are unknown to Instance B, triggering a failure chain in Cursor:Mcp-Session-Id→ 404 Session not found (session lives on another instance)Claude Code and Codex are unaffected because they re-initialize on every connection rather than caching session IDs.
Fix: Replace
LocalSessionManagerwithNeverSessionManagerand setstateful_mode(false). TheMcp-Session-Idheader is completely ignored in stateless mode; each POST is handled independently with no session state.Fix 2 —
structuredContenttype (src/tools/mod.rs)Root cause:
tool_resultunconditionally assigned the parsed JSON value tostructured_content. Tools returningVec<T>(e.g.quote,static_info,trades,candlesticks,participants) serialize to a JSON array. The MCP spec requiresstructuredContentto be a JSON object (record); Cursor validates this strictly and rejects array values with:Fix: Added
.filter(serde_json::Value::is_object)sostructured_contentis only set for JSON object responses. Array responses leave it asNone, which is valid per spec. The fix is centralized intool_resultand covers all tools.🤖 Generated with Claude Code