Class: MCPClient::Auth::ServerMetadata

Inherits:
Object
  • Object
show all
Defined in:
lib/mcp_client/auth.rb

Overview

OAuth authorization server metadata

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(issuer:, authorization_endpoint:, token_endpoint:, registration_endpoint: nil, scopes_supported: nil, response_types_supported: nil, grant_types_supported: nil, code_challenge_methods_supported: nil, client_id_metadata_document_supported: nil, authorization_response_iss_parameter_supported: false) ⇒ ServerMetadata

Returns a new instance of ServerMetadata.

Parameters:

  • issuer (String) —

    Issuer identifier URL

  • authorization_endpoint (String) —

    Authorization endpoint URL

  • token_endpoint (String) —

    Token endpoint URL

  • registration_endpoint (String, nil) (defaults to: nil) —

    Client registration endpoint URL

  • scopes_supported (Array<String>, nil) (defaults to: nil) —

    Supported OAuth scopes

  • response_types_supported (Array<String>, nil) (defaults to: nil) —

    Supported response types

  • grant_types_supported (Array<String>, nil) (defaults to: nil) —

    Supported grant types

  • code_challenge_methods_supported (Array<String>, nil) (defaults to: nil) —

    Supported PKCE code challenge methods (RFC 8414)

  • client_id_metadata_document_supported (Boolean, nil) (defaults to: nil) —

    Whether the server accepts Client ID Metadata Document client IDs (MCP 2025-11-25 / SEP-991)

  • authorization_response_iss_parameter_supported (Boolean, nil) (defaults to: false) —

    Whether the server includes the iss parameter in authorization responses (RFC 9207 Section 2.3, MCP 2026-07-28). Defaults to the RFC 8414 default (false, "not advertised"); an explicit nil means the record carries no answer at all — see #iss_parameter_recorded?



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/mcp_client/auth.rb', line 384

def initialize(issuer:, authorization_endpoint:, token_endpoint:, registration_endpoint: nil,
               scopes_supported: nil, response_types_supported: nil, grant_types_supported: nil,
               code_challenge_methods_supported: nil, client_id_metadata_document_supported: nil,
               authorization_response_iss_parameter_supported: false)
  @issuer = issuer
  @authorization_endpoint = authorization_endpoint
  @token_endpoint = token_endpoint
  @registration_endpoint = registration_endpoint
  @scopes_supported = scopes_supported
  @response_types_supported = response_types_supported
  @grant_types_supported = grant_types_supported
  @code_challenge_methods_supported = code_challenge_methods_supported
  @client_id_metadata_document_supported = 
  @authorization_response_iss_parameter_supported =
    self.class.normalize_iss_advertisement(authorization_response_iss_parameter_supported)
end

Instance Attribute Details

#authorization_endpoint ⇒ Object (readonly)

Returns the value of attribute authorization_endpoint.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def authorization_endpoint
  @authorization_endpoint
end

#authorization_response_iss_parameter_supported ⇒ Object (readonly)

Returns the value of attribute authorization_response_iss_parameter_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def authorization_response_iss_parameter_supported
  @authorization_response_iss_parameter_supported
end

#client_id_metadata_document_supported ⇒ Object (readonly)

Returns the value of attribute client_id_metadata_document_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def 
  @client_id_metadata_document_supported
end

#code_challenge_methods_supported ⇒ Object (readonly)

Returns the value of attribute code_challenge_methods_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def code_challenge_methods_supported
  @code_challenge_methods_supported
end

#grant_types_supported ⇒ Object (readonly)

Returns the value of attribute grant_types_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def grant_types_supported
  @grant_types_supported
end

#issuer ⇒ Object (readonly)

Returns the value of attribute issuer.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def issuer
  @issuer
end

#registration_endpoint ⇒ Object (readonly)

Returns the value of attribute registration_endpoint.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def registration_endpoint
  @registration_endpoint
end

#response_types_supported ⇒ Object (readonly)

Returns the value of attribute response_types_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def response_types_supported
  @response_types_supported
end

#scopes_supported ⇒ Object (readonly)

Returns the value of attribute scopes_supported.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def scopes_supported
  @scopes_supported
end

#token_endpoint ⇒ Object (readonly)

Returns the value of attribute token_endpoint.



365
366
367
# File 'lib/mcp_client/auth.rb', line 365

def token_endpoint
  @token_endpoint
end

Class Method Details

.from_discovery_document(data) ⇒ ServerMetadata

Read an authorization server's own metadata document. An absent authorization_response_iss_parameter_supported in a FETCHED document is the server's own answer ("no", the RFC 8414 default), so it is recorded as an explicit false; only a record PERSISTED before this client read the field (from_h of a hash without the key) is left without an answer.

