Skip to content

fix: trigger lifespan events when using mount_http() (closes #256)#309

Open
Emeralden wants to merge 1 commit into
tadata-org:mainfrom
Emeralden:fix/lifespan-not-triggered-mount-http
Open

fix: trigger lifespan events when using mount_http() (closes #256)#309
Emeralden wants to merge 1 commit into
tadata-org:mainfrom
Emeralden:fix/lifespan-not-triggered-mount-http

Conversation

@Emeralden
Copy link
Copy Markdown

@Emeralden Emeralden commented May 29, 2026

When FastAPI(lifespan=...) is used, Starlette replaces the router's lifespan_context with the user's function and completely bypasses any on_startup / on_shutdown handlers registered via add_event_handler(). This caused the ASGI lifespan protocol to appear unsupported to uvicorn, silently skipping DB connections, caches, and background task setup.

Fix: wrap self.fastapi.router.lifespan_context instead of using add_event_handler(). The wrapper runs the user's startup first (so their resources are available to MCP tools), then starts the StreamableHTTP session manager, and shuts them down in reverse order.

Also add explicit startup() / shutdown() methods to FastApiHttpSessionManager so callers can integrate the session manager into their own lifecycle management if needed.

Tests: 6 new tests in tests/test_lifespan.py covering

  • lifespan startup/shutdown fires with mount_http()
  • correct startup-before-shutdown ordering
  • user resources available during HTTP requests
  • MCP /mcp endpoint reachable post-startup
  • apps without lifespan continue working
  • session manager starts after user startup

Describe your changes

When FastAPI(lifespan=...) is used, Starlette replaces the router's lifespan_context with the user's function and completely bypasses any on_startup / on_shutdown handlers registered via add_event_handler(). This caused the ASGI lifespan protocol to appear unsupported to uvicorn, silently skipping DB connections, caches, and background task setup.

Fix: wrap self.fastapi.router.lifespan_context instead of using add_event_handler(). The wrapper runs the user's startup first (so their resources are available to MCP tools), then starts the StreamableHTTP session manager, and shuts them down in reverse order.

Also add explicit startup() / shutdown() methods to FastApiHttpSessionManager so callers can integrate the session manager into their own lifecycle management if needed.

Issue ticket number and link

Closes #256

Screenshots

(No UI change. Bug fix only)

Checklist

  • Added relevant tests (6 tests in tests/test_lifespan.py)
  • Run ruff & mypy and there are no issues
  • All tests pass (89/89)

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

…rg#256)

When FastAPI(lifespan=...) is used, Starlette replaces the router's
lifespan_context with the user's function and completely bypasses any
on_startup / on_shutdown handlers registered via add_event_handler().
This caused the ASGI lifespan protocol to appear unsupported to uvicorn,
silently skipping DB connections, caches, and background task setup.

Fix: wrap self.fastapi.router.lifespan_context instead of using
add_event_handler(). The wrapper runs the user's startup first (so their
resources are available to MCP tools), then starts the StreamableHTTP
session manager, and shuts them down in reverse order.

Also add explicit startup() / shutdown() methods to
FastApiHttpSessionManager so callers can integrate the session manager
into their own lifecycle management if needed.

Tests: 6 new tests in tests/test_lifespan.py covering
- lifespan startup/shutdown fires with mount_http()
- correct startup-before-shutdown ordering
- user resources available during HTTP requests
- MCP /mcp endpoint reachable post-startup
- apps without lifespan continue working
- session manager starts after user startup
Copilot AI review requested due to automatic review settings May 29, 2026 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] lifespan context manager not triggered when using mount_http() in fastapi-mcp 0.4.0

1 participant