@@ -128,13 +128,41 @@ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you bui
128128The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
129129
130130``` python
131+ # Add lifespan support for startup/shutdown with strong typing
132+ from dataclasses import dataclass
133+ from typing import AsyncIterator
131134from mcp.server.fastmcp import FastMCP
132135
133136# Create a named server
134137mcp = FastMCP(" My App" )
135138
136139# Specify dependencies for deployment and development
137140mcp = FastMCP(" My App" , dependencies = [" pandas" , " numpy" ])
141+
142+ @dataclass
143+ class AppContext :
144+ db: Database # Replace with your actual DB type
145+
146+ @asynccontextmanager
147+ async def app_lifespan (server : FastMCP) -> AsyncIterator[AppContext]:
148+ """ Manage application lifecycle with type-safe context"""
149+ try :
150+ # Initialize on startup
151+ await db.connect()
152+ yield AppContext(db = db)
153+ finally :
154+ # Cleanup on shutdown
155+ await db.disconnect()
156+
157+ # Pass lifespan to server
158+ mcp = FastMCP(" My App" , lifespan = app_lifespan)
159+
160+ # Access type-safe lifespan context in tools
161+ @mcp.tool ()
162+ def query_db (ctx : Context) -> str :
163+ """ Tool that uses initialized resources"""
164+ db = ctx.request_context.lifespan_context[" db" ]
165+ return db.query()
138166```
139167
140168### Resources
@@ -334,7 +362,38 @@ def query_data(sql: str) -> str:
334362
335363### Low-Level Server
336364
337- For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server:
365+ For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server, including lifecycle management through the lifespan API:
366+
367+ ``` python
368+ from contextlib import asynccontextmanager
369+ from typing import AsyncIterator
370+
371+ @asynccontextmanager
372+ async def server_lifespan (server : Server) -> AsyncIterator[dict ]:
373+ """ Manage server startup and shutdown lifecycle."""
374+ try :
375+ # Initialize resources on startup
376+ await db.connect()
377+ yield {" db" : db}
378+ finally :
379+ # Clean up on shutdown
380+ await db.disconnect()
381+
382+ # Pass lifespan to server
383+ server = Server(" example-server" , lifespan = server_lifespan)
384+
385+ # Access lifespan context in handlers
386+ @server.call_tool ()
387+ async def query_db (name : str , arguments : dict ) -> list :
388+ ctx = server.request_context
389+ db = ctx.lifespan_context[" db" ]
390+ return await db.query(arguments[" query" ])
391+ ```
392+
393+ The lifespan API provides:
394+ - A way to initialize resources when the server starts and clean them up when it stops
395+ - Access to initialized resources through the request context in handlers
396+ - Type-safe context passing between lifespan and request handlers
338397
339398``` python
340399from mcp.server.lowlevel import Server, NotificationOptions
@@ -417,9 +476,21 @@ server_params = StdioServerParameters(
417476 env = None # Optional environment variables
418477)
419478
479+ # Optional: create a sampling callback
480+ async def handle_sampling_message (message : types.CreateMessageRequestParams) -> types.CreateMessageResult:
481+ return types.CreateMessageResult(
482+ role = " assistant" ,
483+ content = types.TextContent(
484+ type = " text" ,
485+ text = " Hello, world! from model" ,
486+ ),
487+ model = " gpt-3.5-turbo" ,
488+ stopReason = " endTurn" ,
489+ )
490+
420491async def run ():
421492 async with stdio_client(server_params) as (read, write):
422- async with ClientSession(read, write) as session:
493+ async with ClientSession(read, write, sampling_callback = handle_sampling_message ) as session:
423494 # Initialize the connection
424495 await session.initialize()
425496
0 commit comments