Skip to content

Replace authorization request parameters the endpoint URL already carries - #566

Merged
koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:override_query_parameters_of_the_authorization_endpoint
Sep 22, 2026
Merged

koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:override_query_parameters_of_the_authorization_endpoint

Conversation

@koic

@koic koic commented Sep 21, 2026

Copy link
Copy Markdown
Member

Motivation and Context

Flow#build_authorization_url appended the flow's parameters after whatever query the authorization server metadata's authorization_endpoint already carried. An endpoint URL carrying client_id, redirect_uri, state, code_challenge, or resource of its own therefore produced a request with each of them twice, the URL's value first. RFC 6749 Section 3.1 forbids sending a parameter more than once, and which value a server honors is its own choice; on the legacy 2025-03-26 path the endpoint URL is served by the MCP server itself, so its query could speak for the client's identity, redirect URI, PKCE challenge, and resource at the authorization server.

A parameter the flow sets now replaces one of the same name in the endpoint URL, and the rest of the URL's query is kept, which is what the TypeScript SDK's searchParams.set does.

request and request_uri are dropped from the endpoint URL's query as well, although the flow sets neither. RFC 9101 has an authorization server take the whole authorization request from the object they carry, over every parameter in the query, and both are the client's to send, so an endpoint URL holding one of them could speak for the client through that door too. A scope in the endpoint URL stays when the flow has none of its own, as it does in the TypeScript SDK: an authorization server may place a default scope on its own endpoint URL.

How Has This Been Tested?

A new test in test/mcp/client/oauth/flow_test.rb serves an authorization_endpoint whose query carries those parameters and one more, and checks that the authorization URL holds each parameter once with the flow's value while keeping the extra one. It fails against the previous library.

Two more tests in the same file check that request and request_uri in the endpoint URL's query are dropped, and that a scope there stays when the flow has none; the first of them fails against the previous library.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

…ries

## Motivation and Context

`Flow#build_authorization_url` appended the flow's parameters after whatever query the authorization server
metadata's `authorization_endpoint` already carried. An endpoint URL carrying `client_id`, `redirect_uri`,
`state`, `code_challenge`, or `resource` of its own therefore produced a request with each of them twice,
the URL's value first. RFC 6749 Section 3.1 forbids sending a parameter more than once, and which value
a server honors is its own choice; on the legacy 2025-03-26 path the endpoint URL is served by the MCP server itself,
so its query could speak for the client's identity, redirect URI, PKCE challenge, and resource at the authorization server.

A parameter the flow sets now replaces one of the same name in the endpoint URL, and the rest of the URL's query is kept,
which is what the TypeScript SDK's `searchParams.set` does.

`request` and `request_uri` are dropped from the endpoint URL's query as well, although the flow sets neither.
RFC 9101 has an authorization server take the whole authorization request from the object they carry,
over every parameter in the query, and both are the client's to send, so an endpoint URL holding one of them
could speak for the client through that door too. A `scope` in the endpoint URL stays when the flow has none of its own,
as it does in the TypeScript SDK: an authorization server may place a default scope on its own endpoint URL.

## How Has This Been Tested?

A new test in `test/mcp/client/oauth/flow_test.rb` serves an `authorization_endpoint` whose query carries
those parameters and one more, and checks that the authorization URL holds each parameter once with
the flow's value while keeping the extra one. It fails against the previous library.

Two more tests in the same file check that `request` and `request_uri` in the endpoint URL's query are dropped,
and that a `scope` there stays when the flow has none; the first of them fails against the previous library.

## Breaking Changes

None.
@koic
koic merged commit 08f1acf into modelcontextprotocol:main Sep 22, 2026
11 checks passed
@koic
koic deleted the override_query_parameters_of_the_authorization_endpoint branch September 22, 2026 05:13
Sign up for free to 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.

1 participant