Class: MCP::Client::OAuth::Provider

Inherits:
Object
  • Object
show all
Includes:
StorageBackedProvider
Defined in:
lib/mcp/client/oauth/provider.rb

Overview

Pluggable OAuth client configuration for the OAuth 2.1 Authorization Code + PKCE flow, handed to MCP::Client::HTTP via the oauth: keyword. Inspired by the OAuthClientProvider in the TypeScript SDK and the httpx.Auth-based provider in the Python SDK. For the non-interactive machine-to-machine client_credentials grant, use ClientCredentialsProvider instead.

Required keyword arguments:

  • client_metadata - Hash sent to the authorization server's Dynamic Client Registration endpoint. Must include at minimum redirect_uris, grant_types, response_types, and token_endpoint_auth_method. When application_type is omitted, the SDK infers "native" or "web" from redirect_uris per SEP-837 before registering; an explicit value always wins.
  • redirect_uri - String: the redirect URI used for the authorization request. Must be one of redirect_uris in client_metadata.
  • redirect_handler - Callable invoked with the fully-built authorization URL (a URI). Implementations typically open the user's browser.
  • callback_handler - Callable invoked after redirect_handler. Returns [code, state] where code is the authorization code and state is the state parameter received on the redirect URI.

Optional keyword arguments:

  • scope - String of space-separated scopes to request when the server's WWW-Authenticate does not specify one.
  • storage - Object responding to tokens, save_tokens(tokens), client_information, and save_client_information(info). Defaults to an InMemoryStorage.
  • client_id_metadata_document_url - URL where the client publishes its Client ID Metadata Document (draft-ietf-oauth-client-id-metadata-document-00 and the MCP authorization specification). When the authorization server advertises client_id_metadata_document_supported: true, the SDK uses this URL as the OAuth client_id and skips Dynamic Client Registration. Spec-required: https:// scheme, a non-root path, and no fragment, userinfo, or ./.. segments. The SDK additionally refuses to send query strings (the draft marks them only SHOULD NOT include, but different encodings of the same query would yield different client_id strings for the same document). The document served at the URL is a separate JSON artifact from the client_metadata keyword: DCR client_metadata MUST NOT include client_id, while the CIMD document MUST include client_id set to the URL, client_name, and redirect_uris covering redirect_uri.

Defined Under Namespace

Classes: InsecureRedirectURIError, InvalidClientIDMetadataDocumentURLError, UnregisteredRedirectURIError

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from StorageBackedProvider

#access_token, #clear_tokens!, #client_information, #save_client_information, #save_tokens, #tokens

Constructor Details

#initialize(client_metadata:, redirect_uri:, redirect_handler:, callback_handler:, scope: nil, storage: nil, client_id_metadata_document_url: nil) ⇒ Provider

Returns a new instance of Provider.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/mcp/client/oauth/provider.rb', line 74

def initialize(
  client_metadata:,
  redirect_uri:,
  redirect_handler:,
  callback_handler:,
  scope: nil,
  storage: nil,
  client_id_metadata_document_url: nil
)
  unless Discovery.secure_url?(redirect_uri)
    raise InsecureRedirectURIError,
      "redirect_uri #{redirect_uri.inspect} must use https or be a loopback http URL " \
        "(localhost, 127.0.0.0/8, or ::1) per the MCP authorization Communication Security requirement."
  end

  registered = Array([:redirect_uris] || ["redirect_uris"])
  unless registered.include?(redirect_uri)
    raise UnregisteredRedirectURIError,
      "redirect_uri #{redirect_uri.inspect} must be listed in client_metadata[:redirect_uris] " \
        "(got #{registered.inspect}); otherwise the authorization server will reject the authorization request."
  end

  if  && !Discovery.()
    raise InvalidClientIDMetadataDocumentURLError,
      "client_id_metadata_document_url #{.inspect} must be an https URL " \
        "with a non-root path and no fragment, query, userinfo, or `.`/`..` segments, " \
        "per the MCP authorization specification and `draft-ietf-oauth-client-id-metadata-document`."
  end

  @client_metadata = 
  @redirect_uri = redirect_uri
  @redirect_handler = redirect_handler
  @callback_handler = callback_handler
  @scope = scope
  @storage = storage || InMemoryStorage.new
  @client_id_metadata_document_url = 
end

Instance Attribute Details

#callback_handlerObject (readonly)

Returns the value of attribute callback_handler.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def callback_handler
  @callback_handler
end

#client_id_metadata_document_urlObject (readonly)

Returns the value of attribute client_id_metadata_document_url.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def 
  @client_id_metadata_document_url
end

#client_metadataObject (readonly)

Returns the value of attribute client_metadata.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def 
  @client_metadata
end

#redirect_handlerObject (readonly)

Returns the value of attribute redirect_handler.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def redirect_handler
  @redirect_handler
end

#redirect_uriObject (readonly)

Returns the value of attribute redirect_uri.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def redirect_uri
  @redirect_uri
end

#scopeObject (readonly)

Returns the value of attribute scope.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def scope
  @scope
end

#storageObject (readonly)

Returns the value of attribute storage.



66
67
68
# File 'lib/mcp/client/oauth/provider.rb', line 66

def storage
  @storage
end

Instance Method Details

#authorization_flowObject

Identifies the OAuth flow this provider drives. Flow dispatches on this rather than inspecting client_metadata[:grant_types], which is protocol metadata for the authorization server, not an SDK control signal.



115
116
117
# File 'lib/mcp/client/oauth/provider.rb', line 115

def authorization_flow
  :authorization_code
end