diff --git a/samples/README.md b/samples/README.md index 5ebec43..a509203 100644 --- a/samples/README.md +++ b/samples/README.md @@ -6,16 +6,36 @@ See [the documentation](https://mcp-auth.dev/docs) for the full guide. ## Prerequisites +### Virtual environment setup + +First, navigate to the project root directory and set up a virtual environment: + +```bash +# Navigate to the project root directory (one level up from samples) +cd .. + +# Create a new virtual environment using uv +uv venv + +# Activate the virtual environment (optional when using 'uv run') +source .venv/bin/activate +``` + ### Install dependencies -First, install the required dependencies: +Install the required dependencies using uv: ```bash -# Install production dependencies -pip install -e . +# Make sure you are in the project root directory (where pyproject.toml is located) +# Install the project in development mode +uv pip install -e . # Install development dependencies (optional, for development and testing) -pip install -e ".[dev]" +uv pip install -e ".[dev]" + +# Alternative: Traditional pip method (after activating virtual environment) +# pip install -e . +# pip install -e ".[dev]" ``` ### Environment setup @@ -27,7 +47,7 @@ Set up the required environment variable: export MCP_AUTH_ISSUER= ``` -## Directory Structure +## Directory structure - `current/`: Latest sample implementations (MCP server as resource server) - `v0_1_1/`: Legacy sample implementations (MCP server as authorization server) @@ -48,8 +68,8 @@ To run the Todo Manager server: # Make sure you are in the samples directory first cd samples -# Start the Todo Manager server -uvicorn current.todo-manager.server:app --host 0.0.0.0 --port 3001 +# Start the Todo Manager server using uv +uv run uvicorn current.todo-manager.server:app --host 127.0.0.1 --port 3001 ``` ## Legacy examples (v0.1.1) @@ -63,12 +83,13 @@ A simple server that demonstrates basic authentication. It provides a single too - `whoami`: Returns the authenticated user's information To run the WhoAmI server: + ```bash # Make sure you are in the samples directory first cd samples -# Start the WhoAmI server -uvicorn v0_1_1.whoami:app --host 0.0.0.0 --port 3001 +# Start the WhoAmI server using uv +uv run uvicorn v0_1_1.whoami:app --host 127.0.0.1 --port 3001 ``` ### Todo Manager MCP server (legacy) @@ -80,10 +101,11 @@ Legacy version of the todo manager that acts as both authorization and resource - `delete-todo`: Delete a todo (requires `delete:todos` scope for others' todos) To run the legacy Todo Manager server: + ```bash # Make sure you are in the samples directory first cd samples -# Start the legacy Todo Manager server -uvicorn v0_1_1.todo-manager.server:app --host 0.0.0.0 --port 3001 +# Start the legacy Todo Manager server using uv +uv run uvicorn v0_1_1.todo-manager.server:app --host 127.0.0.1 --port 3001 ``` diff --git a/samples/current/todo-manager/server.py b/samples/current/todo-manager/server.py index 653c356..b128d7f 100644 --- a/samples/current/todo-manager/server.py +++ b/samples/current/todo-manager/server.py @@ -12,6 +12,8 @@ """ import os +import contextlib + from typing import Any, List, Optional from mcp.server.fastmcp import FastMCP from starlette.applications import Starlette @@ -29,7 +31,7 @@ from .service import TodoService # Initialize the FastMCP server -mcp = FastMCP("Todo Manager") +mcp = FastMCP(name="Todo Manager", stateless_http=True) # Initialize the todo service todo_service = TodoService() @@ -44,7 +46,7 @@ ) auth_server_config = fetch_server_config(auth_issuer, AuthServerType.OIDC) -resource_id = "http://localhost:3001" +resource_id = "http://localhost:3001/mcp" mcp_auth = MCPAuth( protected_resources=[ ResourceServerConfig( @@ -136,12 +138,19 @@ def delete_todo(id: str) -> dict[str, Any]: else: return {"error": "Failed to delete todo"} +@contextlib.asynccontextmanager +async def lifespan(app: Starlette): + async with contextlib.AsyncExitStack() as stack: + await stack.enter_async_context(mcp.session_manager.run()) + yield + # Create the middleware and app bearer_auth = Middleware(mcp_auth.bearer_auth_middleware('jwt', resource=resource_id)) app = Starlette( routes=[ # Protect the MCP server with the Bearer auth middleware *mcp_auth.resource_metadata_router().routes, - Mount("/", app=mcp.sse_app(), middleware=[bearer_auth]), + Mount("/", app=mcp.streamable_http_app(), middleware=[bearer_auth]), ], + lifespan=lifespan, )