Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,7 +47,7 @@ Set up the required environment variable:
export MCP_AUTH_ISSUER=<your_auth_issuer_url>
```

## Directory Structure
## Directory structure

- `current/`: Latest sample implementations (MCP server as resource server)
- `v0_1_1/`: Legacy sample implementations (MCP server as authorization server)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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
```
15 changes: 12 additions & 3 deletions samples/current/todo-manager/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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(
Expand Down Expand Up @@ -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,
)