3636 - [ Sampling] ( #sampling )
3737 - [ Logging and Notifications] ( #logging-and-notifications )
3838 - [ Authentication] ( #authentication )
39+ - [ FastMCP Properties] ( #fastmcp-properties )
40+ - [ Session Properties] ( #session-properties-and-methods )
41+ - [ Request Context Properties] ( #request-context-properties )
3942 - [ Running Your Server] ( #running-your-server )
4043 - [ Development Mode] ( #development-mode )
4144 - [ Claude Desktop Integration] ( #claude-desktop-integration )
4245 - [ Direct Execution] ( #direct-execution )
46+ - [ Streamable HTTP Transport] ( #streamable-http-transport )
4347 - [ Mounting to an Existing ASGI Server] ( #mounting-to-an-existing-asgi-server )
4448 - [ Advanced Usage] ( #advanced-usage )
4549 - [ Low-Level Server] ( #low-level-server )
4650 - [ Writing MCP Clients] ( #writing-mcp-clients )
51+ - [ Client Display Utilities] ( #client-display-utilities )
52+ - [ OAuth Authentication for Clients] ( #oauth-authentication-for-clients )
4753 - [ Parsing Tool Results] ( #parsing-tool-results )
4854 - [ MCP Primitives] ( #mcp-primitives )
4955 - [ Server Capabilities] ( #server-capabilities )
@@ -191,6 +197,7 @@ from contextlib import asynccontextmanager
191197from dataclasses import dataclass
192198
193199from mcp.server.fastmcp import Context, FastMCP
200+ from mcp.server.session import ServerSession
194201
195202
196203# Mock database class for example
@@ -236,7 +243,7 @@ mcp = FastMCP("My App", lifespan=app_lifespan)
236243
237244# Access type-safe lifespan context in tools
238245@mcp.tool ()
239- def query_db (ctx : Context) -> str :
246+ def query_db (ctx : Context[ServerSession, AppContext] ) -> str :
240247 """ Tool that uses initialized resources."""
241248 db = ctx.request_context.lifespan_context.db
242249 return db.query()
@@ -303,6 +310,36 @@ def get_weather(city: str, unit: str = "celsius") -> str:
303310_ Full example: [ examples/snippets/servers/basic_tool.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py ) _
304311<!-- /snippet-source -->
305312
313+ Tools can optionally receive a Context object by including a parameter with the ` Context ` type annotation. This context is automatically injected by the FastMCP framework and provides access to MCP capabilities:
314+
315+ <!-- snippet-source examples/snippets/servers/tool_progress.py -->
316+ ``` python
317+ from mcp.server.fastmcp import Context, FastMCP
318+ from mcp.server.session import ServerSession
319+
320+ mcp = FastMCP(name = " Progress Example" )
321+
322+
323+ @mcp.tool ()
324+ async def long_running_task (task_name : str , ctx : Context[ServerSession, None ], steps : int = 5 ) -> str :
325+ """ Execute a task with progress updates."""
326+ await ctx.info(f " Starting: { task_name} " )
327+
328+ for i in range (steps):
329+ progress = (i + 1 ) / steps
330+ await ctx.report_progress(
331+ progress = progress,
332+ total = 1.0 ,
333+ message = f " Step { i + 1 } / { steps} " ,
334+ )
335+ await ctx.debug(f " Completed step { i + 1 } " )
336+
337+ return f " Task ' { task_name} ' completed "
338+ ```
339+
340+ _ Full example: [ examples/snippets/servers/tool_progress.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py ) _
341+ <!-- /snippet-source -->
342+
306343#### Structured Output
307344
308345Tools will return structured results by default, if their return type
@@ -410,7 +447,7 @@ def get_user(user_id: str) -> UserProfile:
410447
411448# Classes WITHOUT type hints cannot be used for structured output
412449class UntypedConfig :
413- def __init__ (self , setting1 , setting2 ):
450+ def __init__ (self , setting1 , setting2 ): # type: ignore [ reportMissingParameterType ]
414451 self .setting1 = setting1
415452 self .setting2 = setting2
416453
@@ -496,17 +533,53 @@ _Full example: [examples/snippets/servers/images.py](https://github.com/modelcon
496533
497534### Context
498535
499- The Context object gives your tools and resources access to MCP capabilities:
536+ The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata.
537+
538+ #### Getting Context in Functions
539+
540+ To use context in a tool or resource function, add a parameter with the ` Context ` type annotation:
541+
542+ ``` python
543+ from mcp.server.fastmcp import Context, FastMCP
544+
545+ mcp = FastMCP(name = " Context Example" )
546+
547+
548+ @mcp.tool ()
549+ async def my_tool (x : int , ctx : Context) -> str :
550+ """ Tool that uses context capabilities."""
551+ # The context parameter can have any name as long as it's type-annotated
552+ return await process_with_context(x, ctx)
553+ ```
554+
555+ #### Context Properties and Methods
556+
557+ The Context object provides the following capabilities:
558+
559+ - ` ctx.request_id ` - Unique ID for the current request
560+ - ` ctx.client_id ` - Client ID if available
561+ - ` ctx.fastmcp ` - Access to the FastMCP server instance (see [ FastMCP Properties] ( #fastmcp-properties ) )
562+ - ` ctx.session ` - Access to the underlying session for advanced communication (see [ Session Properties and Methods] ( #session-properties-and-methods ) )
563+ - ` ctx.request_context ` - Access to request-specific data and lifespan resources (see [ Request Context Properties] ( #request-context-properties ) )
564+ - ` await ctx.debug(message) ` - Send debug log message
565+ - ` await ctx.info(message) ` - Send info log message
566+ - ` await ctx.warning(message) ` - Send warning log message
567+ - ` await ctx.error(message) ` - Send error log message
568+ - ` await ctx.log(level, message, logger_name=None) ` - Send log with custom level
569+ - ` await ctx.report_progress(progress, total=None, message=None) ` - Report operation progress
570+ - ` await ctx.read_resource(uri) ` - Read a resource by URI
571+ - ` await ctx.elicit(message, schema) ` - Request additional information from user with validation
500572
501573<!-- snippet-source examples/snippets/servers/tool_progress.py -->
502574``` python
503575from mcp.server.fastmcp import Context, FastMCP
576+ from mcp.server.session import ServerSession
504577
505578mcp = FastMCP(name = " Progress Example" )
506579
507580
508581@mcp.tool ()
509- async def long_running_task (task_name : str , ctx : Context, steps : int = 5 ) -> str :
582+ async def long_running_task (task_name : str , ctx : Context[ServerSession, None ] , steps : int = 5 ) -> str :
510583 """ Execute a task with progress updates."""
511584 await ctx.info(f " Starting: { task_name} " )
512585
@@ -624,6 +697,7 @@ Request additional information from users. This example shows an Elicitation dur
624697from pydantic import BaseModel, Field
625698
626699from mcp.server.fastmcp import Context, FastMCP
700+ from mcp.server.session import ServerSession
627701
628702mcp = FastMCP(name = " Elicitation Example" )
629703
@@ -639,12 +713,7 @@ class BookingPreferences(BaseModel):
639713
640714
641715@mcp.tool ()
642- async def book_table (
643- date : str ,
644- time : str ,
645- party_size : int ,
646- ctx : Context,
647- ) -> str :
716+ async def book_table (date : str , time : str , party_size : int , ctx : Context[ServerSession, None ]) -> str :
648717 """ Book a table with date availability check."""
649718 # Check if date is available
650719 if date == " 2024-12-25" :
@@ -680,13 +749,14 @@ Tools can interact with LLMs through sampling (generating text):
680749<!-- snippet-source examples/snippets/servers/sampling.py -->
681750``` python
682751from mcp.server.fastmcp import Context, FastMCP
752+ from mcp.server.session import ServerSession
683753from mcp.types import SamplingMessage, TextContent
684754
685755mcp = FastMCP(name = " Sampling Example" )
686756
687757
688758@mcp.tool ()
689- async def generate_poem (topic : str , ctx : Context) -> str :
759+ async def generate_poem (topic : str , ctx : Context[ServerSession, None ] ) -> str :
690760 """ Generate a poem using LLM sampling."""
691761 prompt = f " Write a short poem about { topic} "
692762
@@ -715,12 +785,13 @@ Tools can send logs and notifications through the context:
715785<!-- snippet-source examples/snippets/servers/notifications.py -->
716786``` python
717787from mcp.server.fastmcp import Context, FastMCP
788+ from mcp.server.session import ServerSession
718789
719790mcp = FastMCP(name = " Notifications Example" )
720791
721792
722793@mcp.tool ()
723- async def process_data (data : str , ctx : Context) -> str :
794+ async def process_data (data : str , ctx : Context[ServerSession, None ] ) -> str :
724795 """ Process data with logging."""
725796 # Different log levels
726797 await ctx.debug(f " Debug: Processing ' { data} ' " )
@@ -808,6 +879,99 @@ For a complete example with separate Authorization Server and Resource Server im
808879
809880See [ TokenVerifier] ( src/mcp/server/auth/provider.py ) for more details on implementing token validation.
810881
882+ ### FastMCP Properties
883+
884+ The FastMCP server instance accessible via ` ctx.fastmcp ` provides access to server configuration and metadata:
885+
886+ - ` ctx.fastmcp.name ` - The server's name as defined during initialization
887+ - ` ctx.fastmcp.instructions ` - Server instructions/description provided to clients
888+ - ` ctx.fastmcp.settings ` - Complete server configuration object containing:
889+ - ` debug ` - Debug mode flag
890+ - ` log_level ` - Current logging level
891+ - ` host ` and ` port ` - Server network configuration
892+ - ` mount_path ` , ` sse_path ` , ` streamable_http_path ` - Transport paths
893+ - ` stateless_http ` - Whether the server operates in stateless mode
894+ - And other configuration options
895+
896+ ``` python
897+ @mcp.tool ()
898+ def server_info (ctx : Context) -> dict :
899+ """ Get information about the current server."""
900+ return {
901+ " name" : ctx.fastmcp.name,
902+ " instructions" : ctx.fastmcp.instructions,
903+ " debug_mode" : ctx.fastmcp.settings.debug,
904+ " log_level" : ctx.fastmcp.settings.log_level,
905+ " host" : ctx.fastmcp.settings.host,
906+ " port" : ctx.fastmcp.settings.port,
907+ }
908+ ```
909+
910+ ### Session Properties and Methods
911+
912+ The session object accessible via ` ctx.session ` provides advanced control over client communication:
913+
914+ - ` ctx.session.client_params ` - Client initialization parameters and declared capabilities
915+ - ` await ctx.session.send_log_message(level, data, logger) ` - Send log messages with full control
916+ - ` await ctx.session.create_message(messages, max_tokens) ` - Request LLM sampling/completion
917+ - ` await ctx.session.send_progress_notification(token, progress, total, message) ` - Direct progress updates
918+ - ` await ctx.session.send_resource_updated(uri) ` - Notify clients that a specific resource changed
919+ - ` await ctx.session.send_resource_list_changed() ` - Notify clients that the resource list changed
920+ - ` await ctx.session.send_tool_list_changed() ` - Notify clients that the tool list changed
921+ - ` await ctx.session.send_prompt_list_changed() ` - Notify clients that the prompt list changed
922+
923+ ``` python
924+ @mcp.tool ()
925+ async def notify_data_update (resource_uri : str , ctx : Context) -> str :
926+ """ Update data and notify clients of the change."""
927+ # Perform data update logic here
928+
929+ # Notify clients that this specific resource changed
930+ await ctx.session.send_resource_updated(AnyUrl(resource_uri))
931+
932+ # If this affects the overall resource list, notify about that too
933+ await ctx.session.send_resource_list_changed()
934+
935+ return f " Updated { resource_uri} and notified clients "
936+ ```
937+
938+ ### Request Context Properties
939+
940+ The request context accessible via ` ctx.request_context ` contains request-specific information and resources:
941+
942+ - ` ctx.request_context.lifespan_context ` - Access to resources initialized during server startup
943+ - Database connections, configuration objects, shared services
944+ - Type-safe access to resources defined in your server's lifespan function
945+ - ` ctx.request_context.meta ` - Request metadata from the client including:
946+ - ` progressToken ` - Token for progress notifications
947+ - Other client-provided metadata
948+ - ` ctx.request_context.request ` - The original MCP request object for advanced processing
949+ - ` ctx.request_context.request_id ` - Unique identifier for this request
950+
951+ ``` python
952+ # Example with typed lifespan context
953+ @dataclass
954+ class AppContext :
955+ db: Database
956+ config: AppConfig
957+
958+ @mcp.tool ()
959+ def query_with_config (query : str , ctx : Context) -> str :
960+ """ Execute a query using shared database and configuration."""
961+ # Access typed lifespan context
962+ app_ctx: AppContext = ctx.request_context.lifespan_context
963+
964+ # Use shared resources
965+ connection = app_ctx.db
966+ settings = app_ctx.config
967+
968+ # Execute query with configuration
969+ result = connection.execute(query, timeout = settings.query_timeout)
970+ return str (result)
971+ ```
972+
973+ _ Full lifespan example: [ examples/snippets/servers/lifespan_example.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py ) _
974+
811975## Running Your Server
812976
813977### Development Mode
@@ -1081,6 +1245,7 @@ Run from the repository root:
10811245
10821246from collections.abc import AsyncIterator
10831247from contextlib import asynccontextmanager
1248+ from typing import Any
10841249
10851250import mcp.server.stdio
10861251import mcp.types as types
@@ -1109,7 +1274,7 @@ class Database:
11091274
11101275
11111276@asynccontextmanager
1112- async def server_lifespan (_server : Server) -> AsyncIterator[dict ]:
1277+ async def server_lifespan (_server : Server) -> AsyncIterator[dict[ str , Any] ]:
11131278 """ Manage server startup and shutdown lifecycle."""
11141279 # Initialize resources on startup
11151280 db = await Database.connect()
@@ -1141,7 +1306,7 @@ async def handle_list_tools() -> list[types.Tool]:
11411306
11421307
11431308@server.call_tool ()
1144- async def query_db (name : str , arguments : dict ) -> list[types.TextContent]:
1309+ async def query_db (name : str , arguments : dict[ str , Any] ) -> list[types.TextContent]:
11451310 """ Handle database query tool call."""
11461311 if name != " query_db" :
11471312 raise ValueError (f " Unknown tool: { name} " )
@@ -1395,7 +1560,7 @@ server_params = StdioServerParameters(
13951560
13961561# Optional: create a sampling callback
13971562async def handle_sampling_message (
1398- context : RequestContext, params : types.CreateMessageRequestParams
1563+ context : RequestContext[ClientSession, None ] , params : types.CreateMessageRequestParams
13991564) -> types.CreateMessageResult:
14001565 print (f " Sampling request: { params.messages} " )
14011566 return types.CreateMessageResult(
0 commit comments