Skip to content

Comments

feat: add subject and claims fields to AccessToken#2125

Open
aptsalt wants to merge 1 commit intomodelcontextprotocol:mainfrom
aptsalt:feat/access-token-subject-claims
Open

feat: add subject and claims fields to AccessToken#2125
aptsalt wants to merge 1 commit intomodelcontextprotocol:mainfrom
aptsalt:feat/access-token-subject-claims

Conversation

@aptsalt
Copy link

@aptsalt aptsalt commented Feb 22, 2026

Summary

Adds optional subject and claims fields to AccessToken, allowing token verifiers to expose decoded JWT claims without requiring consumers to re-decode the token.

Problem: After token verification, there's no way to access the JWT sub claim (user ID) or custom claims through AccessToken. Consumers must decode the token a second time or add custom middleware, as described in #1038.

Solution:

class AccessToken(BaseModel):
    token: str
    client_id: str
    scopes: list[str]
    expires_at: int | None = None
    resource: str | None = None
    subject: str | None = None      # NEW: JWT "sub" claim
    claims: dict[str, Any] | None = None  # NEW: additional token claims

Usage in a token verifier:

class MyTokenVerifier:
    async def verify_token(self, token: str) -> AccessToken | None:
        token_claims = decode_and_validate_jwt(token)
        return AccessToken(
            token=token,
            client_id=token_claims["client_id"],
            scopes=token_claims.get("scope", "").split(),
            subject=token_claims.get("sub"),
            claims=token_claims,
        )

Then in tool handlers:

user_id = get_access_token().subject
org_id = get_access_token().claims.get("org_id")

Changes

  • src/mcp/server/auth/provider.py: Add subject and claims optional fields to AccessToken
  • tests/server/auth/test_provider.py: Add 7 tests covering new fields, backward compatibility, and serialization roundtrip

Breaking Changes

None. Both fields default to None. Existing code is unaffected.

Test Plan

  • 7 new tests added (all passing)
  • Full auth test suite passes (60/60)
  • Pyright type checking passes (0 errors)
  • Ruff lint and format pass

Resolves #1038

Add optional `subject` and `claims` fields to `AccessToken` to support
JWT claim access without requiring token re-decoding.

- `subject: str | None` stores the JWT "sub" claim (user/resource owner ID)
- `claims: dict[str, Any] | None` stores additional decoded token claims

Both fields are optional with None defaults, maintaining full backward
compatibility.

Resolves modelcontextprotocol#1038
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.

MCP server: AccessToken class should have field for subject claim ("sub")

1 participant