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
123 lines
3.4 KiB
Markdown
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
|