modelcontextprotocol / modelcontextprotocol/go-sdk

auth: DCR registration omits scopes, causing invalid_scope on strict auth servers

Open
#1,102 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

P2
Dominant language
Go
Stars
5.1k
Forks
543
Avg merge
1d 17h
Merged PRs (30d)
37

Description

Describe the bug

When using AuthorizationCodeHandler with DynamicClientRegistrationConfig, the SDK registers the DCR client before computing the scopes it will request during authorization. If the caller doesn't set ClientRegistrationMetadata.Scope the client is registered without any scope restriction. Section 2 of RFC 7591 says:

scope:
String containing a space-separated list of scope values (as
described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client
can use when requesting access tokens. The semantics of values in
this list are service specific. If omitted, an authorization
server MAY register a client with a default set of scopes.

I think the important part being that the server MAY register a client with default scopes but for registration endpoints that aren't exclusively used for MCP, it's hard to know what that default set of scopes would be.

To Reproduce

  1. Configure an AuthorizationCodeHandler with DynamicClientRegistrationConfig, leaving Metadata.Scope empty
  2. Connect to an MCP server whose auth server enforces scope restrictions on DCR clients (i.e. the authorization endpoint rejects scopes the client wasn't registered for)
  3. The server's Protected Resource Metadata advertises scopes_supported
  4. The 401 response does not include a WWW-Authenticate header with a scope parameter

The SDK discovers the PRM scopes, registers the client without them, then requests authorization with them and the auth server rejects the request.

Expected behavior

The SDK should propagate the discovered scopes into DynamicClientRegistrationConfig.Metadata.Scope before calling RegisterClient, so the client is registered for the same scopes it will request. Callers who explicitly set Scope should not be affected.

Logs

Error: calling "initialize": sending "initialize": rejected by transport: authorization error: invalid_scope: OAuth 2.0 Parameter: scope

Additional context

The fix is to move scope computation above handleRegistration, and set the DCR metadata scope when the caller didn't provide one:

if dcrCfg := h.config.DynamicClientRegistrationConfig; dcrCfg != nil && dcrCfg.Metadata.Scope == "" && len(requestedScopes) > 0 {
dcrCfg.Metadata.Scope = strings.Join(requestedScopes, " ")
}

I believe this would also match what is described in the Scope Selection Strategy section of the specification as well

Reproduced on v1.6.1 and v1.7.0-pre.3. I've made a small change locally that seems to fix the issue I'm seeing. I'm happy to put that up as a PR if that'd be helpful but wanted to confirm the behavior with you first. Thanks!

Edit:
It seems like what I'm describing is what happens with the typescript-sdk. Looks like they are resolving the scopes here. Then registering the DCR client here with those scopes. I don't know what the correct behavior is, but I think there's a difference.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with AuthorizationCodeHandler and trace how requestedScopes are computed relative to handleRegistration and RegisterClient. Check how DynamicClientRegistrationConfig.Metadata.Scope distinguishes caller-provided values, then verify that discovered scopes are present in DCR metadata before authorization while explicit Scope values remain unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
authentication
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.