GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||
GeezerVison is showing github.com — Deprecate constructing the pre-provisioned OAuth clients without an issuer by maxisbey · Pull Request #3435 · modelcontextprotocol/python-sdk Conversation
|
📚 Documentation preview
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 6 files
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The warning is already attributed to the caller's constructor line, so it does not need the provider name or server URL; _checked_issuer keeps its single argument.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
Additional findings (outside the current diff — GitHub can't attach inline comments there):
🟡 src/mcp/client/auth/extensions/client_credentials.py — nit: the PrivateKeyJWT-side docstring examples in this file still construct providers without issuer=, so a user copying the SDK's own documented code now gets the very UserWarning this PR adds (and a pytest suite with warnings-as-errors fails), which the base branch did not do. Fix: add issuer="https://auth.example.com" (or a one-line note about the warning) to every example in this module that omits it — the PrivateKeyJWTOAuthProvider class docstring Options 1-3 (lines 273-310), static_assertion_provider (174-179), and SignedJWTParameters (208-213); the ClientCredentialsOAuthProvider example already has it. [also at: src/mcp/client/auth/extensions/client_credentials.py:309 - nit: the PrivateKeyJWTOAuthProvider class docstring example constructs the provider without issuer=, so anyone…]
This PR makes _checked_issuer(None) emit a UserWarning at construction (src/mcp/client/auth/extensions/client_credentials.py:27-33), and it updated the docs page, the example story, and every in-repo test to pass issuer=. But the module's own public docstrings were only updated in their Args sections: the PrivateKeyJWTOAuthProvider class docstring shows three copy-paste examples (Option 1 ~lines 273-279, Option 2 ~286-292, Option 3 ~304-310), and static_assertion_provider (~174-179) and SignedJWTParameters (~208-213) show two more, all constructing the provider without issuer=. A developer who copies any of these verbatim — the normal way these docstrings are consumed — now sees UserWarning: No issuer given... on every construction, and if their test suite runs with filterwarnings = ["error"] (the convention this repo itself follows) their tests fail outright; on the base branch the same copied code ran silently. The ClientCredentialsOAuthProvider class example (lines 75-82) already includes issuer=, showing the intended pattern; the five…
Verification: nit — triggered whenever a user copies one of this module's own docstring examples verbatim. Mechanism verified: _checked_issuer() at src/mcp/client/auth/extensions/client_credentials.py:27-33 now emits warnings.warn("No issuer given: ...", stacklevel=3) when issuer is None, and the PR updated docs/client/oauth-clients.md, the example story, and all in-repo tests to pass issuer= —…
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
…ssuer The warning becomes an MCPDeprecationWarning: omitting `issuer=` on ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider keeps working in 2.x and will be required in 3.0. The message says why (without it the MCP server decides which authorization server receives the credentials) and what to pass. docs/deprecated.md lists it next to the other SDK-level deprecation, and the OAuth clients page points there.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I re-reviewed the rework that turned the construction warning into an MCPDeprecationWarning and found no bugs; since omitting issuer= now formally becomes required in 3.0, a maintainer's eye on that compatibility-contract commitment is still worthwhile.
What was reviewed: the _checked_issuer restructure in src/mcp/client/auth/extensions/client_credentials.py is behavior-preserving (None warns and falls through as before; non-None keeps the http(s) check), and stacklevel=3 correctly attributes the warning to the constructor call site, pinned by the new warning.filename == __file__ test.
Checked every in-repo construction site against the warnings-as-errors pytest config: all tests, the docs_src tutorial, and the example story now pass issuer= or use pytest.warns; the only remaining no-issuer caller is the conformance harness script, which runs outside pytest as the description notes.
Also confirmed the warning message in the new test matches the source string exactly, and that MCPDeprecationWarning was already exported from mcp, so no new public-API surface is added.
This PR deprecates constructing ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider without issuer=. The only source change is in src/mcp/client/auth/extensions/client_credentials.py: _checked_issuer() now emits an MCPDeprecationWarning (static message, stacklevel=3) when issuer is None, with the non-None validation path unchanged. Docstrings, docs/client/oauth-clients.md, and docs/deprecated.md are updated in the same PR, the example story passes issuer=BASE_URL, and tests across three files gain issuer= so the repo's filterwarnings = ["error"] config stays green. Two new parametrized tests pin the warning text, its attribution to the caller's file, and the unchanged no-issuer exchange behavior. Since my earlier review, commit 04dafcb substantively reworked the change from a plain UserWarning to the SDK's MCPDeprecationWarning with a 3.0-removal commitment, which is why a fresh review body is warranted.
The change sits in OAuth client code, but it does not alter any auth decision: the restructured _checked_issuer provably preserves both branches (None still returns None and the flow still follows discovered metadata; non-None still enforces an http(s) scheme). The deprecation itself is security-motivated in the right direction — it nudges callers toward pinning the authorization server that receives their credentials. No credentials, endpoints, or token-handling logic are touched.
Moderate. The mechanical risk is low (a warning plus docs and test plumbing), and I verified the details that could bite: stacklevel=3 walks warn → _checked_issuer → __init__ → caller correctly and is locked down by the warning.filename == __file__ assertion; the test's expected message string matches the source string character-for-character; and every pytest-covered construction site (tests, docs_src/oauth_clients/tutorial002.py, the example story) now passes issuer= or wraps in pytest.warns, so nothing trips warnings-as-errors. The one reason not to approve outright is policy, not correctness: AGENTS.md treats changes to an existing API's observable behavior — including deprecation-shimmed ones — as explicit maintainer design decisions, and this PR commits the 2.x line to making issuer= required in 3.0. That call belongs to a human maintainer.
The bug hunt ran to a natural dry-streak finish with no findings. Coverage of the new branch is handled by the two new tests (both the warning branch and the non-None validation branch are exercised). The only remaining no-issuer construction is .github/actions/conformance/client.py, which runs as a plain script where the warning just prints — the PR description acknowledges this. My earlier inline nit about the example README's "five lines" count versus the docstring's "six lines" was not addressed by the latest commit, but it is cosmetic and the open thread already records it, so I did not restate it in the body.
Still open from earlier reviews (1):
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The PrivateKeyJWTOAuthProvider, static_assertion_provider and SignedJWTParameters examples now show the non-deprecated form, and the client-credentials story stops counting its config lines.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Code review found no issues
No high-confidence issues detected in this change.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Code review found no issues
No high-confidence issues detected in this change.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
…ut an issuer Backport of #3435. Omitting `issuer=` on ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider keeps working and now warns at construction that it will be required in 3.0, saying why (without it the MCP server decides which authorization server receives the credentials) and what to pass. Difference from main: 1.x has no MCPDeprecationWarning, so the category is DeprecationWarning like the other deprecations on this branch, and there is no deprecations docs page to list it on; the docstrings carry the note and the module's examples pass `issuer=`.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.