Skip to main content
Glama
resource_metadata.py3.97 kB
"""Protected Resource Metadata for OAuth 2.1 Resource Servers. Implements RFC 9728 Protected Resource Metadata, allowing MCP clients to discover the authorization server and supported scopes for this resource server. """ from __future__ import annotations from dataclasses import dataclass, field from typing import TYPE_CHECKING if TYPE_CHECKING: from sso_mcp_server.config import Settings @dataclass class ProtectedResourceMetadata: """RFC 9728 Protected Resource Metadata. Represents the metadata document that Resource Servers publish at their well-known endpoint to describe their OAuth requirements. Attributes: resource: The resource identifier (this server's URL). authorization_servers: List of authorization server issuer URLs. scopes_supported: List of OAuth scopes supported by this resource. bearer_methods_supported: Methods for transmitting Bearer tokens. """ resource: str authorization_servers: list[str] = field(default_factory=list) scopes_supported: list[str] = field(default_factory=list) bearer_methods_supported: list[str] = field(default_factory=lambda: ["header"]) def to_dict(self) -> dict: """Convert to dictionary for JSON serialization. Returns: Dictionary suitable for JSON response. """ result: dict = { "resource": self.resource, } if self.authorization_servers: result["authorization_servers"] = self.authorization_servers if self.scopes_supported: result["scopes_supported"] = self.scopes_supported if self.bearer_methods_supported: result["bearer_methods_supported"] = self.bearer_methods_supported return result def generate_metadata(settings: Settings) -> ProtectedResourceMetadata: """Generate Protected Resource Metadata from settings. Creates an RFC 9728 compliant metadata document based on the server's configuration. Args: settings: Application settings with cloud mode configuration. Returns: ProtectedResourceMetadata instance. """ return ProtectedResourceMetadata( resource=settings.resource_identifier, authorization_servers=settings.allowed_issuers, scopes_supported=settings.scopes_supported, bearer_methods_supported=["header"], ) def build_www_authenticate_header( settings: Settings, error: str | None = None, error_description: str | None = None, scope: str | None = None, ) -> str: """Build WWW-Authenticate header for 401/403 responses. Constructs an RFC 6750 compliant WWW-Authenticate header with optional error details and resource metadata URL. Args: settings: Application settings. error: OAuth error code (e.g., "invalid_token", "insufficient_scope"). error_description: Human-readable error description. scope: Required scope(s) for insufficient_scope errors. Returns: WWW-Authenticate header value. Example: Bearer realm="sso-mcp-server", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource", error="invalid_token", error_description="Token has expired" """ parts = ['Bearer realm="sso-mcp-server"'] # Add resource metadata URL if settings.resource_identifier: base_url = settings.resource_identifier.rstrip("/") metadata_url = f"{base_url}/.well-known/oauth-protected-resource" parts.append(f'resource_metadata="{metadata_url}"') # Add error details if present if error: parts.append(f'error="{error}"') if error_description: # Escape quotes in description safe_desc = error_description.replace('"', '\\"') parts.append(f'error_description="{safe_desc}"') if scope: parts.append(f'scope="{scope}"') return ", ".join(parts)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DauQuangThanh/sso-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server