Skip to content

MCP authorization 2025-03-26 server spec implementation - #38

Draft
mazinesy wants to merge 6 commits into
modelcontextprotocol:mainfrom
mazinesy:oauth2-integration
Draft

MCP authorization 2025-03-26 server spec implementation#38
mazinesy wants to merge 6 commits into
modelcontextprotocol:mainfrom
mazinesy:oauth2-integration

Conversation

@mazinesy

@mazinesymazinesy commented Jun 3, 2025

Copy link
Copy Markdown

@mazinesymazinesy changed the title Oauth2 integrationMCP authorization 2025-03-26 spec implementationJun 3, 2025
@mazinesymazinesy changed the title MCP authorization 2025-03-26 spec implementationMCP authorization 2025-03-26 server spec implementationJun 3, 2025
@mazinesy

Copy link
Copy Markdown
Author

@topherbullock is this something I should put effort in implementing completely (including tests, etc. ?)

@HunterHillegas

Copy link
Copy Markdown

The new version of the MCP spec that just dropped today has some changes related to OAuth, yes? Specifically classification as OAuth Resource Servers? https://modelcontextprotocol.io/specification/2025-06-18/changelog

@mazinesy

Copy link
Copy Markdown
Author

@HunterHillegas My understanding is that the new spec is a superset of the previous one. Basically adding the protected_metadata endpoint as the first interaction on 401 between the client and the server instead of going directly to the .well-known/oauth-authorization-server endpoint

@hernanat

hernanat commented Jul 17, 2025

Copy link
Copy Markdown

hello 👋 wanted to ask what the plans are for this PR? or what the recommendation is for teams that want to use this SDK for building an MCP server + need auth in the meantime?

@mazinesy

Copy link
Copy Markdown
Author

hello 👋 wanted to ask what the plans are for this PR? or what the recommendation is for teams that want to use this SDK for building an MCP server + need auth in the meantime?

cc @topherbullock@atesgoral ?

@alexandru-calinoiu

Copy link
Copy Markdown
Contributor

I am not sure why is this needed, why should be bundle oauth into this gem when one can use an existing tool to handle all of that (ex: doorkeeper). I've implemented this with dynamic client registration in a rails app with doorkeeper and it's working fine.

@hernanat

Copy link
Copy Markdown

I am not sure why is this needed, why should be bundle oauth into this gem when one can use an existing tool to handle all of that (ex: doorkeeper). I've implemented this with dynamic client registration in a rails app with doorkeeper and it's working fine.

it's in the spec.

@HunterHillegas

Copy link
Copy Markdown

@alexandru-calinoiu Sorry to sort of hijack this thread but I have a question it sounds like you can answer - I thought Doorkeeper didn't do DCR? Or did you add that yourself?

@alexandru-calinoiu

alexandru-calinoiu commented Jul 27, 2025

Copy link
Copy Markdown
Contributor

@HunterHillegas I did implemented it myself, sort off:

Needed to update well-known paths:

routes.rb

 get "/.well-known/oauth-authorization-server", to: "oauth_authorization_server_metadata#show"
# OAuth dynamic client registration endpoint
post "/oauth/register", to: "oauth_client_registration#create", as: :oauth_register

oauth_authorization_server_metadata_controller.rb

class OauthAuthorizationServerMetadataController < ApplicationController
skip_before_action :verify_authenticity_token
allow_unauthenticated_access only: [ :show ]
def show
render json: {
.... other options
registration_endpoint: oauth_register_url,
}
end
end

oauth_client_registration_controller.rb

class OauthClientRegistrationController < ApplicationController
allow_unauthenticated_access only: [ :create ]
skip_before_action :verify_authenticity_token
rate_limit to: 10, within: 1.hour, only: :create, with: -> { render_rejection }
before_action :ensure_json_request, only: :create
def create
application = Doorkeeper::Application.new(registration_params)
if application.save
render json: registration_response(application), status: 201
else
render_validation_errors(application.errors)
end
end
private
def ensure_json_request
unless request.content_type == "application/json"
render json: { error: "invalid_request", error_description: "Content-Type must be application/json" }, status: 400
end
end
def registration_params
params.require(:redirect_uris)
{
name: params[:client_name] || "MCP Client",
redirect_uri: params[:redirect_uris].join("\n"),
scopes: "api mcp",
confidential: true
}
end
def registration_response(application)
{
client_id: application.uid,
client_secret: application.secret,
client_id_issued_at: application.created_at.to_i,
client_secret_expires_at: 0,
redirect_uris: application.redirect_uri.split("\n"),
token_endpoint_auth_method: "client_secret_basic",
grant_types: [ "authorization_code" ],
response_types: [ "code" ],
scope: "api mcp"
}
end
def render_validation_errors(errors)
error_type = errors.key?(:redirect_uri) ? "invalid_redirect_uri" : "invalid_client_metadata"
render json: {
error: error_type,
error_description: errors.full_messages.join(", ")
}, status: 400
end
def render_rejection
render json: {
error: "rate_limit_exceeded",
error_description: "Too many registration requests"
}, status: 429
end
end

Basic controller, using the models existing in Doorkeeper, with minimal protection that was needed our internal tooling.

@mazinesy

mazinesy commented Jul 28, 2025

Copy link
Copy Markdown
Author

@alexandru-calinoiu FYI, this implementation mimics the other official implementation, typescript and python. It also follows the 2025-03-26 authorization spec

@alexandru-calinoiu

Copy link
Copy Markdown
Contributor

@alexandru-calinoiu FYI, this implementation mimics the other official implementation, typescript and python. It also follows the 2025-03-26 authorization spec

I agree, just arguing that we can use another library and we don't need to maintain auth in this gem also. Also some projects out there would already use doorkeeper for auth stuff and it will be nice if we could play nice with them.

One suggestion would be to extract this into a separate gem ruby-sdk-oauth and people can choose to either use this or their existing oauth system.

@mazinesy

Copy link
Copy Markdown
Author

When we started working on this, we discussed the possibility of using a lib or having an extra gem, but the spec is specific to the MCP, specifically the part where the MCP acts as the dynamic client registry when the actual provider does not offer. For instance, Google said they will not implement dynamic client regsitration. The spec goes beyond the more generic oauth spec. I understand that for internal needs, that might be too much.

The sdk (probably) should be handling all use cases and give an easy way to enable features. Also, it's important to note that the implementation should respect the spec because the MCP spec is a 2-way street, MCP clients must support it as well.

This implementation worked against the official MCP inspector auth flow given the corresponding spec version.

@alexandru-calinoiu

Copy link
Copy Markdown
Contributor

Oh, sorry I was not aware of the initial discussion.

But I am afraid I don't really understand the point you are making, the specs https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#standards-compliance say pretty clear that this is standard compliance based on established specifications. It does not make sens for mcp to come up with their own flavor of oauth.

In my ideal world I would like to add doorkeeper-dcr along with doorkeeper, configure and have this all work out as expected.

PS: Unfortunately doorkeeper-dcr does not exist at this time, this sounds like some something worth investing some time into this weekend :)

@1c7

1c7 commented Aug 25, 2025

Copy link
Copy Markdown

Hi, Any update? I am trying to add MCP Server to existing Ruby on Rails 7 app.

so I can use Claude Code(or other MCP Client) to retrive useful context (MCP Resources) and call MCP tool

@atesgoral

Copy link
Copy Markdown
Contributor

@koic@mazinesy it would be really cool to revisit this and get it in. I'm happy to give rebasing a shot.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@mazinesy@HunterHillegas@hernanat@alexandru-calinoiu@1c7@atesgoral