You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Lifespan does not execute on startup streamable-http #1300
With stdio protocol, the lifespan runs on server start up as expected. However, with streamable-http the lifespan does not execute on server start up.
Example Code
fromcollections.abcimportAsyncIteratorfromcontextlibimportasynccontextmanagerfromdataclassesimportdataclassfrommcp.server.fastmcpimportContext, FastMCPfrommcp.server.sessionimportServerSession# Mock database class for exampleclassDatabase:
"""Mock database class for example."""@classmethodasyncdefconnect(cls) ->"Database":
"""Connect to database."""returncls()
asyncdefdisconnect(self) ->None:
"""Disconnect from database."""passdefquery(self) ->str:
"""Execute a query."""return"Query result"@dataclassclassAppContext:
"""Application context with typed dependencies."""db: Database@asynccontextmanagerasyncdefapp_lifespan(server: FastMCP) ->AsyncIterator[AppContext]:
"""Manage application lifecycle with type-safe context."""# Initialize on startupprint("Enter lifespan")
db=awaitDatabase.connect()
try:
yieldAppContext(db=db)
finally:
# Cleanup on shutdownawaitdb.disconnect()
# Pass lifespan to servermcp=FastMCP("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools@mcp.tool()defquery_db(ctx: Context[ServerSession, AppContext]) ->str:
"""Tool that uses initialized resources."""db=ctx.request_context.lifespan_context.dbreturndb.query()
mcp.run(transport="streamable-http") # on server startup, the lifespan does not run
I experience this problem also, do not know if I have missed something?
saved your code to t.py
uv run python t.py
INFO: Started server process [99315]
INFO: Waiting for application startup.
[09/29/25 15:29:43] INFO StreamableHTTP session manager started streamable_http_manager.py:110
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
This is my observation:
When using transport=streamable-http, the lifespan context does not execute on server startup. Instead, it runs only when a new client connects and a session is created. I don't know if this is the expected behavior.
This is when I ran the server without connecting with a client:
└ $ uv run .\main.py
INFO: Started server process [19920]
INFO: Waiting for application startup.
StreamableHTTP session manager started
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
After connecting with a client:
Created new transport with session ID: ff70c31b891840af9ce3c5a220d2c9b9
Enter lifespan
INFO: 127.0.0.1:50685 - "POST /mcp HTTP/1.1" 200 OK
INFO: 127.0.0.1:50688 - "POST /mcp HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:50689 - "GET /mcp HTTP/1.1" 200 OK
INFO: 127.0.0.1:50691 - "POST /mcp HTTP/1.1" 200 OK
Processing request of type ListToolsRequest
Terminating session: ff70c31b891840af9ce3c5a220d2c9b9
INFO: 127.0.0.1:50693 - "DELETE /mcp HTTP/1.1" 200 OK
I have tried with both mcp-inspector and ClientSession. Works in both cases.
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
# Connect to a streamable HTTP server
async with streamablehttp_client("http://localhost:8000/mcp") as (
read_stream,
write_stream,
_,
):
# Create a session using the client streams
async with ClientSession(read_stream, write_stream) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[tool.name for tool in tools.tools]}")
if __name__ == "__main__":
asyncio.run(main())
Client Output:
└ $ uv run .\mcp_client.py
Available tools: ['query_db']
Activity
jpoehnelt commentedon Aug 27, 2025
Why was this closed? Link to PR?
savvaki commentedon Aug 28, 2025
I can reopen if you're able to reproduce?
zeyugao commentedon Sep 29, 2025
I experience this problem also, do not know if I have missed something?
saved your code to t.py
beginor commentedon Oct 14, 2025
The same issue still exits with mcp 1.17.0 😂
Arnab-cloud commentedon Oct 22, 2025
This is my observation:
When using
transport=streamable-http, the lifespan context does not execute on server startup. Instead, it runs only when a new client connects and a session is created. I don't know if this is the expected behavior.This is when I ran the server without connecting with a client:
After connecting with a client:
I have tried with both mcp-inspector and
ClientSession. Works in both cases.OS: Windows 11Code for client:
Client Output:
fernando-torres-blip-ai commentedon Jan 13, 2026
Still facing this problem, any solution ?
maxisbey commentedon Feb 19, 2026
Subsumed by #2113 which redesigns lifespan with proper server-scoped vs session-scoped lifetimes.
feat(server): integrate server lifespan into Starlette app lifespan
docs(migration): add lifespan redesign migration guide for Option B