> ## Documentation Index

> Fetch the complete documentation index at: /llms.txt

> Use this file to discover all available pages before exploring further.

Skip to main content
Extensibility

# Lifespans

Server-level setup and teardown with composable lifespans

New in version `3.0.0` Lifespans let you run code once when the server starts and clean up when it stops. Unlike per-session handlers, lifespans run exactly once regardless of how many clients connect.

##
​
Basic Usage

Use the `@lifespan` decorator to define a lifespan:

    from fastmcp import FastMCP
    from fastmcp.server.lifespan import lifespan

    @lifespan
    async def app_lifespan(server):
        # Setup: runs once when server starts
        print("Starting up...")
        try:
            yield {"started_at": "2024-01-01"}
        finally:
            # Teardown: runs when server stops
            print("Shutting down...")

    mcp = FastMCP("MyServer", lifespan=app_lifespan)

The dict you yield becomes the lifespan context, accessible from tools.
Always use `try/finally` for cleanup code to ensure it runs even if the server is cancelled.

##
​
Accessing Lifespan Context

Access the lifespan context in tools via `ctx.lifespan_context`:

    from fastmcp import FastMCP, Context
    from fastmcp.server.lifespan import lifespan

    @lifespan
    async def app_lifespan(server):
        # Initialize shared state
        data = {"users": ["alice", "bob"]}
        yield {"data": data}

    mcp = FastMCP("MyServer", lifespan=app_lifespan)

    @mcp.tool
    def list_users(ctx: Context) -> list[str]:
        data = ctx.lifespan_context["data"]
        return data["users"]

##
​
Composing Lifespans

Compose multiple lifespans with the `|` operator:

    from fastmcp import FastMCP
    from fastmcp.server.lifespan import lifespan

    @lifespan
    async def config_lifespan(server):
        config = {"debug": True, "version": "1.0"}
        yield {"config": config}

    @lifespan
    async def data_lifespan(server):
        data = {"items": []}
        yield {"data": data}

    # Compose with |
    mcp = FastMCP("MyServer", lifespan=config_lifespan | data_lifespan)

Composed lifespans:

- Enter in order (left to right)
- Exit in reverse order (right to left)
- Merge their context dicts (later values overwrite earlier on conflict)

##
​
Backwards Compatibility

Existing `@asynccontextmanager` lifespans still work when passed directly to FastMCP:

    from contextlib import asynccontextmanager
    from fastmcp import FastMCP

    @asynccontextmanager
    async def legacy_lifespan(server):
        yield {"key": "value"}

    mcp = FastMCP("MyServer", lifespan=legacy_lifespan)

To compose an `@asynccontextmanager` function with `@lifespan` functions, wrap it with `ContextManagerLifespan`:

    from contextlib import asynccontextmanager
    from fastmcp.server.lifespan import lifespan, ContextManagerLifespan

    @asynccontextmanager
    async def legacy_lifespan(server):
        yield {"legacy": True}

    @lifespan
    async def new_lifespan(server):
        yield {"new": True}

    # Wrap the legacy lifespan explicitly for composition
    combined = ContextManagerLifespan(legacy_lifespan) | new_lifespan

##
​
With FastAPI

When mounting FastMCP into FastAPI, use `combine_lifespans` to run both your app’s lifespan and the MCP server’s lifespan:

    from contextlib import asynccontextmanager

    from fastapi import FastAPI
    from fastmcp import FastMCP
    from fastmcp.utilities.lifespan import combine_lifespans

    @asynccontextmanager
    async def app_lifespan(app):
        print("FastAPI starting...")
        yield
        print("FastAPI shutting down...")

    mcp = FastMCP("Tools")
    mcp_app = mcp.http_app()

    app = FastAPI(lifespan=combine_lifespans(app_lifespan, mcp_app.lifespan))
    app.mount("/mcp", mcp_app)

See the FastAPI integration guide for full details.
Dependency Injection
Previous
Storage Backends
Next
Ctrl+I
Assistant
Responses are generated using AI and may contain mistakes.
\n\n
\n
\n \n
\n
","contacts":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","dashboard":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","data-table":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","hitchhikers":" \n
\n\n Prefab Showcase\n \n \n \n \n\n
\n
\n \n
\n
","pie-chart":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory-reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
"};