@@ -160,7 +160,7 @@ from dataclasses import dataclass
160160
161161from fake_database import Database # Replace with your actual DB type
162162
163- from mcp.server.fastmcp import Context, FastMCP
163+ from mcp.server.fastmcp import FastMCP
164164
165165# Create a named server
166166mcp = FastMCP(" My App" )
@@ -192,9 +192,10 @@ mcp = FastMCP("My App", lifespan=app_lifespan)
192192
193193# Access type-safe lifespan context in tools
194194@mcp.tool ()
195- def query_db (ctx : Context ) -> str :
195+ def query_db () -> str :
196196 """ Tool that uses initialized resources"""
197- db = ctx.request_context.lifespan_context.db
197+ ctx = mcp.get_context()
198+ db = ctx.request_context.lifespan_context[" db" ]
198199 return db.query()
199200```
200201
@@ -314,27 +315,42 @@ async def long_task(files: list[str], ctx: Context) -> str:
314315Authentication can be used by servers that want to expose tools accessing protected resources.
315316
316317` mcp.server.auth ` implements an OAuth 2.0 server interface, which servers can use by
317- providing an implementation of the ` OAuthServerProvider ` protocol.
318+ providing an implementation of the ` OAuthAuthorizationServerProvider ` protocol.
318319
319- ```
320- mcp = FastMCP("My App",
321- auth_provider=MyOAuthServerProvider(),
322- auth=AuthSettings(
323- issuer_url="https://myapp.com",
324- revocation_options=RevocationOptions(
325- enabled=True,
326- ),
327- client_registration_options=ClientRegistrationOptions(
328- enabled=True,
329- valid_scopes=["myscope", "myotherscope"],
330- default_scopes=["myscope"],
331- ),
332- required_scopes=["myscope"],
320+ ``` python
321+ from mcp import FastMCP
322+ from mcp.server.auth.provider import OAuthAuthorizationServerProvider
323+ from mcp.server.auth.settings import (
324+ AuthSettings,
325+ ClientRegistrationOptions,
326+ RevocationOptions,
327+ )
328+
329+
330+ class MyOAuthServerProvider (OAuthAuthorizationServerProvider ):
331+ # See an example on how to implement at `examples/servers/simple-auth`
332+ ...
333+
334+
335+ mcp = FastMCP(
336+ " My App" ,
337+ auth_server_provider = MyOAuthServerProvider(),
338+ auth = AuthSettings(
339+ issuer_url = " https://myapp.com" ,
340+ revocation_options = RevocationOptions(
341+ enabled = True ,
333342 ),
343+ client_registration_options = ClientRegistrationOptions(
344+ enabled = True ,
345+ valid_scopes = [" myscope" , " myotherscope" ],
346+ default_scopes = [" myscope" ],
347+ ),
348+ required_scopes = [" myscope" ],
349+ ),
334350)
335351```
336352
337- See [ OAuthServerProvider ] ( src/mcp/server/auth/provider.py ) for more details.
353+ See [ OAuthAuthorizationServerProvider ] ( src/mcp/server/auth/provider.py ) for more details.
338354
339355## Running Your Server
340356
@@ -387,6 +403,8 @@ python server.py
387403mcp run server.py
388404```
389405
406+ Note that ` mcp run ` or ` mcp dev ` only supports server using FastMCP and not the low-level server variant.
407+
390408### Streamable HTTP Transport
391409
392410> ** Note** : Streamable HTTP transport is superseding SSE transport for production deployments.
@@ -400,6 +418,9 @@ mcp = FastMCP("StatefulServer")
400418# Stateless server (no session persistence)
401419mcp = FastMCP(" StatelessServer" , stateless_http = True )
402420
421+ # Stateless server (no session persistence, no sse stream with supported client)
422+ mcp = FastMCP(" StatelessServer" , stateless_http = True , json_response = True )
423+
403424# Run server with streamable_http transport
404425mcp.run(transport = " streamable-http" )
405426```
@@ -426,21 +447,28 @@ mcp = FastMCP(name="MathServer", stateless_http=True)
426447
427448
428449@mcp.tool (description = " A simple add tool" )
429- def add_two (n : int ) -> str :
450+ def add_two (n : int ) -> int :
430451 return n + 2
431452```
432453
433454``` python
434455# main.py
456+ import contextlib
435457from fastapi import FastAPI
436458from mcp.echo import echo
437459from mcp.math import math
438460
439461
440- app = FastAPI()
462+ # Create a combined lifespan to manage both session managers
463+ @contextlib.asynccontextmanager
464+ async def lifespan (app : FastAPI):
465+ async with contextlib.AsyncExitStack() as stack:
466+ await stack.enter_async_context(echo.mcp.session_manager.run())
467+ await stack.enter_async_context(math.mcp.session_manager.run())
468+ yield
441469
442- # Use the session manager's lifespan
443- app = FastAPI(lifespan = lambda app : echo.mcp.session_manager.run() )
470+
471+ app = FastAPI(lifespan = lifespan )
444472app.mount(" /echo" , echo.mcp.streamable_http_app())
445473app.mount(" /math" , math.mcp.streamable_http_app())
446474```
@@ -449,19 +477,18 @@ For low level server with Streamable HTTP implementations, see:
449477- Stateful server: [ ` examples/servers/simple-streamablehttp/ ` ] ( examples/servers/simple-streamablehttp/ )
450478- Stateless server: [ ` examples/servers/simple-streamablehttp-stateless/ ` ] ( examples/servers/simple-streamablehttp-stateless/ )
451479
452-
453-
454480The streamable HTTP transport supports:
455481- Stateful and stateless operation modes
456482- Resumability with event stores
457- - JSON or SSE response formats
483+ - JSON or SSE response formats
458484- Better scalability for multi-node deployments
459485
460-
461486### Mounting to an Existing ASGI Server
462487
463488> ** Note** : SSE transport is being superseded by [ Streamable HTTP transport] ( https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http ) .
464489
490+ By default, SSE servers are mounted at ` /sse ` and Streamable HTTP servers are mounted at ` /mcp ` . You can customize these paths using the methods described below.
491+
465492You can mount the SSE server to an existing ASGI server using the ` sse_app ` method. This allows you to integrate the SSE server with other ASGI applications.
466493
467494``` python
@@ -692,6 +719,8 @@ if __name__ == "__main__":
692719 asyncio.run(run())
693720```
694721
722+ Caution: The ` mcp run ` and ` mcp dev ` tool doesn't support low-level server.
723+
695724### Writing MCP Clients
696725
697726The SDK provides a high-level client interface for connecting to MCP servers using various [ transports] ( https://modelcontextprotocol.io/specification/2025-03-26/basic/transports ) :
@@ -780,6 +809,60 @@ async def main():
780809 tool_result = await session.call_tool(" echo" , {" message" : " hello" })
781810```
782811
812+ ### OAuth Authentication for Clients
813+
814+ The SDK includes [ authorization support] ( https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization ) for connecting to protected MCP servers:
815+
816+ ``` python
817+ from mcp.client.auth import OAuthClientProvider, TokenStorage
818+ from mcp.client.session import ClientSession
819+ from mcp.client.streamable_http import streamablehttp_client
820+ from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
821+
822+
823+ class CustomTokenStorage (TokenStorage ):
824+ """ Simple in-memory token storage implementation."""
825+
826+ async def get_tokens (self ) -> OAuthToken | None :
827+ pass
828+
829+ async def set_tokens (self , tokens : OAuthToken) -> None :
830+ pass
831+
832+ async def get_client_info (self ) -> OAuthClientInformationFull | None :
833+ pass
834+
835+ async def set_client_info (self , client_info : OAuthClientInformationFull) -> None :
836+ pass
837+
838+
839+ async def main ():
840+ # Set up OAuth authentication
841+ oauth_auth = OAuthClientProvider(
842+ server_url = " https://api.example.com" ,
843+ client_metadata = OAuthClientMetadata(
844+ client_name = " My Client" ,
845+ redirect_uris = [" http://localhost:3000/callback" ],
846+ grant_types = [" authorization_code" , " refresh_token" ],
847+ response_types = [" code" ],
848+ ),
849+ storage = CustomTokenStorage(),
850+ redirect_handler = lambda url : print (f " Visit: { url} " ),
851+ callback_handler = lambda : (" auth_code" , None ),
852+ )
853+
854+ # Use with streamable HTTP client
855+ async with streamablehttp_client(
856+ " https://api.example.com/mcp" , auth = oauth_auth
857+ ) as (read, write, _):
858+ async with ClientSession(read, write) as session:
859+ await session.initialize()
860+ # Authenticated session ready
861+ ```
862+
863+ For a complete working example, see [ ` examples/clients/simple-auth-client/ ` ] ( examples/clients/simple-auth-client/ ) .
864+
865+
783866### MCP Primitives
784867
785868The MCP protocol defines three core primitives that servers can implement:
0 commit comments