Skip to content

session_idle_timeout is not exposed via streamable_http_app() and can cancel active requests #2455

@shaun0927

Description

@shaun0927

Summary

The session_idle_timeout feature currently has two linked problems:

  1. it is implemented on StreamableHTTPSessionManager but not exposed through the canonical streamable_http_app() API surface
  2. it can terminate a session while a request is actively in flight

Why this looks like a bug

PR #1994 / #2022 describe session_idle_timeout as a way to reap sessions that receive no HTTP requests for the configured duration.

That implies two things:

  • users of the high-level StreamableHTTP API should be able to configure it without dropping down to manual session-manager wiring
  • a request that is currently being processed should not count as an idle session

Today neither of those expectations holds.

Problem 1: not exposed by streamable_http_app()

StreamableHTTPSessionManager(...) accepts session_idle_timeout, but:

  • mcp.server.lowlevel.server.Server.streamable_http_app(...) does not
  • mcp.server.mcpserver.server.MCPServer.streamable_http_app(...) does not

So the recommended high-level API cannot configure a supported session-manager feature.

Reproduction

from mcp.server import Server

app = Server("demo")
app.streamable_http_app(session_idle_timeout=30)

Observed behavior

TypeError: Server.streamable_http_app() got an unexpected keyword argument 'session_idle_timeout'

Problem 2: active requests can be cancelled by the idle timeout

With a short idle timeout and a handler that takes longer than that timeout, the session can be reaped mid-request and the client waits until timeout / session termination rather than receiving the tool result.

Reproduction outline

  • configure StreamableHTTPSessionManager(app=..., session_idle_timeout=...)
  • make a tool handler sleep longer than the timeout
  • call the tool over StreamableHTTP

Observed behavior

On current main, the active request can be terminated before the handler finishes, and the client fails instead of receiving the result.

Expected behavior

  • streamable_http_app() should expose session_idle_timeout
  • idle reaping should only happen when the session has no in-flight requests
  • once the last active request finishes, the idle deadline can resume normally

Validation

I reproduced both behaviors locally against current main.

I also verified that a minimal patch can fix both together by:

  1. threading session_idle_timeout through the low-level + MCPServer streamable_http_app() wrappers
  2. suspending idle reaping while at least one request is in flight
  3. restoring the idle deadline after the last active request completes

A focused regression suite in tests/server/test_streamable_http_manager.py can cover:

  • passthrough from streamable_http_app(session_idle_timeout=...)
  • active request longer than the timeout still completes successfully
  • existing idle-session reaping still works once requests are finished

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