Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Comments

Exclude MCP SDK 1.21.1 and add scope validation to InMemoryOAuthProvider#2422

Merged
jlowin merged 4 commits intomainfrom
exclude-mcp-1.21.1-add-scope-validation
Nov 15, 2025
Merged

Exclude MCP SDK 1.21.1 and add scope validation to InMemoryOAuthProvider#2422
jlowin merged 4 commits intomainfrom
exclude-mcp-1.21.1-add-scope-validation

Conversation

@jlowin
Copy link
Member

@jlowin jlowin commented Nov 15, 2025

This PR addresses the MCP SDK 1.21.1 bug that incorrectly adds the protected resource metadata URL to OAuth scopes.

Changes

  • Exclude MCP SDK 1.21.1: Added version exclusion !=1.21.1 to prevent installation of the buggy version
  • Add scope validation to InMemoryOAuthProvider: Added scope validation that matches MCP SDK behavior, ensuring unit tests catch scope-related bugs
  • Update OAuth client tests: Configure tests to use valid scopes and validate them, ensuring tests properly catch the SDK bug

Testing

  • All OAuth client tests pass with MCP SDK 1.21.0
  • Tests correctly fail with MCP SDK 1.21.1 (demonstrating the bug)
  • Scope validation in InMemoryOAuthProvider matches MCP SDK registration handler behavior

1.21.1 is responsible for the integration test failures we've been seeing lately.

Related

This is a temporary workaround until the MCP SDK bug is fixed. Once fixed (or a new version is released), the version exclusion can be removed -- most likely when we raise the floor to account for the MCP protcol update in a couple weeks. NOTE: the changes to unit tests are not temporary; only the need to avoid this version.

- Exclude MCP SDK 1.21.1 due to bug adding metadata URL to scopes
- Update OAuth client tests to use valid scopes
…oint

- Add scope validation to InMemoryOAuthProvider.register_client() to match MCP SDK behavior
- Ensures unit tests catch scope-related bugs like the MCP SDK 1.21.1 issue
- Remove debug breakpoint from OAuth client redirect_handler
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

Adds explicit runtime validation and presence checks for client identifiers and scopes across the in-memory auth provider and OAuth proxy. Client registration now validates requested scopes against configured valid_scopes and raises ValueError for invalid scopes or missing client_id. Authorization and token-exchange flows now validate client_id presence and raise AuthorizeError or TokenError as appropriate; redirect URI and token payload handling were made more robust to safely handle None values.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: excluding MCP SDK 1.21.1 and adding scope validation to InMemoryOAuthProvider, matching the changeset.
Description check ✅ Passed The description provides clear context about the MCP SDK 1.21.1 bug, explains the changes, includes testing information, and notes it's temporary, but the contributors checklist items are not marked as complete.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch exclude-mcp-1.21.1-add-scope-validation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Add null checks for client_id before using in OAuthTransaction, AuthorizationCode, AccessToken, RefreshToken
- Add null check for redirect_uris before len() call
- Import AuthorizeError from mcp.server.auth.provider
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/fastmcp/server/auth/oauth_proxy.py (1)

1184-1197: Move client_id validation before UpstreamTokenSet construction.

There's a logic ordering issue: Line 1184 uses client.client_id or "" as a fallback, but the validation check at lines 1196-1197 occurs afterward. If client.client_id is None, you'll store an empty string in UpstreamTokenSet before the validation fails.

Move the validation check from lines 1196-1197 to occur immediately after Line 1125 (before constructing UpstreamTokenSet). Once validated, Line 1184 can safely use client.client_id without the fallback:

         # Clean up client code (one-time use)
         await self._code_store.delete(key=authorization_code.code)
 
+        # Validate client_id presence before token operations
+        if client.client_id is None:
+            raise TokenError("invalid_client", "Client ID is required")
+
         # Generate IDs for token storage
         upstream_token_id = secrets.token_urlsafe(32)

Then at Line 1184, simplify to:

-            client_id=client.client_id or "",
+            client_id=client.client_id,

And remove the now-redundant check at lines 1196-1197:

