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
Recommended deployment pattern for FastMCP on AWS Lambda using Mangum #3121
Root-caused this by checking Mangum's actual source (mangum/adapter.py): Mangum.__call__ creates a new LifespanCycle and enters/exits it on every single invocation, not just cold starts. streamable_http_app() wires the Starlette lifespan to session_manager.run(), which is documented as callable exactly once per instance. So the second invocation against a module-level global app sends a second lifespan.startup, which raises RuntimeError: StreamableHTTPSessionManager.run() can only be called once per instance. This isn't Mangum-version-specific or a misconfiguration — it happens regardless of stateless_http, since that flag doesn't change the lifespan wiring.
I verified this two ways: reproduced the exact RuntimeError with a global instance across two invocations, and confirmed 3 clean invocations with the app rebuilt fresh inside the handler (your workaround is correct — and cheap, since tool registration is just in-memory bookkeeping, not I/O).
Happy to open a PR adding an examples/servers/aws-lambda-streamablehttp/ example (factory function + Lambda handler + README explaining the above) if that'd be useful — let me know.
(Disclosure: used Claude Code to help navigate the SDK/Mangum source and draft this; I've reviewed and verified the repro myself.)
The root-cause above is right: Mangum runs the ASGI lifespan on every invocation, the app's lifespan enters StreamableHTTPSessionManager.run(), and run() is single-use per instance by design (regardless of stateless_http), so a module-level app fails on the first warm invocation — building the app inside the handler is the correct pattern, not a workaround. On your 1.28 line the FastMCP instance caches a single session manager, so a fresh instance per invocation is what you need there; on v2 (where FastMCP is renamed MCPServer) streamable_http_app() builds a new session manager on every call, so you can keep mcp = MCPServer(...) at module scope, with tools registered once at cold start, and only call mcp.streamable_http_app() inside the handler before wrapping it in Mangum. For Lambda you'll likely also want json_response=True (one JSON body per request instead of a held-open SSE stream) and stateless_http=True, since there's no session affinity — the transport options are listed under Running your server → Streamable HTTP. Finally, pass transport_security= with your Function URL's hostname: by default streamable_http_app() arms DNS-rebinding protection with a localhost-only allowlist and answers everything else with 421, which Deploy & scale walks through.
Closing this as part of a wider backlog cleanup around the v2 release. Feel free to reopen if this is still relevant.
Activity
ashiksharonm commentedon Jul 18, 2026
Root-caused this by checking Mangum's actual source (
mangum/adapter.py):Mangum.__call__creates a newLifespanCycleand enters/exits it on every single invocation, not just cold starts.streamable_http_app()wires the Starlettelifespantosession_manager.run(), which is documented as callable exactly once per instance. So the second invocation against a module-level globalappsends a secondlifespan.startup, which raisesRuntimeError: StreamableHTTPSessionManager.run() can only be called once per instance. This isn't Mangum-version-specific or a misconfiguration — it happens regardless ofstateless_http, since that flag doesn't change the lifespan wiring.I verified this two ways: reproduced the exact
RuntimeErrorwith a global instance across two invocations, and confirmed 3 clean invocations with the app rebuilt fresh inside the handler (your workaround is correct — and cheap, since tool registration is just in-memory bookkeeping, not I/O).Happy to open a PR adding an
examples/servers/aws-lambda-streamablehttp/example (factory function + Lambda handler + README explaining the above) if that'd be useful — let me know.(Disclosure: used Claude Code to help navigate the SDK/Mangum source and draft this; I've reviewed and verified the repro myself.)
maxisbey commentedon Jul 24, 2026
The root-cause above is right: Mangum runs the ASGI lifespan on every invocation, the app's lifespan enters
StreamableHTTPSessionManager.run(), andrun()is single-use per instance by design (regardless ofstateless_http), so a module-level app fails on the first warm invocation — building the app inside the handler is the correct pattern, not a workaround. On your 1.28 line theFastMCPinstance caches a single session manager, so a fresh instance per invocation is what you need there; on v2 (whereFastMCPis renamedMCPServer)streamable_http_app()builds a new session manager on every call, so you can keepmcp = MCPServer(...)at module scope, with tools registered once at cold start, and only callmcp.streamable_http_app()inside the handler before wrapping it inMangum. For Lambda you'll likely also wantjson_response=True(one JSON body per request instead of a held-open SSE stream) andstateless_http=True, since there's no session affinity — the transport options are listed under Running your server → Streamable HTTP. Finally, passtransport_security=with your Function URL's hostname: by defaultstreamable_http_app()arms DNS-rebinding protection with a localhost-only allowlist and answers everything else with421, which Deploy & scale walks through.Closing this as part of a wider backlog cleanup around the v2 release. Feel free to reopen if this is still relevant.
AI Disclaimer