Skip to content

Add OAuth authentication client for HTTPX #751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
May 19, 2025
85 changes: 85 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,91 @@ async def main():
tool_result = await session.call_tool("echo", {"message": "hello"})
```

### OAuth Authentication for Clients

The SDK supports OAuth 2.0 client authentication for secure access to MCP servers that require authentication:

```python
from mcp.client.auth import UnauthorizedError
from mcp.client.oauth_providers import InMemoryOAuthProvider
from mcp.client.streamable_http import streamablehttp_client
from mcp.shared.auth import OAuthClientMetadata
from mcp import ClientSession

# Create an OAuth provider
oauth_provider = InMemoryOAuthProvider(
redirect_url="http://localhost:8080/callback",
client_metadata=OAuthClientMetadata(
redirect_uris=["http://localhost:8080/callback"],
client_name="My MCP Client",
scope="tools resources", # Request specific scopes
),
)


async def main():
# Connect with OAuth authentication
async with streamablehttp_client(
"https://example.com/mcp",
auth_provider=oauth_provider,
) as (read_stream, write_stream, _):
# Create a session
async with ClientSession(read_stream, write_stream) as session:
# Initialize (this may trigger OAuth flow)
try:
await session.initialize()
# Use authenticated session
result = await session.call_tool("protected_tool", {"arg": "value"})
except UnauthorizedError:
# Handle authorization required
print("Authorization required. Check your browser.")


# Handle OAuth callback after user authorization
async def handle_callback(authorization_code: str):
from mcp.client.streamable_http import StreamableHTTPTransport

# Create a transport instance to handle auth completion
transport = StreamableHTTPTransport(
url="https://example.com/mcp",
auth_provider=oauth_provider,
)

# Exchange authorization code for tokens
await transport.finish_auth(authorization_code)
print("Authorization successful!")
```

#### Custom OAuth Providers

You can implement custom OAuth storage by creating your own provider:

```python
from mcp.client.oauth_providers import InMemoryOAuthProvider


class DatabaseOAuthProvider(InMemoryOAuthProvider):
async def save_tokens(self, tokens):
# Save to database
# await db.save_tokens(self.client_id, tokens)
pass

async def tokens(self):
# Load from database
# return await db.load_tokens(self.client_id)
return None

# Implement other methods as needed...
```

The OAuth client implementation supports:

- Dynamic client registration
- Authorization code flow with PKCE
- Token refresh
- Multiple storage providers (in-memory and file-based included)
- Automatic token management and retry logic

### MCP Primitives

The MCP protocol defines three core primitives that servers can implement:
Expand Down
70 changes: 70 additions & 0 deletions examples/clients/simple-auth-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Simple Auth Client Example

A demonstration of how to use the MCP Python SDK with OAuth authentication over streamable HTTP transport.

## Features

- OAuth 2.0 authentication with PKCE
- Streamable HTTP transport
- Interactive command-line interface

## Installation

```bash
cd examples/clients/simple-auth-client
uv sync --reinstall
```

## Usage

### 1. Start an MCP server with OAuth support

```bash
# Example with mcp-simple-auth
cd path/to/mcp-simple-auth
uv run mcp-simple-auth --transport streamable-http --port 3001
```

### 2. Run the client

```bash
uv run mcp-simple-auth-client

# Or with custom server URL
MCP_SERVER_URL=http://localhost:3001 uv run mcp-simple-auth-client
```

### 3. Complete OAuth flow

The client will open your browser for authentication. After completing OAuth, you can use commands:

- `list` - List available tools
- `call <tool_name> [args]` - Call a tool with optional JSON arguments
- `quit` - Exit

## Example

```
🔐 Simple MCP Auth Client
Connecting to: http://localhost:3001

Please visit the following URL to authorize the application:
http://localhost:3001/authorize?response_type=code&client_id=...

✅ Connected to MCP server at http://localhost:3001

mcp> list
📋 Available tools:
1. echo - Echo back the input text

mcp> call echo {"text": "Hello, world!"}
🔧 Tool 'echo' result:
Hello, world!

mcp> quit
👋 Goodbye!
```

## Configuration

- `MCP_SERVER_URL` - Server URL (default: http://localhost:3001)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Simple OAuth client for MCP simple-auth server."""
Loading
Loading