Skip to content

Commit 76a5f81

Browse files
authored
Merge branch 'main' into subprocess_kill_win32
2 parents f85dc16 + 5441767 commit 76a5f81

File tree

48 files changed

+4664
-901
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+4664
-901
lines changed

.github/workflows/publish-docs-manually.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
uses: astral-sh/setup-uv@v3
2020
with:
2121
enable-cache: true
22+
version: 0.7.2
2223

2324
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
2425
- uses: actions/cache@v4

.github/workflows/publish-pypi.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
uses: astral-sh/setup-uv@v3
1717
with:
1818
enable-cache: true
19+
version: 0.7.2
1920

2021
- name: Set up Python 3.12
2122
run: uv python install 3.12
@@ -67,6 +68,7 @@ jobs:
6768
uses: astral-sh/setup-uv@v3
6869
with:
6970
enable-cache: true
71+
version: 0.7.2
7072

7173
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
7274
- uses: actions/cache@v4

.github/workflows/shared.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
uses: astral-sh/setup-uv@v3
1414
with:
1515
enable-cache: true
16+
version: 0.7.2
1617

1718
- name: Install the project
1819
run: uv sync --frozen --all-extras --dev --python 3.12
@@ -29,6 +30,7 @@ jobs:
2930
uses: astral-sh/setup-uv@v3
3031
with:
3132
enable-cache: true
33+
version: 0.7.2
3234

3335
- name: Install the project
3436
run: uv sync --frozen --all-extras --dev --python 3.12
@@ -50,6 +52,7 @@ jobs:
5052
uses: astral-sh/setup-uv@v3
5153
with:
5254
enable-cache: true
55+
version: 0.7.2
5356

5457
- name: Install the project
5558
run: uv sync --frozen --all-extras --dev --python ${{ matrix.python-version }}

README.md

Lines changed: 91 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ from dataclasses import dataclass
160160

161161
from 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
166166
mcp = 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:
314315
Authentication 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_server_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,
342+
),
343+
client_registration_options=ClientRegistrationOptions(
344+
enabled=True,
345+
valid_scopes=["myscope", "myotherscope"],
346+
default_scopes=["myscope"],
333347
),
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

@@ -461,15 +477,12 @@ For low level server with Streamable HTTP implementations, see:
461477
- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/)
462478
- Stateless server: [`examples/servers/simple-streamablehttp-stateless/`](examples/servers/simple-streamablehttp-stateless/)
463479

464-
465-
466480
The streamable HTTP transport supports:
467481
- Stateful and stateless operation modes
468482
- Resumability with event stores
469-
- JSON or SSE response formats
483+
- JSON or SSE response formats
470484
- Better scalability for multi-node deployments
471485

472-
473486
### Mounting to an Existing ASGI Server
474487

475488
> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http).
@@ -631,7 +644,7 @@ server = Server("example-server", lifespan=server_lifespan)
631644
# Access lifespan context in handlers
632645
@server.call_tool()
633646
async def query_db(name: str, arguments: dict) -> list:
634-
ctx = server.get_context()
647+
ctx = server.request_context
635648
db = ctx.lifespan_context["db"]
636649
return await db.query(arguments["query"])
637650
```
@@ -796,6 +809,60 @@ async def main():
796809
tool_result = await session.call_tool("echo", {"message": "hello"})
797810
```
798811

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+
799866
### MCP Primitives
800867

801868
The MCP protocol defines three core primitives that servers can implement:
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Simple Auth Client Example
2+
3+
A demonstration of how to use the MCP Python SDK with OAuth authentication over streamable HTTP or SSE transport.
4+
5+
## Features
6+
7+
- OAuth 2.0 authentication with PKCE
8+
- Support for both StreamableHTTP and SSE transports
9+
- Interactive command-line interface
10+
11+
## Installation
12+
13+
```bash
14+
cd examples/clients/simple-auth-client
15+
uv sync --reinstall
16+
```
17+
18+
## Usage
19+
20+
### 1. Start an MCP server with OAuth support
21+
22+
```bash
23+
# Example with mcp-simple-auth
24+
cd path/to/mcp-simple-auth
25+
uv run mcp-simple-auth --transport streamable-http --port 3001
26+
```
27+
28+
### 2. Run the client
29+
30+
```bash
31+
uv run mcp-simple-auth-client
32+
33+
# Or with custom server URL
34+
MCP_SERVER_PORT=3001 uv run mcp-simple-auth-client
35+
36+
# Use SSE transport
37+
MCP_TRANSPORT_TYPE=sse uv run mcp-simple-auth-client
38+
```
39+
40+
### 3. Complete OAuth flow
41+
42+
The client will open your browser for authentication. After completing OAuth, you can use commands:
43+
44+
- `list` - List available tools
45+
- `call <tool_name> [args]` - Call a tool with optional JSON arguments
46+
- `quit` - Exit
47+
48+
## Example
49+
50+
```
51+
🔐 Simple MCP Auth Client
52+
Connecting to: http://localhost:3001
53+
54+
Please visit the following URL to authorize the application:
55+
http://localhost:3001/authorize?response_type=code&client_id=...
56+
57+
✅ Connected to MCP server at http://localhost:3001
58+
59+
mcp> list
60+
📋 Available tools:
61+
1. echo - Echo back the input text
62+
63+
mcp> call echo {"text": "Hello, world!"}
64+
🔧 Tool 'echo' result:
65+
Hello, world!
66+
67+
mcp> quit
68+
👋 Goodbye!
69+
```
70+
71+
## Configuration
72+
73+
- `MCP_SERVER_PORT` - Server URL (default: 8000)
74+
- `MCP_TRANSPORT_TYPE` - Transport type: `streamable_http` (default) or `sse`
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Simple OAuth client for MCP simple-auth server."""

0 commit comments

Comments
 (0)