Skip to content

Stateless mode drops HTTP responses for long-running tool calls #1886

@tony-nekola-silk

Description

@tony-nekola-silk

Description

When using StreamableHTTPSessionManager with stateless=True and json_response=True, HTTP responses for long-running tool calls (2-5+ minutes) are never sent back to the client. The client receives an empty response immediately while the server continues processing.

Environment

  • MCP SDK: 1.25.0
  • Python: 3.13
  • Client: Claude Code 2.1.9 (MCP protocol version 2025-11-25)

Reproduction

Server configuration:

session_manager = StreamableHTTPSessionManager(
    app=mcp, 
    json_response=True, 
    stateless=True
)

Tool that takes several minutes:

@mcp.call_tool()
async def call_tool(name: str, arguments: dict):
    result = await long_running_operation()  # 2-5 minutes
    return result

Steps:

  1. Connect Claude Code to the MCP server
  2. Call the long-running tool
  3. Client receives empty response immediately
  4. Server logs show tool completed successfully with valid result

Expected Behavior

HTTP response should be sent after tool completes, containing the result.

Actual Behavior

  • Client receives empty response immediately
  • Server processes tool call successfully
  • Server generates result (logged correctly)
  • HTTP response is never sent to client

Log Evidence

12:01:55.130 - Client POST request received (mcp_protocol: 2025-11-25)
12:01:56.080 - tool_call event logged
12:06:50.269 - Tool result generated:
               content_count: 1, content_types: ["text"]
               ❌ NO HTTP response logged for client request

Key observation: Only ONE mcp_request logged but both tools/list and tools/call execute. Response routing appears broken for the second request.

Workaround Attempted

Setting stateless=False causes 400 Bad Request: Missing session ID - incompatible with Claude Code's connection pattern.

Hypothesis

In _handle_stateless_request, when rapid successive requests arrive from the same client, response routing fails for long-running operations. The response is generated but never correlated back to the correct HTTP connection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions