Class: MCPClient::Auth::ClientInfo

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

Overview

Registered OAuth client information

Constant Summary collapse

REGISTRATION_TYPES =

How the client id was obtained (MCP 2026-07-28 client registration): 'pre_registered' credentials belong to one authorization server and must not be reused with another; 'dynamic' registrations are redone for a new authorization server; 'cimd' (Client ID Metadata Document) client ids are portable across authorization servers.

%w[pre_registered dynamic cimd].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client_id:, metadata:, client_secret: nil, client_id_issued_at: nil, client_secret_expires_at: nil, issuer: nil, registration_type: nil) ⇒ ClientInfo

Returns a new instance of ClientInfo.

Parameters:

  • client_id (String) —

    OAuth client ID

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

    OAuth client secret (for confidential clients)

  • client_id_issued_at (Integer, nil) (defaults to: nil) —

    Unix timestamp when client ID was issued

  • client_secret_expires_at (Integer, nil) (defaults to: nil) —

    Unix timestamp when client secret expires

  • metadata (ClientMetadata) —

    Client metadata

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

    issuer identifier of the authorization server these credentials belong to (MCP 2026-07-28 "Authorization Server Binding")

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

    one of REGISTRATION_TYPES (nil: unknown, treated as a dynamic registration; credentials a host pre-registered should say 'pre_registered')



246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/mcp_client/auth.rb', line 246

def initialize(client_id:, metadata:, client_secret: nil, client_id_issued_at: nil,
               client_secret_expires_at: nil, issuer: nil, registration_type: nil)
  unless registration_type.nil? || REGISTRATION_TYPES.include?(registration_type)
    raise ArgumentError, "registration_type must be one of #{REGISTRATION_TYPES.join(', ')}"
  end

  @client_id = client_id
  @client_secret = client_secret
  @client_id_issued_at = client_id_issued_at
  @client_secret_expires_at = client_secret_expires_at
  @metadata = 
  @issuer = issuer
  @registration_type = registration_type
end

Instance Attribute Details

#client_id ⇒ Object (readonly)

Returns the value of attribute client_id.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def client_id
  @client_id
end

#client_id_issued_at ⇒ Object (readonly)

Returns the value of attribute client_id_issued_at.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def client_id_issued_at
  @client_id_issued_at
end

#client_secret ⇒ Object (readonly)

Returns the value of attribute client_secret.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def client_secret
  @client_secret
end

#client_secret_expires_at ⇒ Object (readonly)

Returns the value of attribute client_secret_expires_at.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def client_secret_expires_at
  @client_secret_expires_at
end

#issuer ⇒ Object (readonly)

Returns the value of attribute issuer.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def issuer
  @issuer
end

#metadata ⇒ Object (readonly)

Returns the value of attribute metadata.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def 
  @metadata
end

#registration_type ⇒ Object (readonly)

Returns the value of attribute registration_type.



234
235
236
# File 'lib/mcp_client/auth.rb', line 234

def registration_type
  @registration_type
end

Class Method Details

.build_metadata_from_hash(metadata_data) ⇒ ClientMetadata

Build ClientMetadata from hash data

Parameters:

  • metadata_data (Hash) —

    Metadata hash

Returns:



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/mcp_client/auth.rb', line 336

def self.()
  ClientMetadata.new(
    redirect_uris: [:redirect_uris] || ['redirect_uris'] || [],
    token_endpoint_auth_method: extract_auth_method(),
    grant_types: [:grant_types] || ['grant_types'] ||
                 %w[authorization_code refresh_token],
    response_types: [:response_types] || ['response_types'] || ['code'],
    scope: [:scope] || ['scope'],
    client_name: [:client_name] || ['client_name'],
    client_uri: [:client_uri] || ['client_uri'],
    logo_uri: [:logo_uri] || ['logo_uri'],
    tos_uri: [:tos_uri] || ['tos_uri'],
    policy_uri: [:policy_uri] || ['policy_uri'],
    contacts: [:contacts] || ['contacts'],
    application_type: [:application_type] || ['application_type']
  )
