Skip to main content

MCP Authentication

PraisonAI MCP Server supports multiple authentication methods per the MCP 2025-11-25 specification, including OAuth 2.1 with PKCE, OpenID Connect Discovery, and API Key authentication.

Protocol Version

This feature implements MCP Protocol Version 2025-11-25.

Authentication Methods

MethodDescriptionUse Case
OAuth 2.1Full OAuth flow with PKCEWeb applications, user auth
OIDC DiscoveryAuto-discover OAuth endpointsEnterprise SSO
API KeySimple bearer tokenCLI tools, scripts

Python API

OIDC Discovery

import asyncio
from praisonai.mcp_server.auth.oidc import OIDCDiscovery

async def main():
    discovery = OIDCDiscovery()
    
    # Discover from any OIDC provider
    config = await discovery.discover("https://accounts.google.com")
    
    if config:
        print(f"Issuer: {config.issuer}")
        print(f"Auth endpoint: {config.authorization_endpoint}")
        print(f"Token endpoint: {config.token_endpoint}")
        print(f"JWKS URI: {config.jwks_uri}")

asyncio.run(main())

OAuth 2.1 with PKCE

from praisonai.mcp_server.auth.oauth import OAuthConfig, OAuthManager

# Configure OAuth
config = OAuthConfig(
    authorization_endpoint="https://auth.example.com/authorize",
    token_endpoint="https://auth.example.com/token",
    client_id="my-mcp-client",
    default_scopes=["openid", "profile", "tools:read"],
    use_pkce=True,  # Required for OAuth 2.1
)

oauth = OAuthManager(config)

# Create authorization URL with PKCE
auth_url, auth_request = oauth.create_authorization_url(
    scopes=["openid", "profile", "tools:call"],
)

print(f"Auth URL: {auth_url}")
print(f"State: {auth_request.state}")
print(f"Code verifier: {auth_request.code_verifier}")
print(f"Code challenge: {auth_request.code_challenge}")

# After user authorizes, exchange code for token
# token = await oauth.exchange_code(code, auth_request)

API Key Authentication

from praisonai.mcp_server.auth.api_key import APIKeyAuth

api_key_auth = APIKeyAuth()

# Generate a new API key
raw_key, api_key = api_key_auth.generate_key(
    name="my-api-key",
    scopes=["tools:read", "tools:call", "resources:read"],
)

print(f"Key: {raw_key}")  # mcp_xxx... (store securely!)
print(f"Key ID: {api_key.key_id}")
print(f"Scopes: {api_key.scopes}")

# Validate a key
is_valid, validated_key = api_key_auth.validate(raw_key)
print(f"Valid: {is_valid}")

# Validate from Authorization header
is_valid, key = api_key_auth.validate_header("Bearer mcp_xxx...")

Scope Management

from praisonai.mcp_server.auth.scopes import ScopeManager

scope_manager = ScopeManager()

# Check if required scopes are granted
required = ["tools:read"]
granted = ["tools:call"]  # tools:call implies tools:read

is_valid, challenge = scope_manager.validate_scopes(required, granted)
print(f"Valid: {is_valid}")

# Expand scopes (show implied scopes)
expanded = scope_manager.expand_scopes(["tools:call"])
print(f"Expanded: {expanded}")  # {'tools:call', 'tools:read'}

# Admin scope expands to all
admin_expanded = scope_manager.expand_scopes(["admin"])
print(f"Admin expands to: {list(admin_expanded)[:5]}...")

CLI Usage

Start Server with API Key

praisonai mcp serve --transport http-stream --api-key YOUR_SECRET_KEY

Generate API Key

praisonai mcp auth generate-key --name "my-key" --scopes "tools:read,tools:call"

Validate API Key

praisonai mcp auth validate-key YOUR_KEY

Available Scopes

ScopeDescriptionImplies
tools:readList and describe tools-
tools:callExecute toolstools:read
resources:readRead resources-
resources:subscribeSubscribe to resource updatesresources:read
prompts:readList and get prompts-
prompts:executeExecute promptsprompts:read
tasks:readView tasks-
tasks:writeCreate/cancel taskstasks:read
adminFull accessAll scopes

WWW-Authenticate Challenge

challenge = oauth.create_www_authenticate_challenge(
    required_scopes=["admin"],
    error="insufficient_scope",
    error_description="Admin access required",
)
# Bearer scope="admin", error="insufficient_scope", error_description="Admin access required"

Security Best Practices

  1. Always use PKCE - Required for OAuth 2.1
  2. Validate origins - Use --allowed-origins for HTTP transport
  3. Rotate API keys - Regularly rotate keys
  4. Minimal scopes - Request only needed scopes
  5. Secure storage - Never commit keys to version control

Environment Variables

# OAuth configuration
export OAUTH_CLIENT_ID=your_client_id
export OAUTH_CLIENT_SECRET=your_client_secret  # Optional for public clients
export OIDC_ISSUER_URL=https://auth.example.com

# API key (for server)
export MCP_API_KEY=your_api_key