TsengX/mcp-oauth-sample
If you are the rightful owner of mcp-oauth-sample and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
This server integrates OAuth authentication with MCP functionality, using statically pre-registered client credentials, ideal for development and debugging purposes.
MCP OAuth Sample
A demonstration server that integrates OAuth authentication with MCP functionality, using statically pre-registered client credentials, ideal for development and debugging purposes.
Features
- ✅ Single-Port Deployment: OAuth and MCP functionality run on the same port
- ✅ Static Client Registration: Uses pre-configured
client_idandclient_secret - ✅ No Dynamic Registration: Suitable for single-client usage scenarios
- ✅ Easy to Use: Start with
uvin one command - ✅ Production-Ready: Supports custom credentials and configuration files
Quick Start
Prerequisites
- Python 3.10+
- uv - Python package manager
Install uv
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or using Homebrew (macOS)
brew install uv
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Clone the Repository
git clone https://github.com/TsengX/mcp-oauth-sample.git
cd mcp-oauth-sample
Start the Server
Method 1: Using Default Settings
# Use default port 9003 and default credentials
uv run python mcp_simple_auth/statically_registered_client_server.py
# Or using uv script command
uv run mcp-static-auth
Method 2: Custom Port and Credentials
uv run python mcp_simple_auth/statically_registered_client_server.py \
--port 9003 \
--client-id "my-client-001" \
--client-secret "my-secure-secret-12345"
Method 3: Using Environment Variables
export MCP_STATIC_CLIENT_ID="my-client-001"
export MCP_STATIC_CLIENT_SECRET="my-secure-secret"
export MCP_STATIC_PORT=9003
uv run python mcp_simple_auth/statically_registered_client_server.py
Server Endpoints
After starting, the server provides the following endpoints:
- MCP Endpoint:
http://localhost:9003/mcp - OAuth Authorization:
http://localhost:9003/authorize - OAuth Token:
http://localhost:9003/token - Login Page:
http://localhost:9003/login - Token Introspection:
http://localhost:9003/introspect
Configuration
Environment Variables
Supported environment variables (with MCP_STATIC_ prefix):
MCP_STATIC_CLIENT_ID: Pre-registered client IDMCP_STATIC_CLIENT_SECRET: Pre-registered client secretMCP_STATIC_PORT: Server listening portMCP_STATIC_HOST: Server host address
Command Line Arguments
python mcp_simple_auth/statically_registered_client_server.py --help
Available arguments:
--port: Listening port (default: 9003)--client-id: Client ID (default: static-mcp-client-001)--client-secret: Client secret (default: your-secret-key-change-this-in-production)
Client Integration
Java Client Example
public class McpClient {
// Use the same credentials as server configuration
private static final String CLIENT_ID = "static-mcp-client-001";
private static final String CLIENT_SECRET = "your-secret-key-change-this-in-production";
private static final String SERVER_URL = "http://localhost:9003";
// OAuth endpoints
private static final String AUTHORIZE_ENDPOINT = SERVER_URL + "/authorize";
private static final String TOKEN_ENDPOINT = SERVER_URL + "/token";
private static final String MCP_ENDPOINT = SERVER_URL + "/mcp";
// ... implement OAuth flow
}
Using Pre-registered Credentials
No dynamic registration needed, directly use the pre-registered client_id and client_secret:
- Request authorization URL:
GET /authorize - User logs in via browser
- Get authorization code
- Exchange token:
POST /token(using pre-registered credentials)
OAuth Flow
Flow Diagram
Client Server (9003)
│ │
├── GET /authorize ────────────►│
│ │
│←── Login page URL ────────────┤
│ │
└──► Open browser to login ───►│
│ │
│←── Callback with auth code ───┤
│ /callback?code=xxx │
│ │
├── POST /token ────────────────►│
│ (using pre-registered creds)│
│ │
│←── access_token ───────────────┤
│ │
├── Use token to access MCP ───►│
│ Authorization: Bearer token │
│ │
│←── MCP Response ───────────────┤
Default Credentials
Development environment default credentials:
- Client ID:
static-mcp-client-001 - Client Secret:
your-secret-key-change-this-in-production
⚠️ Important: Make sure to change these credentials in production environments!
Production Deployment
Generate Secure Key
# Using OpenSSL
openssl rand -hex 32
# Using Python
python3 -c "import secrets; print(secrets.token_hex(32))"
# Using /dev/urandom
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1
Start Production Server
# Generate random key
CLIENT_SECRET=$(openssl rand -hex 32)
# Start server
uv run python mcp_simple_auth/statically_registered_client_server.py \
--port 9003 \
--client-id "prod-mcp-client-001" \
--client-secret "$CLIENT_SECRET"
Security Best Practices
- ✅ Don't hardcode secrets in code
- ✅ Use environment variables or secret management services (e.g., AWS Secrets Manager, HashiCorp Vault)
- ✅ Rotate
client_secretregularly - ✅ Use strong random keys (at least 32 characters)
- ✅ Disable debug mode in production
Available Tools
The server provides the following MCP tools:
1. get_time
Get the current server time.
Returns:
{
"current_time": "2024-01-01T12:00:00",
"timezone": "UTC",
"timestamp": 1704110400.0,
"formatted": "2024-01-01 12:00:00"
}
2. echo
Echo a message back.
Parameters: message (string)
Returns:
{
"echo": "Hello, World!",
"length": 13
}
Testing
Test OAuth Endpoints
# 1. View authorization server metadata
curl http://localhost:9003/.well-known/oauth-authorization-server
# 2. Try dynamic registration (should fail with 403)
curl -X POST http://localhost:9003/register \
-H "Content-Type: application/json" \
-d '{"client_name": "test"}'
# 3. Access login page
open http://localhost:9003/login?state=test123&client_id=static-mcp-client-001
Test MCP Functionality
# Connect to server using MCP client
# Example using Python SDK
python -c "
from mcp import Client
client = Client('http://localhost:9003/mcp')
# Requires valid OAuth token
"
Development
Project Structure
mcp-oauth-sample/
├── mcp_simple_auth/
│ ├── statically_registered_client_server.py # Main server file
│ ├── simple_auth_provider.py # OAuth provider
│ └── token_verifier.py # Token verifier
├── pyproject.toml # Project configuration
└── README.md # This document
Adding Custom Tools
Edit mcp_simple_auth/statically_registered_client_server.py:
def create_combined_mcp_server(settings: StaticallyRegisteredSettings) -> FastMCP:
# ... existing code ...
@app.tool()
async def my_custom_tool(param: str) -> dict[str, Any]:
"""
Your custom tool description.
Args:
param: Description of parameter
Returns:
Tool result
"""
return {"result": f"Processed: {param}"}
return app
Local Development
# Install dependencies
uv sync
# Run development server
uv run python mcp_simple_auth/statically_registered_client_server.py --port 9003
# Run tests
uv run pytest
FAQ
Q: Why use static client registration?
A: Static registration is suitable for single-client production scenarios, simpler and more controllable, avoiding the complexity of dynamic registration.
Q: How to support multiple clients?
A: If you need to support multiple clients, consider using dynamic client registration, or run multiple server instances with different credentials for each.
Q: Does this server support OAuth refresh tokens?
A: The current implementation simplifies the refresh token functionality. It is recommended to implement a complete refresh token flow in production.
Q: How to deploy to production?
A: Recommended deployment approach:
- Use environment variables for secret management
- Configure reverse proxy (e.g., Nginx)
- Enable HTTPS
- Configure firewall rules
- Use process manager (e.g., systemd, supervisord)
Q: How to handle token expiration?
A: In the current implementation, access tokens have a validity period of 3600 seconds (1 hour). You can adjust the validity period by modifying the expires_at parameter in the code.
License
MIT License
Contributing
Issues and Pull Requests are welcome!
Acknowledgments
Built on the Model Context Protocol (MCP) Python SDK.