Skip to content

Add OAuth 2.1 authentication for streamable-http transport #72

@dfkunstler

Description

@dfkunstler

Summary

The MCP server currently has no authentication or authorization when using streamable-http transport. The README explicitly warns against using it for this reason. The MCP Python SDK (v1.23+) now includes built-in OAuth 2.1 Resource Server support following the MCP authorization specification and RFC 9728 (Protected Resource Metadata). We should leverage this to secure the HTTP transport.

Motivation

  • The streamable-http transport exposes the server over the network but has zero access control today
  • Remote/multi-user deployments (e.g., behind an API gateway, in a container, via AgentCore) need authentication
  • The MCP spec recommends OAuth 2.1 for HTTP transports, and the SDK we already depend on provides the plumbing

Proposed Approach

The MCP Python SDK provides a TokenVerifier protocol and AuthSettings configuration that integrate directly with FastMCP. The server would act as an OAuth 2.1 Resource Server (RS), validating bearer tokens issued by an external Authorization Server (AS).

Core changes:

  1. Implement TokenVerifier (from mcp.server.auth.provider) to validate incoming bearer tokens — either via JWT signature verification or token introspection
  2. Add AuthSettings (from mcp.server.auth.settings) to configure issuer URL, resource server URL, and required scopes
  3. Add configuration options to Config class:
    • OSCAL_AUTH_ISSUER_URL — Authorization Server issuer URL
    • OSCAL_AUTH_RESOURCE_SERVER_URL — this server's public URL
    • OSCAL_AUTH_REQUIRED_SCOPES — comma-separated list of required OAuth scopes
    • CLI args: --auth-issuer-url, --auth-resource-server-url, --auth-required-scopes
  4. Conditionally enable auth only when transport is streamable-http and an issuer URL is configured (stdio remains unaffected)
  5. Add a dependency for JWT validation (e.g., authlib or python-jose[cryptography])

Example integration in main.py:

from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings

mcp = FastMCP(
    config.server_name,
    token_verifier=OscalTokenVerifier(...),
    auth=AuthSettings(
        issuer_url=config.auth_issuer_url,
        resource_server_url=config.auth_resource_server_url,
        required_scopes=config.auth_required_scopes,
    ),
)

Scope

  • TokenVerifier implementation with JWT validation
  • New auth-related config options (env vars + CLI args)
  • Conditional enablement (only for streamable-http with issuer configured)
  • Unit tests for token verification (valid, expired, wrong scope, malformed)
  • Integration test with a mock Authorization Server
  • Update README to document auth configuration
  • Update dotenv.example with new env vars

Out of Scope (for now)

  • Built-in Authorization Server — users bring their own AS (Cognito, Auth0, Keycloak, etc.)
  • Per-tool authorization / fine-grained scopes
  • TLS termination (assumed to be handled by a reverse proxy or load balancer)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions