* Use issuer_url for OAuth issuer identity, not base_url
* Apply ruff format to issuer identity tests
* Align ID-JAG audience docstring with issuer_url
* Make InMemoryOAuthProvider keyword-only like its parent
* Keep ID-JAG audience on base_url, out of scope for issuer identity
* Remove stray scratch script
* Make AuthorizationHandler keyword-only
* Bind ID-JAG audience to the issuer identifier
* Fix double slash in issuer_url well-known log hint
* Remove server-initiated sampling and roots from the server API
Deletes fastmcp/server/sampling/, Context.sample/sample_step/list_roots, and
FastMCP(sampling_handler=). The proxy's handshake-era relay now reaches the
front session through the SDK directly.
* Update tests for the removed sampling and roots server API
* Era-gate client.set_logging_level on modern connections
* Document that server-initiated sampling and roots are not in FastMCP 4
* Silence ty deprecation diagnostics and drop stale sampling doc mentions
* Baseline tools-call-sampling; fix removal leftovers flagged by ruff
* Document sampling handlers on both protocol routes; qualify log-level override
* Docs: sampling and roots work on modern via the guard pattern
The imperative ctx.sample()/ctx.list_roots() stay removed, but both
capabilities survive as input-required requests, as tests/conformance
exercises on 2026-07-28. Direct LLM calls remain the recommendation for
generation; roots has no round-trip-budget objection.
* Change register: record the guard route for sampling and roots
* Editorial pass on the sampling and roots docs
* Flag the sampling removal at the top of the page
* Restore the version badge and point sampling users at 3.x
* Keep the sampling conformance scenario live; fix roots example URIs
* Upgrade guide: staying on 3.x is an option for sampling servers
* Elicitation: state the era split once, not twice
Labels are bot-assigned from title/body/code; noting a "suggested" label
in the PR body was a leftover from an unrelated PR (#4392) and doesn't
match how this repo actually labels things.
The imperative ctx.sample()/ctx.list_roots() stay removed, but both
capabilities survive as input-required requests, as tests/conformance
exercises on 2026-07-28. Direct LLM calls remain the recommendation for
generation; roots has no round-trip-budget objection.
A proxy has no back-channel to the real user, so driving a backend ask inside
it failed outright. Surface it as a result for the parent, as ProxyTool does.
Partial fulfillment means two in-flight updates can carry different answers,
so acknowledging the one that loses the update lock stranded the task on a key
the client had already sent.
Prompt and resource asks carry no content, so caching one stored an empty
result and the client never saw the question. Bypass the cache on
continuation legs and return asks unwrapped, as tool calls already did.
Keep the final outstanding input marker until the next task leg is durable,
so a racing tasks/get cannot read a parked leg as complete. Let resources and
resource templates return InputRequiredResult like tools and prompts. Identify
parked requests by their question rather than sort order.
Deletes fastmcp/server/sampling/, Context.sample/sample_step/list_roots, and
FastMCP(sampling_handler=). The proxy's handshake-era relay now reaches the
front session through the SDK directly.
* Honor OAuth application_type in DCR (SEP-837)
* Simplify web redirect check per ruff SIM103
* Enforce application_type over HTTP, at auth time, and tighten native scheme rules
Recover the DCR application_type the SDK RegistrationHandler drops (P1), enforce the stored type on the authorization redirect path (P2), restrict native to loopback http + custom schemes (P2), and document the web/native rules (P2).
* Fix loopback range detection and use a positive scheme allowlist
Classify loopback hosts with ipaddress.is_loopback so all of 127.0.0.0/8 counts (a web client could bypass the non-loopback rule with 127.0.0.2). Replace the NON_REDIRECT_NETWORK_SCHEMES denylist with STANDARD_URI_SCHEMES: native now accepts only https, loopback http, and unregistered private-use schemes per RFC 8252, so smb/smtp/nfs and other unlisted standard schemes no longer pass.
* Vendor the IANA scheme registry and consolidate the loopback classifier
Replace the hand-picked STANDARD_URI_SCHEMES with a vendored snapshot of the IANA URI scheme registry (423 schemes), so registered transports nobody enumerated (coap, coaps, stun, turn, mqtt) fail closed instead of passing as private-use. Delete the stale duplicate _is_loopback_host in oauth_proxy/models.py and reuse the ipaddress-based classifier from redirect_validation, restoring loopback port flexibility across all of 127.0.0.0/8.
* Treat the reserved localhost namespace and absolute host forms as loopback
RFC 6761 6.3 reserves the whole localhost namespace for the local machine, so app.localhost and localhost. are loopback just as much as localhost. Previously a web client could register https://app.localhost/callback and bypass the non-loopback rule, while native clients were wrongly refused legitimate http://app.localhost:3000 dev callbacks. The suffix test is anchored on a leading dot so localhost.evil.com and notlocalhost stay non-loopback.
* Narrow scope: drop native scheme classification, keep the web rule
Registry membership cannot separate app-dispatch schemes from network transports (vscode is registered because it is an app scheme), so classifying a native client's scheme rejected callbacks that real MCP clients need. Remove the vendored registry and the private-use test; native now accepts any scheme outside the unsafe set, with cleartext http still limited to loopback. Also reject web registrations that omit redirect_uris rather than storing an unusable localhost placeholder.
* fix : canonical mime type mapping from formats to remove inconsistency
* Apply ruff format to _get_mime_type
---------
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
* Signal component-level scope shortfalls as insufficient_scope (SEP-2350)
* Fix ty type narrowing in scope step-up test
* Respect check short-circuit when reporting scope shortfall (P2)
* Report union of unmet scopes and document step-up contract
* Aggregate scope shortfall across the AuthMiddleware chain
* Stop chain scope aggregation at the first unevaluated gate
* Unpublish v4 development notes; prep docs for beta 1
* Nest development notes under dev-docs/
* Rewrite site-root links in dev notes as absolute URLs for GitHub rendering
2.1.216 regressed the bubblewrap sandbox the action wraps Bash in when
allowed_non_write_users is set, so every command failed and triage applied
zero labels while reporting success. Also fail the triage job on sandbox
errors, which the existing denial guard could not see.
The example called proxy.with_namespace("remote"), which is not defined
anywhere in the codebase and raises AttributeError. Namespacing a provider
is done via the add_provider() keyword argument.