Skip to content

feat: dynamic client registration #838

@JosiahParry

Description

@JosiahParry

I've developed my own MCP server https://jebbysays.dev/mcp and I would like to use it from R. But there's a number of hiccups. One of them is Dynamic Client Registration (DCR) support in R.

Step 4 of MCP "Understanding Authorization in MCP" is client registration. MCP servers use DCR to support clients connecting to them dynamically.

My motivation was trying to use ellmer with my MCP server.

It would be great if httr2 could implement DCR—my POC attempt is below.

I think it would help get closer to using MCP servers with {mcptools} and {ellmer}

related: posit-dev/mcptools#88

library(httr2)

#' OAuth 2.0 Discovery
#'
#' @param issuer the OAuth 2.0 issuer url. Must have a `/.well-known/oauth-authorization-server` endpoint.
#'
#' @export
discover_oauth <- function(issuer) {
  rlang:::check_string(issuer)
  if (!httr2:::is_string_url(issuer)) {
    cli::cli_abort("{.arg issuer} must be a valid url")
  }

  httr2::request(issuer) |>
    httr2::req_url_path_append(".well-known/oauth-authorization-server") |>
    httr2::req_perform() |>
    httr2::resp_body_json()
}


# Discover OAuth provider info per rfc8414
mcp_meta <- discover_oauth("https://jebbysays.dev")

# perform self registration to get an OAuth client to auth to
# give the redirec_uri i want for httr2 to use
redirect_uri <- "http://localhost:8888"

reg <- request(mcp_meta$registration_endpoint) |>
  req_body_json(list(
    client_name = "my-r-client",
    redirect_uris = list(redirect_uri),
    grant_types = list("authorization_code"),
    response_types = list("code"),
    scope = "openid profile email offline_access"
  )) |>
  req_perform() |>
  resp_body_json()


# use my own OAuth2 app
issuer <- "https://clerk.jebbysays.dev"
issuer_meta <- discover_oauth(issuer)

# create a client for my registered app for the MCP server
client <- oauth_client(
  id = reg$client_id,
  secret = reg$client_secret,
  token_url = issuer_meta$token_endpoint
)

# get an auth token from our new self-registered endpoint
token <- oauth_flow_auth_code(
  client = client,
  auth_url = issuer_meta$authorization_endpoint,
  redirect_uri = redirect_uri,
  scope = reg$scope
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions