Skip to content

Conversation

Ujjwal-Bajpayee
Copy link

Summary

This PR implements token issuer validation in the MCP Python SDK client to ensure compliance with the MCP specification requirement:

"MCP clients MUST NOT send tokens to the MCP server other than ones issued by the MCP server's authorization server."

Previously, the SDK only checked for token existence and expiration.
This change adds verification that tokens were issued by the expected authorization server before they are used.


What I Changed

auth.py

  • Added an optional field expected_issuer: str | None = None to OAuthContext.
  • Updated is_token_valid() to:
    • Keep the original token existence and expiration checks.
    • If expected_issuer is not set, preserve the original behavior.
    • If expected_issuer is set, decode the access token (assuming JWT format), extract the iss claim, and verify that it matches self.expected_issuer.
    • Return False for missing/mismatched issuers or parsing errors.
  • Added a private helper method:

Why This Is Safe and Backward-Compatible

  • If expected_issuer is not provided, behavior is identical to previous versions.
  • No function signatures or external APIs were changed.
  • Only is_token_valid and one private helper were modified.
  • Errors or malformed tokens default to a safe False return value (fail closed).
  • The update adds a security and compliance improvement without introducing breaking changes.

Validation Performed

  • Verified local compilation — no syntax or import errors.
  • Checked runtime behavior for valid/invalid/missing iss claims.
  • Confirmed is_token_valid() correctly respects token expiry and issuer matching.
  • Ensured all existing authentication flows remain functional.

🔗 Related Issue

Closes #1442


Type of Change

  • Bug fix (non-breaking change that fixes a compliance/security issue)
  • New feature
  • Refactor
  • Test update only
  • Documentation update

@felixweinberger felixweinberger added auth Issues and PRs related to Authentication / OAuth improves spec compliance When a change improves ability of SDK users to comply with spec definition needs more eyes Needs alignment among maintainers whether this is something we want to add labels Oct 8, 2025
Copy link
Member

@pcarleton pcarleton left a comment

Choose a reason for hiding this comment

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

This helps with catching incorrect tokens sent to the MCP Server, preventing a class of MITIM attack. This will only help with JWT-based tokens, leaving the issue unsolved for opaque tokens. A more complete solution would involve e.g. requiring AS's send an ?issuer= param on their callback, and checking that. However, that would require a specification change, so this is still an improvement in the interim.

So, overall 👍 to this approach.

I left a few comments, and then please add a test, both for JWT tokens, opaque tokens, and an opaque token that has .'s but is not a JWT.

return False

# If no expected issuer is configured, behave as before
if not getattr(self, "expected_issuer", None):
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if not getattr(self, "expected_issuer", None):
if not self.expected_issuer:

no need for get_attr here afaict

logger.exception("Failed to validate token issuer")
return False

def _token_issuer_matches(self, token: str) -> bool:
Copy link
Member

Choose a reason for hiding this comment

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

I'd rather we use a library for JWT parsing rather than do it partially here, e.g. PyJWT

@pcarleton pcarleton added needs more work Not ready to be merged yet, needs additional changes. and removed needs more eyes Needs alignment among maintainers whether this is something we want to add labels Oct 10, 2025
@Ujjwal-Bajpayee
Copy link
Author

@pcarleton Thanks for the feedback. I’ll update to use direct access for expected_issuer, switch to PyJWT for parsing, and add the requested tests for JWT and opaque tokens. I’ll push the changes and update the PR soon.

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

Labels

auth Issues and PRs related to Authentication / OAuth improves spec compliance When a change improves ability of SDK users to comply with spec definition needs more work Not ready to be merged yet, needs additional changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP Python SDK Implementation Gap-10: MCP Python SDK Client Missing Token Issuer Validation

3 participants