end

.extract_auth_method(metadata_data) ⇒ String

Extract token endpoint auth method from metadata

Parameters:

  • metadata_data (Hash) —

    Metadata hash

Returns:

  • (String) —

    Authentication method



357
358
359
360
# File 'lib/mcp_client/auth.rb', line 357

def self.extract_auth_method()
  [:token_endpoint_auth_method] ||
    ['token_endpoint_auth_method'] || 'none'
end

.from_h(data) ⇒ ClientInfo

Create client info from hash

Parameters:

  • data (Hash) —

    Client info data

Returns:



318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/mcp_client/auth.rb', line 318

def self.from_h(data)
   = data[:metadata] || data['metadata'] || {}
   = ()

  new(
    client_id: data[:client_id] || data['client_id'],
    client_secret: data[:client_secret] || data['client_secret'],
    client_id_issued_at: data[:client_id_issued_at] || data['client_id_issued_at'],
    client_secret_expires_at: data[:client_secret_expires_at] || data['client_secret_expires_at'],
    metadata: ,
    issuer: data[:issuer] || data['issuer'],
    registration_type: data[:registration_type] || data['registration_type']
  )
end

Instance Method Details

#client_secret_expired? ⇒ Boolean

Check if client secret is expired. RFC 7591 Section 3.2.1 gives 0 the meaning "this secret does not expire", so it is not an expiry in the past.

Returns:

  • (Boolean) —

    true if client secret is expired



295
296
297
298
299
# File 'lib/mcp_client/auth.rb', line 295

def client_secret_expired?
  return false if @client_secret_expires_at.nil? || @client_secret_expires_at.zero?

  Time.now.to_i >= @client_secret_expires_at
end

#effective_registration_type ⇒ String

The registration type. Credentials persisted before the field existed count as a dynamic registration: RFC 7591's client_id_issued_at is optional, so its absence proves nothing, and this library only ever stored the registrations it made. Credentials a host pre-registered are recorded as such explicitly (registration_type: 'pre_registered').

Returns:

  • (String)


277
278
279
# File 'lib/mcp_client/auth.rb', line 277

def effective_registration_type
  @registration_type || 'dynamic'
end

#portable? ⇒ Boolean

Returns whether the client id is portable across authorization servers.

Returns:

  • (Boolean) —

    whether the client id is portable across authorization servers



262
263
264
# File 'lib/mcp_client/auth.rb', line 262

def portable?
  @registration_type == 'cimd'
end

#pre_registered? ⇒ Boolean

Returns whether these are pre-registered (static) credentials.

Returns:

  • (Boolean) —

    whether these are pre-registered (static) credentials



267
268
269
# File 'lib/mcp_client/auth.rb', line 267

def pre_registered?
  effective_registration_type == 'pre_registered'
end

#to_h ⇒ Hash

Convert to hash for serialization

Returns:

  • (Hash) —

    Hash representation



303
304
305
306
307
308
309
310
311
312
313
# File 'lib/mcp_client/auth.rb', line 303

def to_h
  {
    client_id: @client_id,
    client_secret: @client_secret,
    client_id_issued_at: @client_id_issued_at,
    client_secret_expires_at: @client_secret_expires_at,
    metadata: @metadata.to_h,
    issuer: @issuer,
    registration_type: @registration_type
  }.compact
end

#with_issuer(issuer, registration_type: effective_registration_type) ⇒ ClientInfo

A copy bound to an authorization server.

Parameters:

  • issuer (String) —

    the issuer identifier

  • registration_type (String) (defaults to: effective_registration_type) —

    the type to record (defaults to the effective type)

Returns:



285
286
287
288
289
# File 'lib/mcp_client/auth.rb', line 285

def with_issuer(issuer, registration_type: effective_registration_type)
  self.class.new(client_id: @client_id, metadata: @metadata, client_secret: @client_secret,
                 client_id_issued_at: @client_id_issued_at, client_secret_expires_at: @client_secret_expires_at,
                 issuer: issuer, registration_type: registration_type)
end