Title: Add docs, tested examples, and a story for SEP-990 identity assertion by maxisbey · Pull Request #3004 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Add docs, tested examples, and a story for SEP-990 identity assertion by maxisbey · Pull Request #3004 · modelcontextprotocol/python-sdk
X Title: Add docs, tested examples, and a story for SEP-990 identity assertion by maxisbey · Pull Request #3004 · modelcontextprotocol/python-sdk
Description: Documentation for the Identity Assertion Authorization Grant (SEP-990) that #2988 added. That PR shipped the implementation with two snippets under examples/snippets/ and a migration-guide entry; this adds the book page, the tested docs_src/ examples behind it, and a self-verifying story, in the architecture #2978 established. Motivation and Context IdentityAssertionOAuthProvider, exchange_identity_assertion, and AuthSettings(identity_assertion_enabled=...) are public API with no presence in the docs book, and nothing renders or executes the examples/snippets/ files. Concretely: docs/advanced/identity-assertion.md, a new page after OAuth clients in the nav. It covers both halves: the client provider (and its inverted trust model: the authorization server is configuration, never discovered from the MCP server) and the authorization-server hook. It is careful to keep the two parties apart that the rest of the book is allowed to blur: the enterprise IdP that issues the ID-JAG, and the MCP authorization server that accepts it. The two existing auth pages each gain a one-paragraph cross-reference. docs_src/identity_assertion/: the page's two included examples. The client uses the modern Client API with an in-process stand-in IdP. The authorization server really validates the ID-JAG with pyjwt (signature, typ, iss/aud/exp, the client_id match, jti replay, and an ID-JAG for a resource it does not serve is refused with invalid_target) instead of stubbing the validation out. tests/docs_src/test_identity_assertion.py proves the page's claims, including the whole grant end to end across two in-memory ASGI apps. The recorded wire is one 401, the issuer's well-known fetch, one POST /token, and the retried request: no /authorize, no /register, no protected-resource-metadata fetch. examples/stories/identity_assertion/: a self-verifying story (stand-in IdP, authorization server, bearer-gated MCP server, client), registered in the stories manifest and run by the tests/examples/ matrix over both server variants and both protocol eras. Two things worth a reviewer's attention: The shipped client snippet cannot complete the flow it demonstrates. examples/snippets/clients/identity_assertion_client.py sets issuer="http://localhost:8001", but an authorization server built with create_auth_routes serves its metadata issuer from an AnyHttpUrl, which renders a path-less origin as http://localhost:8001/. The provider's RFC 8414 §3.3 comparison is an exact string match, so discovery stops at issuer mismatch. It shipped that way because nothing executes the snippets, which is the gap this PR closes; the new page documents the exact-match rule and the end-to-end test pins it. I left the examples/snippets/ files untouched here and can fix or fold them into the story as a follow-up. tests/docs_src/test_shape.py loses the plain-ASCII typography check. It enforced a style preference (no em dashes, curly quotes, arrows, section signs) as a hard CI failure across every book page and example, which also blocks legitimate typography such as the section sign in an RFC citation (RFC 7523 §3) that the SDK's own docstrings already use. The plain-ASCII style stays as the convention the book follows; the gate goes. How Has This Been Tested? ./scripts/test (the full suite, 100% branch coverage, strict-no-cover), pre-commit run --all-files, and uv run mkdocs build --strict are green. The new docs test wires the page's two example files together and runs the whole grant in memory, asserting the request sequence, the exact token-request form, and that the sub the IdP signed is what get_access_token().subject reports inside a tool. The story passes the tests/examples/ matrix (both server variants, both protocol eras), and its README commands run for real: uv run python -m stories.identity_assertion.client --http self-hosts a uvicorn server and exits OK. Breaking Changes None. Docs, examples, and tests only; nothing under src/ changes. 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 Additional context The page presents this as an optional extension (Enterprise-Managed Authorization), not as part of a protocol release, and is deliberate about the two RFCs: obtaining the ID-JAG from the IdP is an RFC 8693 token exchange and out of the SDK's scope; what the SDK implements on both sides is the RFC 7523 jwt-bearer presentation of it. (#2988's title says RFC 8693; the merged implementation is RFC 7523, per the extension spec.) Also moves the stories README's mrtr row out of the "deferred" table, where it was stale: it has been runnable since #2998. AI Disclaimer
Open Graph Description: Documentation for the Identity Assertion Authorization Grant (SEP-990) that #2988 added. That PR shipped the implementation with two snippets under examples/snippets/ and a migration-guide entry; t...
X Description: Documentation for the Identity Assertion Authorization Grant (SEP-990) that #2988 added. That PR shipped the implementation with two snippets under examples/snippets/ and a migration-guide entry; t...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/pull/3004
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:148dc883-a76f-8fbf-6b17-985e28a39ff8 |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | BC40:248EA8:FFBA1:165668:6A5A40FA |
| html-safe-nonce | e5bcd47398635033b5eb6876703ea63c5ec4a09bd2d693dac894803031ee5261 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCQzQwOjI0OEVBODpGRkJBMToxNjU2Njg6NkE1QTQwRkEiLCJ2aXNpdG9yX2lkIjoiNzY4NzU4MjQwODkzOTAyODczMCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 5fc4a42bb1c0cb0c26e366ebd1b46936e482b9598bf97a495752d8f617ddeccd |
| hovercard-subject-tag | pull_request:3944191078 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/modelcontextprotocol/python-sdk/pull/3004/files |
| twitter:image | https://avatars.githubusercontent.com/u/224885523?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/224885523?s=400&v=4 |
| og:image:alt | Documentation for the Identity Assertion Authorization Grant (SEP-990) that #2988 added. That PR shipped the implementation with two snippets under examples/snippets/ and a migration-guide entry; t... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | 19c67ad7579d2401ff06e88a32ef45460fbb40fab3191c7f7582d5e166f326fc |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | e618485bff22dab2ef1ffb4e34e4e6626688df69 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width