-        # Issue minimal FastMCP access token (just a reference via JTI)
-        if client.client_id is None:
-            raise TokenError("invalid_client", "Client ID is required")
         fastmcp_access_token = self._jwt_issuer.issue_access_token(
🧹 Nitpick comments (2)
src/fastmcp/server/auth/providers/in_memory.py (2)

69-81: LGTM! Scope validation correctly matches MCP SDK behavior.

The scope validation logic properly validates requested scopes against configured valid_scopes, matching the MCP SDK registration handler behavior as intended per the PR objectives. The implementation correctly handles the preconditions and provides clear error messages listing invalid scopes.

If you'd like to address the static analysis hint, consider defining a custom exception class for scope validation errors:

class InvalidScopeError(ValueError):
    """Raised when requested scopes are not valid."""
    pass

Then use it:

             if invalid_scopes:
-                raise ValueError(
-                    f"Requested scopes are not valid: {', '.join(invalid_scopes)}"
-                )
+                raise InvalidScopeError(
+                    f"Requested scopes are not valid: {', '.join(invalid_scopes)}"
+                )

However, this is purely optional for cleaner exception handling patterns.


83-84: LGTM! Essential validation to prevent invalid registrations.

This validation ensures that only clients with valid client_id values can be registered, preventing downstream errors in the OAuth flow.

Similar to the scope validation above, you could optionally define a custom exception class to address the static analysis hint, but this is not critical.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1895f86 and d40f22b.

⛔ Files ignored due to path filters (3)
  • tests/integration_tests/auth/test_github_provider_integration.py is excluded by none and included by none
  • tests/server/auth/test_oidc_proxy.py is excluded by none and included by none
  • tests/server/test_auth_integration.py is excluded by none and included by none
📒 Files selected for processing (2)
  • src/fastmcp/server/auth/oauth_proxy.py (8 hunks)
  • src/fastmcp/server/auth/providers/in_memory.py (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/fastmcp/server/auth/providers/in_memory.py (1)
src/fastmcp/server/context.py (1)
  • client_id (291-297)
src/fastmcp/server/auth/oauth_proxy.py (1)
src/fastmcp/server/context.py (1)
  • client_id (291-297)
🪛 Ruff (0.14.4)
src/fastmcp/server/auth/providers/in_memory.py

79-81: Avoid specifying long messages outside the exception class

(TRY003)


84-84: Avoid specifying long messages outside the exception class

(TRY003)

src/fastmcp/server/auth/oauth_proxy.py

946-946: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (10)
src/fastmcp/server/auth/oauth_proxy.py (6)

47-47: LGTM - Import needed for OAuth error handling.

The AuthorizeError import is correctly added to support OAuth 2.1-compliant error responses in authorization flows.


945-946: LGTM - Essential client_id validation added.

The validation correctly prevents registration of clients without a client_id, which would cause downstream issues. The ValueError is appropriate for invalid input during registration.

Note: The PR objectives mention adding "scope validation to match MCP SDK registration handler behavior," but I don't see scope validation logic in this method. Is scope validation implemented elsewhere or still pending?


976-976: LGTM - Defensive programming for logging safety.

The None check prevents potential AttributeError when logging redirect URI count. While the code at Line 950 provides a default value, this defensive check improves robustness.


1013-1016: LGTM - Appropriate OAuth error handling.

The validation correctly raises AuthorizeError with the standard OAuth 2.1 error code "invalid_client" before creating the transaction. This prevents downstream issues in the authorization flow.


1095-1098: LGTM - Consistent OAuth error handling.

The validation correctly raises AuthorizeError before constructing the AuthorizationCode object. This is consistent with the validation pattern used in the authorize method.


1393-1394: LGTM - Appropriate token endpoint error handling.

The validation correctly raises TokenError with the OAuth-compliant "invalid_client" error code before issuing new tokens. This is properly placed before token operations.

src/fastmcp/server/auth/providers/in_memory.py (4)

110-110: LGTM! Good defensive guard for redirect_uris check.

Adding the guard to check whether client.redirect_uris exists before checking membership prevents potential errors when redirect_uris is None or undefined.


129-132: LGTM! Defensive validation prevents downstream errors.

This check ensures client_id is present before creating the AuthorizationCode object (line 135). While the registration validation (lines 83-84) prevents None client_id in registered clients, this provides defense-in-depth since the client parameter is passed from external callers.


189-190: LGTM! Consistent defensive validation in token exchange.

This validation mirrors the pattern in the authorize method and prevents errors when creating AccessToken and RefreshToken objects that require client_id (lines 193, 199).


261-262: LGTM! Completes consistent validation across all token operations.

This validation maintains consistency with the authorization code exchange method and ensures client_id is valid for creating new tokens during refresh token rotation (lines 265, 271).

@jlowin jlowin merged commit e6936d0 into main Nov 15, 2025
17 of 19 checks passed
@jlowin jlowin deleted the exclude-mcp-1.21.1-add-scope-validation branch November 15, 2025 17:22
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