Skip to content

Redesign lifespan: separate server-scoped and session-scoped lifetimes #2113

Description

@maxisbey

Summary

The current lifespan implementation is tied to sessions/transports rather than having distinct scopes. This causes two P0 bugs (#1300, #1304) and makes the model fundamentally wrong for production use.

Problem

Goal

Provide two distinct lifetime scopes:

  • Server lifespan — entered once when the server starts, exited when it shuts down. Survives across all sessions and requests. This is where you put database pools, ML models, shared caches.
  • Session lifespan — entered when a client session is established, exited when the session ends. This is where you put per-user state, auth context, session-specific resources.

Both should be accessible from handler context. The current single lifespan parameter should be replaced or extended to support both scopes.

Subsumes


AI Disclaimer

Activity

  1. added
    breaking changeWill break existing deployments when updated without changes
    v2Affects the v2 line (2.x on main)
    enhancementRequest for a new feature that's not currently supported
    P0Broken core functionality, security issues, critical missing feature
    P1Significant bug affecting many users, highly requested feature
    and removed
    P0Broken core functionality, security issues, critical missing feature
    on Feb 19, 2026
  2. kumar-pankaj0 commented on Feb 22, 2026

    @kumar-pankaj0

    Hi @maxisbey - I wanted to share my understanding of the lifespan redesign issue and confirm the proposed solution.

    Problem Summary

    The current single lifespan is tied to Server.run(), which is called per-session (streamable-http) or per-request (stateless_http). This causes:

    1. Bug Lifespan does not execute on startup streamable-http #1300: With streamable-http, lifespan doesn't run on server startup - only when a client connects
    2. Bug Lifespan enters and exits for each request when stateless_http=True #1304: With stateless_http=True, lifespan enters/exits for every request

    Both problems stem from the same root cause: no way to create resources that live for the entire server process.

    Proposed Solution: Two Separate Lifespans

    Server Lifespan (runs ONCE)

    • When: Server starts → stops
    • Use for: Database connection pools, ML models, shared caches
    • Shared by: All clients/requests

    Session Lifespan (runs PER CLIENT)

    • When: Client connects → disconnects
    • Use for: User-specific data, auth context, scoped database access
    • Unique to: Each client/session

    API Design Question

    I see two possible approaches:

    Option A: Extend (backwards compatible)

    server = Server(
        "myapp",
        lifespan=my_lifespan,           # Session lifespan (current behavior)
        server_lifespan=server_lifespan, # NEW: Server lifespan
    )

    Option B: Replace (breaking change, clearer)

    server = Server(
        "myapp",
        server_lifespan=server_lifespan,  # Server-scoped
        session_lifespan=session_lifespan, # Session-scoped
    )

    Given this is a "redesign" and the maintainers marked the related bugs as "subsumed by #2113", I lean toward Option B for a cleaner API, with a migration guide.

    Context Access in Handlers

    @server.tool()
    async def my_tool(ctx: ServerRequestContext):
        # Access server-level resources (shared)
        db = ctx.server_lifespan_context["db"]
        
        # Access session-level resources (client-specific)
        user = ctx.session_lifespan_context["user"]

    Would love to hear your thoughts on the API design choice and whether this aligns with your vision for the fix!

  3. maxisbey commented on Aug 10, 2026

    @maxisbey
    ContributorAuthor

    This landed as part of v2, which is now released (via #2928) — closing. Feel free to reopen if there's something still outstanding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featurebreaking changeWill break existing deployments when updated without changesenhancementRequest for a new feature that's not currently supportedv2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions