Module: Mcp::DiscoveryMetadata

Defined in:
app/services/mcp/discovery_metadata.rb

Overview

Single source of truth for the MCP gateway's OAuth discovery documents.

The gateway (mcp.warmlyyours.com) is WarmlyYours' OAuth 2.1 authorization
server (Doorkeeper: authorization_code + refresh_token grants, forced
PKCE/S256, RFC 7591 dynamic registration, scope mcp). These builders are
shared by OauthMetadataController (the canonical, self-describing
copies served on mcp.*) and OauthDiscoveryController (which surfaces the
same metadata on the public origins a crawler/agent scans). Centralizing them
keeps the two from drifting if the OAuth config changes.

Tokens are opaque (no JWT), so there is intentionally no jwks_uri (OPTIONAL
per RFC 8414 §2), and there is no OpenID Connect layer, so no
/.well-known/openid-configuration.

Class Method Summary collapse

Class Method Details

.authorization_server(issuer:) ⇒ Hash

RFC 8414 OAuth 2.0 Authorization Server Metadata.

Parameters:

  • issuer (String)

    the issuer identifier; also the base for the
    advertised endpoints (the AS hosts them under its own origin).

Returns:

  • (Hash)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/services/mcp/discovery_metadata.rb', line 27

def authorization_server(issuer:)
  {
    issuer: issuer,
    authorization_endpoint: "#{issuer}/oauth/authorize",
    token_endpoint: "#{issuer}/oauth/token",
    revocation_endpoint: "#{issuer}/oauth/revoke",
    # RFC 7591 dynamic client registration — required for Claude Code's
    # auto-OAuth flow; without it every client must be pre-created.
    registration_endpoint: "#{issuer}/oauth/register",
    response_types_supported: %w[code],
    grant_types_supported: %w[authorization_code refresh_token],
    code_challenge_methods_supported: %w[S256],
    token_endpoint_auth_methods_supported: %w[none client_secret_basic client_secret_post],
    scopes_supported: %w[mcp]
  }
end

.protected_resource(resource:, authorization_servers:) ⇒ Hash

RFC 9728 OAuth 2.0 Protected Resource Metadata.

Parameters:

  • resource (String)

    the protected resource's identifier (its origin).

  • authorization_servers (Array<String>)

    issuer URLs allowed to mint
    tokens for the resource.

Returns:

  • (Hash)


50
51
52
53
54
55
56
57
# File 'app/services/mcp/discovery_metadata.rb', line 50

def protected_resource(resource:, authorization_servers:)
  {
    resource: resource,
    authorization_servers: authorization_servers,
    bearer_methods_supported: %w[header],
    scopes_supported: %w[mcp]
  }
end