Parameters:

  • data (Hash) —

    the parsed metadata document

Returns:



496
497
498
499
500
501
# File 'lib/mcp_client/auth.rb', line 496

def self.from_discovery_document(data)
   = from_h(data)
  return  if .iss_parameter_recorded?

  from_h(data.merge(authorization_response_iss_parameter_supported: false))
end

.from_h(data) ⇒ ServerMetadata

Create server metadata from hash

Parameters:

  • data (Hash) —

    Server metadata

Returns:



471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/mcp_client/auth.rb', line 471

def self.from_h(data)
  new(
    issuer: data[:issuer] || data['issuer'],
    authorization_endpoint: data[:authorization_endpoint] || data['authorization_endpoint'],
    token_endpoint: data[:token_endpoint] || data['token_endpoint'],
    registration_endpoint: data[:registration_endpoint] || data['registration_endpoint'],
    scopes_supported: data[:scopes_supported] || data['scopes_supported'],
    response_types_supported: data[:response_types_supported] || data['response_types_supported'],
    grant_types_supported: data[:grant_types_supported] || data['grant_types_supported'],
    code_challenge_methods_supported: data[:code_challenge_methods_supported] ||
      data['code_challenge_methods_supported'],
    client_id_metadata_document_supported: fetch_boolean(data, :client_id_metadata_document_supported),
    authorization_response_iss_parameter_supported:
      fetch_boolean(data, :authorization_response_iss_parameter_supported)
  )
end

.normalize_iss_advertisement(value) ⇒ Boolean?

RFC 8414 makes authorization_response_iss_parameter_supported a JSON boolean. A document (or a persisted record) carrying anything else — "true", 1, {} — says nothing this client can act on, and "says nothing" must never be read as "not advertised": that is the reading that accepts a callback with no iss from a server that does send one, which is exactly the mix-up RFC 9207 exists to stop. An unusable answer is therefore treated as an advertisement — the check fails closed, refusing a response without iss — and is recorded as one, so a round trip through storage keeps the same reading. Only an absent value (nil) stays "no answer at all" (see #iss_parameter_recorded?).

Parameters:

  • value (Object, nil) —

    the value as given

Returns:

  • (Boolean, nil)


422
423
424
425
426
# File 'lib/mcp_client/auth.rb', line 422

def self.normalize_iss_advertisement(value)
  return value if value.nil? || value == true || value == false

  true
end

Instance Method Details

#iss_parameter_recorded? ⇒ Boolean

Whether this record actually carries an answer about the RFC 9207 iss parameter. A record persisted before this client read the field carries none, and "no answer" must not be read as "not supported": that would accept a response without iss from a server that advertises it.

Returns:

  • (Boolean)


434
435
436
# File 'lib/mcp_client/auth.rb', line 434

def iss_parameter_recorded?
  !@authorization_response_iss_parameter_supported.nil?
end

#iss_parameter_supported? ⇒ Boolean

Whether the server advertises the RFC 9207 iss authorization response parameter; when it does, a response without iss MUST be rejected (MCP 2026-07-28 "Authorization Response Validation").

Returns:

  • (Boolean)


405
406
407
# File 'lib/mcp_client/auth.rb', line 405

def iss_parameter_supported?
  @authorization_response_iss_parameter_supported == true
end

#supports_client_id_metadata_documents? ⇒ Boolean

Check if the server accepts clients using Client ID Metadata Documents (MCP 2025-11-25 / SEP-991), i.e. HTTPS URLs as client identifiers

Returns:

  • (Boolean) —

    true if client_id_metadata_document_supported is true



447
448
449
# File 'lib/mcp_client/auth.rb', line 447

def 
  @client_id_metadata_document_supported == true
end

#supports_registration? ⇒ Boolean

Check if dynamic client registration is supported

Returns:

  • (Boolean) —

    true if registration endpoint is available



440
441
442
# File 'lib/mcp_client/auth.rb', line 440

def supports_registration?
  !@registration_endpoint.nil?
end

#to_h ⇒ Hash

Convert to hash

Returns:

  • (Hash) —

    Hash representation



453
454
455
456
457
458
459
460
461
462
463
464
465
466
# File 'lib/mcp_client/auth.rb', line 453

def to_h
  {
    issuer: @issuer,
    authorization_endpoint: @authorization_endpoint,
    token_endpoint: @token_endpoint,
    registration_endpoint: @registration_endpoint,
    scopes_supported: @scopes_supported,
    response_types_supported: @response_types_supported,
    grant_types_supported: @grant_types_supported,
    code_challenge_methods_supported: @code_challenge_methods_supported,
    client_id_metadata_document_supported: @client_id_metadata_document_supported,
    authorization_response_iss_parameter_supported: @authorization_response_iss_parameter_supported
  }.compact
end