Skip to content

fix: normalize OAuth redirect URI URL subtypes#2947

Open
fengjikui wants to merge 2 commits into
modelcontextprotocol:mainfrom
fengjikui:codex/oauth-redirect-uri-normalize
Open

fix: normalize OAuth redirect URI URL subtypes#2947
fengjikui wants to merge 2 commits into
modelcontextprotocol:mainfrom
fengjikui:codex/oauth-redirect-uri-normalize

Conversation

@fengjikui

Copy link
Copy Markdown
Contributor

Fixes #2687

Summary

OAuth client metadata stores redirect_uris as AnyUrl, but Pydantic v2 preserves stricter URL subtype instances that callers pass in, such as AnyHttpUrl. Those subtype instances serialize to the same URL string as AnyUrl, but object equality is type-strict, so validate_redirect_uri(AnyUrl(...)) rejects a registered AnyHttpUrl(...) value.

This normalizes redirect_uris at the model boundary by stringifying Pydantic URL objects before validation. Pydantic then rebuilds them as the declared AnyUrl type. Raw strings and existing validation errors still follow the normal field validation path.

Evidence

Before the fix, the minimal repro fails:

stored_types ['AnyHttpUrl']
string_equal True
object_equal False
membership False
failed Redirect URI 'https://example.com/cb' not registered for client

After the fix, the same repro succeeds and JSON output is unchanged:

stored_types ['AnyUrl']
membership True
validated https://example.com/cb
json ['https://example.com/cb']

Validation

uv run --frozen pytest tests/shared/test_auth.py
uv run --frozen ruff format --check src/mcp/shared/auth.py tests/shared/test_auth.py
uv run --frozen ruff check src/mcp/shared/auth.py tests/shared/test_auth.py
uv run --frozen coverage erase && uv run --frozen coverage run -m pytest tests/shared/test_auth.py && uv run --frozen coverage combine && uv run --frozen coverage report --include='src/mcp/shared/auth.py' --fail-under=0 && UV_FROZEN=1 uv run --frozen strict-no-cover

AI Assistance

AI assistance was used to prepare this patch and validation notes.

@fengjikui fengjikui marked this pull request as ready for review June 22, 2026 15:19
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.

OAuthClientInformationFull.redirect_uris: pydantic strict-type-equality breaks AnyUrl(x) != AnyHttpUrl(x) round-trip

1 participant