Skip to content

Commit 2d8a1eb

Browse files
committed
feat: add lifespan support to FastMCP server
Adds support for the lifespan API to FastMCP server, enabling: - Simple setup with FastMCP constructor - Type-safe context passing to tools and handlers - Configuration via Settings class 🤖 Generated with Claude CLI. Co-Authored-By: Claude <[email protected]>
1 parent 380883b commit 2d8a1eb

File tree

1 file changed

+40
-4
lines changed

1 file changed

+40
-4
lines changed

Diff for: src/mcp/server/fastmcp/server.py

+40-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
import inspect
44
import json
55
import re
6+
from collections.abc import AsyncIterator
7+
from contextlib import (
8+
AbstractAsyncContextManager,
9+
asynccontextmanager,
10+
)
611
from itertools import chain
7-
from typing import Any, Callable, Literal, Sequence
12+
from typing import Any, Callable, Generic, Literal, Sequence
813

914
import anyio
1015
import pydantic_core
@@ -19,8 +24,16 @@
1924
from mcp.server.fastmcp.tools import ToolManager
2025
from mcp.server.fastmcp.utilities.logging import configure_logging, get_logger
2126
from mcp.server.fastmcp.utilities.types import Image
22-
from mcp.server.lowlevel import Server as MCPServer
2327
from mcp.server.lowlevel.helper_types import ReadResourceContents
28+
from mcp.server.lowlevel.server import (
29+
LifespanResultT,
30+
)
31+
from mcp.server.lowlevel.server import (
32+
Server as MCPServer,
33+
)
34+
from mcp.server.lowlevel.server import (
35+
lifespan as default_lifespan,
36+
)
2437
from mcp.server.sse import SseServerTransport
2538
from mcp.server.stdio import stdio_server
2639
from mcp.shared.context import RequestContext
@@ -50,7 +63,7 @@
5063
logger = get_logger(__name__)
5164

5265

53-
class Settings(BaseSettings):
66+
class Settings(BaseSettings, Generic[LifespanResultT]):
5467
"""FastMCP server settings.
5568
5669
All settings can be configured via environment variables with the prefix FASTMCP_.
@@ -85,13 +98,36 @@ class Settings(BaseSettings):
8598
description="List of dependencies to install in the server environment",
8699
)
87100

101+
lifespan: (
102+
Callable[["FastMCP"], AbstractAsyncContextManager[LifespanResultT]] | None
103+
) = Field(None, description="Lifespan contexte manager")
104+
105+
106+
def lifespan_wrapper(
107+
app: "FastMCP",
108+
lifespan: Callable[["FastMCP"], AbstractAsyncContextManager[LifespanResultT]],
109+
) -> Callable[[MCPServer], AbstractAsyncContextManager[object]]:
110+
@asynccontextmanager
111+
async def wrap(s: MCPServer) -> AsyncIterator[object]:
112+
async with lifespan(app) as context:
113+
yield context
114+
115+
return wrap
116+
88117

89118
class FastMCP:
90119
def __init__(
91120
self, name: str | None = None, instructions: str | None = None, **settings: Any
92121
):
93122
self.settings = Settings(**settings)
94-
self._mcp_server = MCPServer(name=name or "FastMCP", instructions=instructions)
123+
124+
self._mcp_server = MCPServer(
125+
name=name or "FastMCP",
126+
instructions=instructions,
127+
lifespan=lifespan_wrapper(self, self.settings.lifespan)
128+
if self.settings.lifespan
129+
else default_lifespan,
130+
)
95131
self._tool_manager = ToolManager(
96132
warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools
97133
)

0 commit comments

Comments
 (0)