arcade-mcp/libs/arcade-mcp-server/docs/examples/07_auth.md
Eric Gustin a11f79b32d
Update arcade-mcp-server docs (#597)
1. Updates docs to prefer `uv run server.py` instead of `arcade mcp` or
`python -m arcade_mcp_server`
2. Found a bug with running stdio servers while updating the docs, so i
snuck that in this PR
2025-10-02 17:16:38 -07:00

123 lines
3.4 KiB
Markdown

# 07 - OAuth Tools
Learn how to create tools that require OAuth
## Prerequisites
Before running this example, you need to authenticate with Arcade:
```bash
# Install the Arcade CLI (if not already installed)
uv pip install arcade-mcp
# Login to Arcade
arcade login
```
## Running the Example
- **Run HTTP**: `uv run examples/07_auth.py`
- **Run stdio**: `uv run examples/07_auth.py stdio`
## Source Code
```python
--8<-- "docs/examples/07_auth.py"
```
## OAuth Authentication Features
### 1. Requiring Authentication
Use the `requires_auth` parameter with an auth provider to require OAuth:
```python
from arcade_mcp_server.auth import Reddit
@app.tool(requires_auth=Reddit(scopes=["read"]))
async def get_posts_in_subreddit(
context: Context,
subreddit: Annotated[str, "The name of the subreddit"]
) -> dict:
"""Get posts from a specific subreddit."""
# OAuth token is automatically injected into context
oauth_token = context.get_auth_token_or_empty()
# Use the token to make authenticated API requests
```
### 2. Specifying OAuth Scopes
Different tools may require different scopes:
```python
# Read-only access
@app.tool(requires_auth=Reddit(scopes=["read"]))
async def read_only_tool(context: Context) -> dict:
"""Tool that only reads data."""
pass
# Multiple scopes for more permissions
@app.tool(requires_auth=Reddit(scopes=["read", "identity"]))
async def identity_tool(context: Context) -> dict:
"""Tool that accesses user identity."""
pass
```
### 3. Accessing OAuth Tokens
OAuth tokens are securely injected into the context at runtime:
```python
# Get the token (returns empty string if not authenticated)
oauth_token = context.get_auth_token_or_empty()
# Use token in API requests
headers = {
"Authorization": f"Bearer {oauth_token}",
"User-Agent": "my-app",
}
```
### 4. Making Authenticated API Requests
Use the OAuth token with httpx or other HTTP clients:
```python
import httpx
async with httpx.AsyncClient() as client:
response = await client.get(
"https://oauth.reddit.com/api/endpoint",
headers={"Authorization": f"Bearer {oauth_token}"}
)
response.raise_for_status()
return response.json()
```
## Available Auth Providers
The `arcade_mcp_server.auth` module provides several OAuth providers:
## Authentication Flow
1. **User runs `arcade login`**: Authenticates with Arcade and stores credentials
2. **Tool is called**: MCP client calls a tool that requires authentication
3. **Authorization Required**: If the user has not authorized the required scopes, then they are prompted to go through an OAuth flow
3. **Token injection**: Arcade injects the OAuth token into the tool's context
4. **API request**: Tool uses the token to make authenticated API requests
5. **Response**: Tool returns data to the MCP client
The LLM and MCP clients never see the OAuth tokens - they are securely injected server-side.
## Security Best Practices
1. **Never log tokens**: OAuth tokens should never be logged or exposed
2. **Use appropriate scopes**: Request only the scopes your tool actually needs
## Key Concepts
- **OAuth Integration**: Arcade handles OAuth flows and token management
- **Secure Token Injection**: Tokens are injected into context at runtime
- **Scope Management**: Specify exactly which permissions your tool needs
- **Provider Support**: Multiple OAuth providers available out of the box
- **User Privacy**: LLMs and MCP clients never see OAuth tokens