Compare commits

..

319 commits

Author SHA1 Message Date
prefect-renovate[bot]
c9cf23779e
chore(deps): Update astral-sh/setup-uv action to v9 (#4806)
Co-authored-by: prefect-renovate[bot] <313130218+prefect-renovate[bot]@users.noreply.github.com>
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-14 13:56:10 -05:00
prefect-renovate[bot]
542cde677b
chore(deps): Update dependency node to v24 (#4807)
Co-authored-by: prefect-renovate[bot] <313130218+prefect-renovate[bot]@users.noreply.github.com>
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-14 13:49:31 -05:00
prefect-renovate[bot]
3a2d12abcf
chore(deps): Update j178/prek-action action to v3 (#4808)
Co-authored-by: prefect-renovate[bot] <313130218+prefect-renovate[bot]@users.noreply.github.com>
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-14 13:45:26 -05:00
Jeremiah Lowin
37321449d9
docs: add FastMCP 4 beta 3 release entries (#4841) 2026-08-14 13:43:56 -04:00
Jeremiah Lowin
59487837ee
docs: prepare FastMCP 4 beta 3 (#4840) 2026-08-14 13:33:22 -04:00
Akshay Parihar
46399056db
Scalekit issuer updates backward compatibility (#4798) 2026-08-14 13:21:54 -04:00
nate nowack
addb8fa541
Bump cryptography to 50.0.0 (#4836)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 13:16:22 -04:00
marvin-context-protocol[bot]
bab1073da2
chore: Update SDK documentation (#4832) 2026-08-14 13:15:03 -04:00
nate nowack
6ccbb570cc
Cover CallArgument resolution in background tasks (#4833)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 13:14:36 -04:00
nate nowack
38c054be1d
Fix static analysis under newer ty releases (#4831)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 13:09:44 -04:00
Chris Guidry
ba283ddb4c
Support CallArgument and Depends bindings from uncalled-for 0.4.0 (#4802)
* Support CallArgument and Depends bindings from uncalled-for 0.4.0

uncalled-for 0.4.0 adds explicit argument references: CallArgument()
lets a dependency factory read an argument of the function it serves,
and Depends(factory, **bindings) supplies factory arguments at the
declaration site (https://github.com/chrisguidry/uncalled-for/pull/12).
FastMCP's resolver now opens a frame_scope() around dependency
resolution, with the sanitized user arguments as the frame's provided
values. A CallArgument can reference a tool call's public parameters,
but a caller-supplied value for a dependency parameter name is still
stripped before resolution. CallArgument and CycleError are re-exported
from fastmcp.dependencies, and the dependency-injection docs cover both
features.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Raise the pydocket floor to 0.24.0 outside Windows

pydocket 0.24.0 resolves TaskArgument and CallArgument through
uncalled-for 0.4.0's call-scoped frames. Windows keeps the 0.20.0
floor: the burner-redis<0.1.7 pin there transitively caps pydocket to
<0.20.2, and burner-redis has shipped no fixed release yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bump the pydocket floor to 0.24.1 for reliable worker shutdown

docket 0.24.1 fixes a lost cancellation in worker shutdown on Python
3.10 and 3.11 (chrisguidry/docket#456): asyncio.wait_for swallowed a
cancellation delivered in the same event-loop tick that its inner future
completed, so cancelling run_forever during our lifespan teardown left
the worker running and hung the test session. That is what timed out the
Python 3.10 and lowest-direct jobs here. The floor stays platform-split;
Windows keeps >=0.20.0 under the burner-redis pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Drop the Windows burner-redis pin and unify the pydocket floor at 0.24.1

The pin blamed the wrong package. The Windows "interpreter crash" that
motivated it (#4618) was pydocket 0.23.1 losing an external cancellation
during worker teardown; pytest-timeout's hard kill of the hung xdist
worker discarded its stdout and looked like a native fault. Capping
burner-redis also dragged pydocket below 0.20.2, so the two variables
were never separated. The repro matrix on prefectlabs/burner-redis#7
shows the July environment failing as resolved, passing with only
pydocket rolled back, and passing with pydocket 0.24.1 alongside
burner-redis 0.1.7 on Windows. pydocket 0.24.1 carries the fix
(chrisguidry/docket#456), so every platform now shares one floor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-13 22:19:17 -05:00
marvin-context-protocol[bot]
fe93371d04
chore: Update SDK documentation (#4828)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-08-13 20:36:58 -05:00
Jeremiah Lowin
3dd0886156
Fix StatefulProxyClient reconnection after session failure (#4829) 2026-08-13 16:01:19 -04:00
nate nowack
822c82c93f
Add audience pinning to GoogleTokenVerifier (#4827)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 15:59:16 -04:00
Trevor Hudson
19d9360cc1
Keep earlier consent CSRF tokens valid within a transaction (#4818)
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-13 15:24:02 -04:00
Shaik Mohammed Kaif
2061bc46c7
fix(openapi): extract parameter-level example and examples (#4793) 2026-08-13 12:03:56 -04:00
Jeremiah Lowin
e108bc539e
Clarify auto-closed PR message (#4820) 2026-08-11 13:55:48 -04:00
nate nowack
6be0ac8e15
Fix partial hint resolution on Python 3.14 (#4796)
🤖 Generated with OpenAI Codex
2026-08-11 12:14:34 -05:00
Jeremiah Lowin
052889a359
Docs: mirror v3.4.7 release notes (#4811) 2026-08-10 17:16:20 -04:00
Eddie
bba8c44f7b
Add Prefect Horizon authentication client and local state (#4785)
* feat: add Horizon authentication client and state

* fix: apply Windows state ACLs to existing descriptors

* fix: distinguish public route authorization failures

* fix: harden Horizon state boundaries
2026-08-10 17:06:42 -04:00
Nicholas Brown
6475650fc7
Docs language dropdown (#4801)
* add language dropdown

* add dropdown to ts docs

* fix merge conflicts
2026-08-10 11:03:45 -05:00
marvin-context-protocol[bot]
8a1820f1c3
chore: Update SDK documentation (#4782)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-08-07 15:49:36 -05:00
Sai Mouli
06fee6d300
Serialize the event store's stream list read-modify-write (#4758)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-08-06 20:09:36 -04:00
Jamie Zieziula
706f7d2695
feat(renovate): migrate to Renovate, retire Dependabot (#4754)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-06 20:02:29 -04:00
Chris Guidry
1ac8fc6060
Encrypt task context snapshots at rest (#4772)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 20:01:40 -04:00
Jeremiah Lowin
04f9971120
Delegate typed tool output serialization to Pydantic (#4771) 2026-08-06 19:59:19 -04:00
marvin-context-protocol[bot]
803da5319c
chore: Update SDK documentation (#4679) 2026-08-06 19:56:40 -04:00
Jake Kaplan
9feb1f378b
Forward proxy server metadata across protocol eras (#4776)
* Forward proxy negotiation metadata

🤖 Generated with OpenAI Codex

* Limit forwarded proxy metadata

🤖 Generated with OpenAI Codex

* Tighten negotiation metadata forwarding

🤖 Generated with OpenAI Codex

* Tighten proxy metadata docs

🤖 Generated with OpenAI Codex

* Keep proxy metadata middleware with provider

🤖 Generated with OpenAI Codex

* Simplify proxy negotiation middleware API

🤖 Generated with OpenAI Codex

* Name proxy metadata middleware directly

🤖 Generated with OpenAI Codex

* Preserve discovery middleware contracts

🤖 Generated with OpenAI Codex

* Clarify proxy metadata ownership

🤖 Generated with OpenAI Codex

* Align proxy metadata wording

🤖 Generated with OpenAI Codex

* Call forwarded values server metadata

🤖 Generated with OpenAI Codex

* Harden proxy metadata reads

🤖 Generated with OpenAI Codex

* Expose configured discovery result

🤖 Generated with OpenAI Codex

* Preserve proxy discovery compatibility

🤖 Generated with OpenAI Codex

* Preserve deprecated initialization middleware

🤖 Generated with OpenAI Codex

* Harden proxy metadata boundaries

🤖 Generated with OpenAI Codex

* Restore deprecated middleware location

🤖 Generated with OpenAI Codex

* Simplify proxy metadata client lifecycle

🤖 Generated with OpenAI Codex

* Clarify proxy metadata lifecycle

🤖 Generated with OpenAI Codex

* Preserve proxy factory errors

🤖 Generated with OpenAI Codex

* Detach forwarded proxy metadata

🤖 Generated with OpenAI Codex

* Simplify proxy metadata implementation

🤖 Generated with OpenAI Codex

* Distinguish proxy metadata failures

🤖 Generated with OpenAI Codex

* Narrow proxy metadata validation fallback

🤖 Generated with OpenAI Codex

* Retrigger CI

🤖 Generated with OpenAI Codex
2026-08-06 19:09:05 -04:00
nate nowack
75fb116e36
Support EdDSA verification in JWTVerifier (#4752) 2026-08-06 14:09:37 -04:00
Jeremiah Lowin
6fb34e9383
Document MCP protocol support and conformance (#4781) 2026-08-06 11:15:38 -04:00
Yonatan
c8b88b3a37
fix(context): move elicit overload docs inside the stubs so mypy sees the chain (#4774) 2026-08-06 09:35:49 -04:00
Jeremiah Lowin
2bee9aeb58
Clarify review of closed contributor PRs (#4780) 2026-08-06 09:34:11 -04:00
Jeremiah Lowin
875e8e18bd
Preserve legacy httpx compatibility without importing it (#4766) 2026-08-05 18:09:16 -04:00
Jake Kaplan
959daf2321
Sanitize forwarded request metadata where the proxy copies it (#4770)
* Separate proxy protocol policy from client construction

🤖 Generated with OpenAI Codex

* Strip connection-owned request metadata at the proxy backend boundary

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Sanitize forwarded request metadata where the proxy copies it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Forward hop-safe request metadata for proxied resources, templates, and prompts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 15:46:10 -04:00
nate nowack
8661193411
Quote run-claude allowed tools argument (#4741)
Generated with Codex
2026-08-05 11:15:51 -04:00
Jeremiah Lowin
e4d8ca648a
Avoid loading MCP and CLI stacks during lightweight imports (#4763) 2026-08-05 10:56:13 -04:00
Jeremiah Lowin
2c2f98691f
Docs: mirror v3.4.6 release notes (#4764) 2026-08-05 10:53:15 -04:00
nate nowack
b9b7ea6914
Declare run-claude extra allowed tools input (#4740)
Generated with Codex
2026-08-05 10:39:35 -04:00
Sai Mouli
4f28dceac8
Don't cache error results in ResponseCachingMiddleware (#4705) 2026-08-04 17:15:01 -04:00
LHMQ878
db92d44ef5
Serve empty list results from the response cache (#4738) 2026-08-04 17:11:42 -04:00
Jeremiah Lowin
886776f5fc
Canonicalize response cache arguments (#4753)
Co-authored-by: LHMQ878 <LHMQ878@users.noreply.github.com>
2026-08-04 15:25:46 -04:00
Jeremiah Lowin
d267792653
docs: clarify external OAuth consent mode (#4746) 2026-08-03 18:02:09 -04:00
nate nowack
a7e9b70919
Fix static analysis with latest ty (#4739)
* Fix upgrade static analysis

Generated with Codex

* Preserve concrete transport return types

Generated with Codex

* Avoid widening transport return types

Generated with Codex

* Model transforming transport return types

Generated with Codex

* Exclude standalone screenshot examples from ty

Generated with Codex
2026-08-03 10:53:23 -05:00
Jeremiah Lowin
022547ad8c
Preserve string-compatible prompt arguments (#4730) 2026-08-02 14:56:05 -04:00
Jeremiah Lowin
34bdd480c9
Improve HTTP server startup performance (#4729) 2026-08-02 14:11:26 -04:00
Shuying
c428a08fea
fix: preserve valid servers during CLI discovery (#4714)
Co-authored-by: Shuying <zsy@u.northwestern.edu>
2026-08-02 09:42:26 -04:00
Martin Styk
10b158baf3
Forward enable_cimd to Auth0, AWS Cognito and OCI providers (#4719)
Signed-off-by: Martin Styk <mart.styk@gmail.com>
2026-08-02 09:42:06 -04:00
YAO_001
9034a2eb4b
Fix CodeMode tool error propagation (#4704)
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-08-02 09:41:36 -04:00
nate nowack
40c3e122e8
Write downloaded skill text as UTF-8 (#4715) 2026-08-02 09:33:32 -04:00
Jake Kaplan
bc07264529
Fix self-referential connection error causes (#4720)
🤖 Generated with OpenAI Codex
2026-07-30 16:23:33 -04:00
Jeremiah Lowin
bcef61d806
Route published docs through pull requests (#4713) 2026-07-30 10:18:03 -04:00
Nicholas Brown
0f18a258d4
add language dropdown (#4716) 2026-07-30 09:32:58 -04:00
nate nowack
44c0907dda
Give parallel Windows CI more timeout headroom (#4680)
pytest-timeout falls back to its thread method on Windows, which os._exit()s
the process instead of failing the test. A single slow test therefore kills an
xdist worker and fails whichever unrelated test it was running.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:22:17 -05:00
Jeremiah Lowin
07f6eafd99
Add comprehensive Codex code review rules (#4710) 2026-07-29 09:51:36 -04:00
Jeremiah Lowin
a22f778dbf
Rewrite the FastMCP docs welcome page (#4709) 2026-07-29 09:51:22 -04:00
Jeremiah Lowin
0792ac812c
Improve the v4 docs (#4707) 2026-07-29 09:51:13 -04:00
Jeremiah Lowin
7339936980
Rewrite the v4 What's New page and document server extensions (#4698)
* Rewrite the v4 What's New page

Teach the headline features with code instead of asserting them, drop the
major-version throat-clearing and SEP list, and correct the elicitation
claim: ctx.elicit() is unchanged and handshake-only, while sampling and
roots are removed outright.

* Fix broken doc links and stale version references

Repoint five dead links and anchors, refresh v3-era version examples on the
v4 docs, and add the missing FastMCP 3 entry to the installation page's
upgrade section.

* Document server extensions

add_extension() shipped in v4 with no documentation page. Covers the
extension interface, request methods, tool-call interception, lifespan
ownership, and the client half.

* Link the FastMCP TypeScript library

* Address Codex review feedback

Gate the extension interceptor on the client's per-request opt-in rather
than claiming negotiation does it; show the v4 beta pin on the install
page instead of a version a reader cannot get; note that UserSession
requires authentication.
2026-07-28 20:05:45 -04:00
Jeremiah Lowin
7a77805159
Use mcp.types directly instead of aliasing to mcp_types in docs (#4696) 2026-07-28 19:08:44 -04:00
Jeremiah Lowin
baced6281c
Always emit a tool title, derived from name when unset (#4694)
* Always emit a tool title, derived from name when unset

Some MCP clients (e.g. ChatGPT) drop tools with no `title` instead of
falling back to `name` for display as the spec allows. Deriving a
default title in Tool.to_mcp_tool() fixes this for every tool built on
top of it, including the search-transform, code-mode, and session
proxy tools that never set one explicitly.

Fixes #4414

* Derive fallback title from the overridden name, document it

Addresses Codex review on #4694.

* Resolve title precedence from effective overrides

* Normalize mapping annotations before deriving the title
2026-07-28 17:30:20 -04:00
Jeremiah Lowin
5a98ceb5ca
Add v4.0.0b1 changelog and updates entries (#4681)
* Add v4.0.0b1 changelog and updates entries

* Drop meta note from b1 intro; add #4682 under enhancements

* File #4682 under fixes

* Correct the camelCase rename claim: Python model fields, not the wire

* Baseline the b1 changelog on v3.4.5

* Simplify the beta banner
2026-07-28 17:15:48 -04:00
Jeremiah Lowin
8b76710e66
Move to the stable MCP Python SDK 2.0.0 (#4655) 2026-07-28 16:31:49 -04:00
Jeremiah Lowin
81b1e818e5
Apply app visibility where no host can (#4692) 2026-07-28 16:12:38 -04:00
Jeremiah Lowin
a8b5da9770
Late-bind app tool names so UIs survive composition (#4682) 2026-07-28 10:54:19 -04:00
Jeremiah Lowin
0175bc9235
Split the SDK upgrade guides by SDK version (#4684) 2026-07-28 10:47:39 -04:00
Jeremiah Lowin
d6b9daecb1
Read CLI-scanned MCP config files as UTF-8 explicitly (#4690) 2026-07-28 08:12:17 -04:00
Jeremiah Lowin
78c61415b5
Resolve review threads on fix, reply on decline (#4685)
* Resolve review threads on fix, reply on decline

* Use a placeholder PR number in the resolve example
2026-07-27 21:41:02 -04:00
Jeremiah Lowin
90ea26f337
Soften the review-comment reply guidance (#4683) 2026-07-27 21:06:12 -04:00
Jeremiah Lowin
f4ae8bb0af
Let maintenance releases publish without fastmcp-tasks (#4676) 2026-07-27 16:07:54 -04:00
Jeremiah Lowin
d382943012
Note that review comment threads should get an acknowledgement (#4678) 2026-07-27 16:07:39 -04:00
Jeremiah Lowin
7674645761
Flatten OpenAPI discriminator subtypes into request bodies (#4677)
* Flatten OpenAPI discriminator subtypes into request bodies

* Resolve schema-name discriminator mappings and union conflicting variant fields

* Advertise discriminator values for propertyless variants and document the behavior
2026-07-27 16:06:54 -04:00
Bill Easton
75b9f92504
feat: Add telemetry interop mode for FastMCP (#4046)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-27 16:05:29 -04:00
苏紫辰
c3cbe8b9a3
Fix OpenAPI allOf reference fields (#4653)
* Fix OpenAPI allOf reference fields

🤖 Generated with Codex

* Add allOf reference crash regression

🤖 Generated with Codex

* Handle OpenAPI component refs in allOf

🤖 Generated with Codex

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-27 15:25:22 -04:00
Jeremiah Lowin
ffea4d6a3e
Docs: add v3.4.5 changelog entries to main (#4674)
* Docs: add v3.4.5 changelog entries

* Condense the 3.4.5 entries to patch-release length
2026-07-27 15:13:03 -04:00
Eduardo Cruz Guedes
794bfe9567
Add valid_scopes parameter to OIDC proxy valid scopes (#4660)
* Accept valid_scopes on OIDCProxy

* Keep valid_scopes when verify_id_token restores scopes

* Document valid_scopes on the OIDC proxy

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-27 15:12:15 -04:00
marvin-context-protocol[bot]
11ee46bf3b
chore: Update SDK documentation (#4647)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-27 15:03:41 -04:00
Jeremiah Lowin
cc02df94c5
Audit v4 docs: fix missing version badges, fill whats-new gaps (#4668)
* Fix missing/wrong 4.0.0 version badges

* Fill v4 badge and whats-new gaps found in docs audit
2026-07-27 15:03:18 -04:00
Jeremiah Lowin
ea7fb8cb2e
Remove 3.x-era compatibility shims (#4661)
* Remove 3.x-era compatibility shims

* Require response_type in ctx.elicit()

* Name the utilities path for the two non-re-exported auth helpers

* Point sampling handler migration at its submodule
2026-07-27 14:59:43 -04:00
Jeremiah Lowin
1550eea886
Copy schemas iteratively so deep nesting still compresses (#4671)
* Copy schemas iteratively so deep nesting still compresses

* Keep $defs when the reference scan hits its depth limit
2026-07-27 14:58:13 -04:00
Jeremiah Lowin
e4ccf06baf
Fix FAQ: sampling/roots/elicitation legacy-mode advice, SessionProvider registration (#4672)
* Fix FAQ: narrow the legacy-mode recommendation, note SessionProvider registration

* Correct sampling's modern-protocol claim: guard pattern works, just isn't the recommended path
2026-07-27 14:57:35 -04:00
Jeremiah Lowin
886c85e5f5
Cover require_roles in the v4 highlights (#4666)
* Cover require_roles in whats-new

* Decouple require_roles from the SEP-990 example; require a claim-validating provider
2026-07-27 14:57:23 -04:00
Jeremiah Lowin
95edc1d2f3
Record effective scopes on the OAuth transaction (#4670) 2026-07-27 14:33:57 -04:00
Jeremiah Lowin
4e136e60d6
Document the issuer_url identity change for upgraders (#4658)
* Document the issuer_url identity change for upgraders

Adds an upgrade note covering the one-time re-authorization, fixes the MultiAuth examples that pointed issuer_url at the upstream IdP, and corrects the OCI docstring.

* Address review: valid docstring example, narrower reauth scope

* Scope the reauth checklist item to token-minting providers
2026-07-27 12:45:24 -04:00
Jeremiah Lowin
27a5921bff
Expand the FAQ for the v4 transition (#4649) 2026-07-27 12:41:32 -04:00
Jeremiah Lowin
920cb47778
Add require_roles auth check (#4656)
* Add require_roles auth check

* Make role docs runnable standalone and fully annotated

* Treat a scalar role claim as one role; correct step-up docs

* Add v4 version badge to require_roles docs
2026-07-27 12:36:58 -04:00
Jeremiah Lowin
0c1c42f151
Bind CIMD assertion audience to the advertised token endpoint (#4659)
A bare-authority base_url renders with a trailing slash, so the expected aud was https://host//token while the metadata advertised https://host/token.
2026-07-27 11:46:03 -04:00
Jeremiah Lowin
6c4ba6b420
Use the snake_case field name in the task return-type test (#4657) 2026-07-27 10:56:03 -04:00
Jeremiah Lowin
a42faab783
Use issuer_url for OAuth issuer identity (#4652)
* 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
2026-07-27 10:43:12 -04:00
Jeremiah Lowin
b1e0586d4e
Remove server-initiated sampling and roots from the server API (#4648)
* 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
2026-07-27 10:32:31 -04:00
Jeremiah Lowin
9ea5a40728
Drop stale label-noting instructions from CLAUDE.md and review-pr skill (#4654)
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.
2026-07-27 10:31:58 -04:00
Jeremiah Lowin
b2b2b0f918
Elicitation: state the era split once, not twice 2026-07-27 09:43:52 -04:00
Jeremiah Lowin
a2bec08e76
Fix double slash in issuer_url well-known log hint 2026-07-27 09:43:29 -04:00
Jeremiah Lowin
62afdca775
Bind ID-JAG audience to the issuer identifier 2026-07-27 09:37:38 -04:00
Jeremiah Lowin
c4dcf833ca
Upgrade guide: staying on 3.x is an option for sampling servers 2026-07-27 09:37:15 -04:00
Jeremiah Lowin
0172e4c4d4
Keep the sampling conformance scenario live; fix roots example URIs 2026-07-27 09:35:30 -04:00
Jeremiah Lowin
aaaca09a91
Make AuthorizationHandler keyword-only 2026-07-26 21:11:55 -04:00
Jeremiah Lowin
0e9cab86fd
Restore the version badge and point sampling users at 3.x 2026-07-26 21:10:41 -04:00
Jeremiah Lowin
4a616d6e39
Flag the sampling removal at the top of the page 2026-07-26 20:42:12 -04:00
Jeremiah Lowin
7fe3c1e8bd Editorial pass on the sampling and roots docs 2026-07-26 20:23:23 -04:00
Jeremiah Lowin
d5ff831602
Change register: record the guard route for sampling and roots 2026-07-26 19:33:40 -04:00
Jeremiah Lowin
cf7edc895c
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.
2026-07-26 19:22:37 -04:00
Jeremiah Lowin
46c3b74346
Remove stray scratch script 2026-07-26 17:48:11 -04:00
Jeremiah Lowin
98ac0402df
Keep ID-JAG audience on base_url, out of scope for issuer identity 2026-07-26 17:48:01 -04:00
Jeremiah Lowin
dec25ba6be
Merge remote-tracking branch 'origin/main' into r4648
# Conflicts:
#	tests/conformance/expected-failures.yml
2026-07-26 17:40:14 -04:00
Jeremiah Lowin
fecced2b5c
Merge pull request #4650 from PrefectHQ/claude/mcp-conformance-tests-7ec13f
Pass the MCP conformance suite's draft and pending scenarios
2026-07-26 17:38:13 -04:00
Jeremiah Lowin
5745323ecd
Cover trace propagation through the modern proxy relay 2026-07-26 17:15:30 -04:00
Jeremiah Lowin
46cd0c7933
Format the split guard-components test module 2026-07-26 17:03:04 -04:00
Jeremiah Lowin
f7eed91aa8
Forward guard asks through prompt, resource, and template proxies
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.
2026-07-26 16:58:58 -04:00
Jeremiah Lowin
8768921fd9
Split guard caching tests into their own module
Keeps test_caching.py under its size limit by topic rather than by
compressing the new tests.
2026-07-26 16:46:21 -04:00
Jeremiah Lowin
2d3ad9ca0d
Make a contended tasks/update wait instead of dropping its answer
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.
2026-07-26 16:40:33 -04:00
Jeremiah Lowin
4ef7d16419
Keep multi-round-trip asks out of the response cache
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.
2026-07-26 16:06:17 -04:00
Jeremiah Lowin
7ca58583fd
Document the guard pattern for prompts and resources 2026-07-26 15:49:45 -04:00
Jeremiah Lowin
96e12569b1
Address review: durable re-entry, resource guards, deterministic test
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.
2026-07-26 15:36:40 -04:00
Jeremiah Lowin
a7248480e2
Make InMemoryOAuthProvider keyword-only like its parent 2026-07-26 15:34:06 -04:00
Jeremiah Lowin
18aa6a09d6
Document sampling handlers on both protocol routes; qualify log-level override 2026-07-26 15:19:11 -04:00
Jeremiah Lowin
66d842d6e9
Align ID-JAG audience docstring with issuer_url 2026-07-26 15:13:58 -04:00
Jeremiah Lowin
681d5a7120
Apply ruff format to issuer identity tests 2026-07-26 15:12:50 -04:00
Jeremiah Lowin
c4c72ac240
Use issuer_url for OAuth issuer identity, not base_url 2026-07-26 15:10:15 -04:00
Jeremiah Lowin
b9fcef1889
Baseline tools-call-sampling; fix removal leftovers flagged by ruff 2026-07-26 15:07:24 -04:00
Jeremiah Lowin
7699deb99c
Pass the MCP conformance suite's draft and pending scenarios
Pin the suite, build out the fixture, and fix the protocol gaps it found.
2026-07-26 15:00:08 -04:00
Jeremiah Lowin
1593257f2a
Merge remote-tracking branch 'origin/main' into modern-merge
# Conflicts:
#	tests/client/test_roots.py
2026-07-26 14:53:31 -04:00
Jeremiah Lowin
90f2e190d0
Silence ty deprecation diagnostics and drop stale sampling doc mentions 2026-07-26 14:45:55 -04:00
Shuying
2a93404e8c
fix: accept callable roots handlers (#4639)
* Accept callable roots handlers

🤖 Generated with OpenAI Codex

* fix: cover callable object roots handlers

🤖 Generated with OpenAI Codex

---------

Co-authored-by: Shuying <zsy@u.northwestern.edu>
2026-07-26 14:43:41 -04:00
Jeremiah Lowin
1a43a3b8e9
Document that server-initiated sampling and roots are not in FastMCP 4 2026-07-26 14:43:18 -04:00
Jeremiah Lowin
fca339084b
Era-gate client.set_logging_level on modern connections 2026-07-26 14:39:31 -04:00
Jeremiah Lowin
704b74b3ab
Update tests for the removed sampling and roots server API 2026-07-26 14:38:26 -04:00
Jeremiah Lowin
e056a3946e
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.
2026-07-26 14:34:21 -04:00
Jeremiah Lowin
b07f9ce9ae
Honor OAuth application_type in DCR (SEP-837) (#4621)
* 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.
2026-07-26 14:24:50 -04:00
Aman Gupta
e4a87f2afe
fix : canonical mime type mapping from formats to remove inconsistency #4627 (#4628)
* 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>
2026-07-26 14:15:08 -04:00
Jeremiah Lowin
4ebb3fd5e6
Emit scope step-up challenges for incremental authorization (SEP-2350) (#4623)
* 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
2026-07-26 14:13:26 -04:00
dependabot[bot]
c4cb1910a3
chore(deps): bump mcp from 1.27.2 to 1.28.1 in /examples/testing_demo in the uv group across 1 directory (#4614)
Signed-off-by: dependabot[bot] <support@github.com>
2026-07-26 14:10:21 -04:00
dependabot[bot]
bc770c6fc0
Bump actions/setup-python from 6 to 7 (#4641)
Signed-off-by: dependabot[bot] <support@github.com>
2026-07-26 14:10:03 -04:00
dependabot[bot]
ac83711ff8
Bump actions/upload-artifact from 4 to 7 (#4640)
Signed-off-by: dependabot[bot] <support@github.com>
2026-07-26 14:09:51 -04:00
Jeremiah Lowin
4b09a040be
Unpublish v4 development notes; prep docs for beta 1 (#4644)
* 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
2026-07-26 14:08:34 -04:00
Jeremiah Lowin
387a063aec
Pin Claude Code to 2.1.215 in the sandboxed Marvin workflows (#4645)
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.
2026-07-26 13:57:14 -04:00
andrew-stelmach-fleet
caadfe6413
docs: fix ProxyProvider docstring example using nonexistent with_namespace() (#4633)
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.
2026-07-26 13:50:13 -04:00
Jeremiah Lowin
2f992f71ea
Support routable transport headers for gateways (SEP-2243) (#4622) 2026-07-26 13:40:09 -04:00
marvin-context-protocol[bot]
37fb0ad803
chore: Update SDK documentation (#4615) 2026-07-23 20:52:17 -04:00
Jeremiah Lowin
cb5f6abdd0
Pin burner-redis below the Windows-crashing 0.1.7 release (#4618)
* Pin burner-redis below the Windows-crashing 0.1.7 release

burner-redis 0.1.7 crashes the interpreter (native fault, no Python traceback)
running the memory:// task backend under pytest-xdist on Windows — reproduced on
GitHub Actions windows-latest via the 'Upgrade checks' workflow, confirmed
absent on macOS/Linux with the identical dependency versions.

pydocket only floors burner-redis at >=0.1.6, so capping pydocket's own version
is not enough: a resolver remains free to pick the newest burner-redis
satisfying that floor. fastmcp-tasks previously pinned pydocket>=0.20.0 with no
upper bound, so a fresh 'pip install fastmcp[tasks]' today can resolve straight
into the broken combination for a real Windows user on the default backend.

Pin burner-redis<0.1.7 directly, which in turn caps pydocket to <0.20.2 (the
last release that doesn't itself require burner-redis>=0.1.7). Verified the pin
holds under both locked and --upgrade (highest) resolution.

* Scope the burner-redis pin to Windows only

burner-redis 0.1.7 is confirmed fine on macOS/Linux (full suite green there with
the identical upgraded dependencies) - only Windows crashes. The previous
unconditional pin blocked every platform from newer pydocket/burner-redis
releases unnecessarily. Add sys_platform == 'win32' to the burner-redis
constraint so only Windows installs are capped.

Verified via uv pip compile --python-platform: macOS/Linux resolve to
burner-redis 0.1.7 / pydocket 0.23.0 (unblocked); Windows resolves to
burner-redis 0.1.6 / pydocket 0.20.1 (still capped).
2026-07-23 20:51:43 -04:00
Jeremiah Lowin
cf021d1a70
whats-new: add the argument completion capability (#4620)
Server-side completions (@mcp.completion) shipped in #4582 but the
What's New page didn't mention it. Adds it to the authoring-capabilities
cluster with a runnable example and a link to the servers/completions page.
2026-07-23 20:44:16 -04:00
Jeremiah Lowin
f896f5acb5
v4 docs quality pass: stale task/era claims, broken links, polish (#4619)
* v4 docs quality pass: fix stale task/era claims, broken links, writing polish

* whats-new: add the client-side protocol negotiation story

The page told the server half of the era story (serves every era) but
never the client half — that a default Client(url) now negotiates the
modern era, where earlier versions pinned the handshake. Completes the
mental model and links to the client negotiation docs.

* Address review: drop 'complete' over-claim; link mounted-state to Session State
2026-07-23 20:42:13 -04:00
Jeremiah Lowin
078c44d835
Fix stale Mac/Windows-vs-Linux OAuth key/storage docs (#4617)
* Fix stale Mac/Windows-vs-Linux OAuth key/storage docs

#2223 replaced platform-aware keyring/MemoryStore defaults with
deterministic key derivation and an always-on-disk encrypted store,
but the docs update in that PR missed several spots.

* Fix OIDCProxy doc referring to internal upstream_client_secret name

Codex review: the public OIDCProxy constructor takes client_secret;
upstream_client_secret is only OAuthProxy's internal parameter name.
2026-07-23 20:30:05 -04:00
Jeremiah Lowin
39148870af
Merge pull request #4603 from PrefectHQ/feat/tasks-sep2663
Add background tasks via the io.modelcontextprotocol/tasks extension (SEP-2663)
2026-07-23 20:16:11 -04:00
Jeremiah Lowin
601903436b
Pass task-creation results through ToolResult-only middleware
A task-augmented tools/call returns a CreateTaskResult up through the middleware
chain. Response caching and response limiting assumed a ToolResult and accessed
.content/.wrap(), crashing after the task was already enqueued (a client retry
could duplicate side effects). Both now pass any non-ToolResult through
untouched, alongside the existing InputRequiredToolResult bypass.
2026-07-23 20:09:47 -04:00
Jeremiah Lowin
79ba8f180d
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f
# Conflicts:
#	uv.lock
2026-07-23 20:07:13 -04:00
Jeremiah Lowin
76c6f1a64e
Session-in-task Context API, task telemetry, settings dotenv, guard fail-loud
Five review fixes. ctx.session_id / get_state / set_state now work in a Docket
worker by falling back to the snapshotted session id. Task management wire calls
(submission, tasks/get/update/cancel) create client spans and propagate trace
context. TasksClientSettings loads .env like DocketSettings, and the docs use
its real env var name. A state-only guard round (request_state, no input
requests) fails with a clear error instead of silently completing wrong.
2026-07-23 20:05:54 -04:00
nate nowack
856844cae7
Document targeted v4 prerelease installation (#4598)
🤖 Generated with Codex

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-23 20:00:28 -04:00
nate nowack
cc3d1c18a3
Allow FastMCP prereleases through the repository cooldown (#4596)
* Allow FastMCP prerelease resolution

🤖 Generated with Codex

* Include fastmcp-remote in prerelease resolution

🤖 Generated with Codex

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-23 20:00:23 -04:00
nate nowack
d8ac6cbfde
Fix OAuth proxy override typing (#4612) 2026-07-23 19:52:42 -04:00
Jeremiah Lowin
c556f07a66
Archive v3 docs and publish v4 as the primary version (#4613)
* Archive v3 docs under /v3 and publish v4 as the primary version

* Label primary docs version v4.0.0 (alpha 1)

* Add What's New in v4 page; fix upgrade-guide phrasing; point banner at What's New

* Rewrite What's New around v4's new capabilities, not the sampling deprecation

* Lead What's New with the SDK v2 engine swap and the SEPs it brings

* State ships now (link Session State); tasks arrive next alpha

* Exclude docs/v3 frozen snapshots from doc-example import validation
2026-07-23 19:47:57 -04:00
Jeremiah Lowin
1c57079b9b
Verify UserSession state works inside background tasks
Lock in the tasks x stateless-session-state (#4604) integration: a
session: UserSession parameter resolves in a Docket worker via the task-aware
get_server() and the principal restored from the task snapshot, sharing state
across a principal's tasked calls and staying isolated between principals.
2026-07-23 19:38:19 -04:00
Jeremiah Lowin
3f746b91fc
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f
# Conflicts:
#	fastmcp_slim/fastmcp/server/dependencies.py
2026-07-23 19:32:52 -04:00
Jeremiah Lowin
cb4419ed02
Fix broken Docket links in task docs
The example README pointed at github.com/PrefectHQ/docket (404); the canonical
repo is chrisguidry/docket. Point the docs' Docket-docs link at the canonical
docket.lol.
2026-07-23 19:24:45 -04:00
Jeremiah Lowin
8363ec4d26
Add stateless session state (UserSession / SessionId) (#4604)
* Design doc: stateless session state

* Add stateless session-state primitives: Scope, SessionCodec, scoped state

* Add SessionProvider and Session() annotation for stateless session state

* Rewrite session-state design to final shape (Session object, two patterns, no seal)

* Rework stateless session state to final Session/SessionId design

Remove Scope, SessionCodec/sealing, and scoped ctx.get_state. Add the
Session object (get/set/delete/clear over one dict per (principal,
session_id) key), injected session: Session (keyed by principal, requires
auth), session_id: SessionId argument with auto-filled description, and
SessionProvider contributing create_session/end_session.

* Rename injected marker to UserSession; auto-wire SessionProvider on SessionId

* Document stateless session state as a v4 feature

* Require SessionProvider and make sessions create-then-validate

Remove the implicit SessionProvider auto-wiring; a SessionProvider must now be
registered explicitly. create_session records an owned session and get_session
validates the id, rejecting uncreated or foreign ids.

* Add Session.id (public id for session_id sessions, None for UserSession)

* Fix ty: narrow Tool | None and ToolResult.structured_content in session tests

* Fix session-provider enforcement gap for non-local tools; stop embedding raw principal in UserSession key

* Fix disabled session_id tools blocking listing; reject local tools shadowing SessionProvider lifecycle names

* Decouple SessionId description from lifecycle tool name so it survives namespaced mounts

* Remove SessionProvider enforcement; get_session validation is the guarantee

* Fix stale enforcement/key-format docs; document store-owned session TTL

* Dedup SessionId contract description; tighten context.mdx session-state lead

* Make session store/description resolution work in Docket task workers and for partial tools

* Expose get_session as a standalone task-safe function; drop foreground-only Context.get_session

* Move get_session to dependencies alongside the other request accessors

* Reframe context state docs as Request State; cross-request persistence points to Session State

* Address UserSession injection edge cases from review

- inject a UserSession instance (not bare Session) so isinstance holds
- support session: UserSession | None = None (inject None when unauth)
- detect SessionId params past a partial's positional binding
2026-07-23 19:21:00 -04:00
Jeremiah Lowin
53741dc9c7
Keep task routing keys alive via sliding TTL; version-aware worker server resolution
A resumed leg that runs longer than its pointer's wall-clock TTL stranded
_lookup_task on the base leg (false completion / not found). Each poll now
refreshes the routing keys' TTL (sliding expiration), so an actively-polled
task keeps them alive regardless of execution duration, and the resumed-leg
write uses the same buffered TTL as creation. Separately, remote-worker server
resolution now respects the requested tool version, so two versions of the same
mounted tool name resolve to their own child server.
2026-07-23 19:18:51 -04:00
Jeremiah Lowin
95f766cb74
Normalize asyncio.TimeoutError to builtin in task input timeout (py3.10)
asyncio.wait_for raises asyncio.TimeoutError, a distinct type from the builtin
before Python 3.11, so an elicitation-callback timeout leaked an uncaught type
on 3.10. Convert it to the builtin TimeoutError the rest of the drive raises.
2026-07-23 18:35:57 -04:00
Jeremiah Lowin
f81d6c07d8
Load task settings from .env; gate root publish on fastmcp-tasks; fix worker command
DocketSettings now loads the same dotenv source as core settings, so a
FASTMCP_DOCKET_* value in .env configures the backend instead of silently
using memory://. The root fastmcp publish waits for the matching fastmcp-tasks
to appear on PyPI before uploading, so the [tasks] extra is never installable
but unresolvable. And the example README uses the real worker entry point
(python -m fastmcp_tasks.worker_cli worker).
2026-07-23 18:30:52 -04:00
Jeremiah Lowin
c3ad5e9ecb
Clear stale auth in reused workers; bound elicitation; version explicit tasks
Three review fixes. A Docket worker may reuse an asyncio context across tasks,
so snapshot restore now always resets auth and headers to the current task's
state — an anonymous task following an authenticated one no longer inherits the
prior caller's identity. A stalled in-task elicitation handler is now bounded by
the call's remaining timeout, like polling and sleeps. And call_tool_task takes
a version= to task a specific component version rather than the highest.
2026-07-23 18:25:48 -04:00
Jeremiah Lowin
a194acdc5f
Resolve mounted server and headers correctly in remote task workers
Two remote-worker fixes. A separate worker process cannot reach the submitting
process's server map, so a mounted task's ctx.fastmcp/CurrentFastMCP() fell back
to the root; the worker now re-resolves the owning child from the root using the
snapshotted tool name. And restoring headers no longer fabricates a live Request
— get_http_headers() reads a dedicated task-headers context var while
get_http_request()/CurrentRequest() correctly keep raising inside a task.
2026-07-23 18:19:35 -04:00
Jeremiah Lowin
fbee629ed9
Advertise only supported token endpoint auth methods in OAuthProxy metadata (#4608)
* Advertise only supported token endpoint auth methods in OAuthProxy metadata

* Normalize DCR registration response to the stored public client
2026-07-23 18:11:18 -04:00
Jeremiah Lowin
9019a7af70
Add PyPI publish workflow for fastmcp-tasks
The fastmcp[tasks] extra pins fastmcp-tasks=={version}, but no workflow
published it — pip install "fastmcp[tasks]" would fail to resolve. Mirror the
fastmcp-remote workflow: build on release, wait for the matching fastmcp-slim to
appear on PyPI, then publish.
2026-07-23 16:54:31 -04:00
Jeremiah Lowin
f627170088
Bound task drive by one deadline; version-aware tasking; serialize cancel
Three review fixes: transparent call_tool(timeout=N) now enforces one deadline
across the whole poll loop (not per-request), matching the sync timeout; the
tools/call interceptor resolves the client-requested component version instead
of the highest; tasks/cancel runs under the per-task update lock and re-resolves
the live leg, so it can't cancel a stale leg while an update enqueues the next.
2026-07-23 16:53:08 -04:00
Jeremiah Lowin
733801ed6c
Rework tasks example into a runnable HTTP client/server pair
Server runs over HTTP on the default memory:// backend (no Redis needed); the
client drives it transparently, via an explicit handle, and with a parallel
command that fires several tasks at once to show them overlap. A 1s poll
interval keeps the demo snappy.
2026-07-23 16:44:53 -04:00
Liang Hu
99327084d2
Preserve raw CallToolResult returns (#4587)
Co-authored-by: nate nowack <thrast36@gmail.com>
2026-07-23 15:10:42 -05:00
nate nowack
06aa84943c
Expose era-neutral client server metadata (#4599)
* Expose era-neutral client metadata

🤖 Generated with Codex

* Clarify pinned modern client metadata
2026-07-23 15:06:26 -05:00
Jeremiah Lowin
1d442ffa36
Make tasks/cancel actually cancel input_required tasks
A guard task parked on input has an already-COMPLETED Docket execution, so
docket.cancel on it was a no-op: tasks/get reported input_required forever and
tasks/update could still resume it. Record a durable logical-cancellation
marker that tasks/get reports as cancelled and tasks/update refuses to resume,
and clear the parked leg's outstanding requests on cancel.
2026-07-23 08:15:21 -04:00
Jeremiah Lowin
110943fc61
Skip expired snapshot tokens; bound task wait polls by deadline
A queued task can outlive its submitter's token expiry: install the snapshot
token only if still valid, matching the SDK bearer check, so a delayed task
never runs under credentials a live request would reject. ToolTask.wait now
bounds each tasks/get by the remaining deadline so a stalled poll cannot block
past the caller's timeout.
2026-07-23 08:12:42 -04:00
Jeremiah Lowin
1c7ade215b
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f 2026-07-23 08:00:29 -04:00
Jeremiah Lowin
edb54bddf3
Merge pull request #4602 from PrefectHQ/feat/server-extension-api
Add FastMCP-native server extension API (SEP-2133)
2026-07-23 07:59:59 -04:00
Jeremiah Lowin
b75dde3b5c
Mask raised task errors regardless of ctx param
Resolve the error-masking policy via the worker-server resolver instead of
the active Context: a task tool that raises without requesting a ctx param
has no active context, so the old lookup leaked unmasked error text past
mask_error_details=True. Also route custom Tool subclasses through the same
error-conversion wrapper as FunctionTool.
2026-07-23 07:59:54 -04:00
Jeremiah Lowin
19c5c507cc
Address review feedback on SEP-2663 tasks
- Client task support is opt-in via importing fastmcp_tasks (drop the core
  auto-load of companion packages); a plain Client never advertises tasks.
- A worker restores the submitting caller's auth token and headers from the
  task snapshot into the standard ambient context, so get_access_token() /
  get_http_headers() work in a distributed worker with no new core hooks.
- worker_cli validates the loaded extension's resolved backend, not env defaults,
  so a constructor-configured Redis worker starts.
- Thread the per-call read timeout through task polling; bound ToolTask.wait by
  its deadline; set_elicitation_callback rebuilds internal extensions so a
  later-set handler answers in-task input.
- README imports TaskConfig from fastmcp.utilities.tasks.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 19:14:16 -04:00
Jeremiah Lowin
e5ca0269cb
docs: rewrite background tasks pages for SEP-2663
Server (servers/tasks.mdx) and client (clients/tasks.mdx) docs rewritten for
the extension model: add_extension(TasksExtension()), the guard pattern for
in-task input (no imperative ctx.elicit()), tools-only, and the modern-protocol
requirement (the inverse of the old SEP-1686 legacy-only note). Mechanical
fixes elsewhere for the same reason: telemetry.mdx's tasks/{operation} method
list (get/update/cancel, not result/list), client.mdx's legacy-only feature
list (tasks moved to modern-only) and extension-composition paragraph
(describes the tasks ClientExtension, not the removed notification binding),
and stale SEP-1686 references in the FastMCP 2 upgrade guide. v4-notes status
lines updated to Shipped (#4602, #4603).
2026-07-22 17:24:56 -04:00
Jeremiah Lowin
bb3ef39a89
Close SEP-2663 compliance gaps: -32003 on task methods, raised-error semantics, update race
- tasks/get|update|cancel now return -32003 when the client did not declare the
  tasks extension for the request (SEP-2663 MUST).
- A task tool that raises is a completed task with an is_error result, not a
  failed task; failed is reserved for protocol faults, matching a live tools/call.
- A per-task lock serializes concurrent tasks/update so two racing answers cannot
  each enqueue a next leg (double execution).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 16:59:13 -04:00
Jeremiah Lowin
74e01d5e08
Add SEP-2663 client half: transparent call_tool, ResultClaim, Task handle
A FastMCP client now transparently completes tasked tools/call: the tasks
ClientExtension advertises the capability and claims the CreateTaskResult, and
the resolver drives the tasks/get poll loop to completion, answering in-task
input through the client's elicitation handler and returning the tool's real
result. call_tool is transparent, call_tool_mcp exposes the raw result, and
call_tool_task yields a Task handle. The client half moves to fastmcp-tasks;
the [tasks] client extension auto-wires into Client (ProxyClient opts out).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 15:21:10 -04:00
nate nowack
8efa405833
Bridge camelCase ToolAnnotations reads (#4597)
🤖 Generated with Codex
2026-07-22 13:55:41 -05:00
Jeremiah Lowin
d41ff5bcd8
Rebuild guard tasks as end-and-reenter; remove imperative in-task elicit
A task tool that returns InputRequiredResult now ends its leg (freeing the
worker) and stores the ask as durable state; tasks/update enqueues a fresh
Docket execution (the next leg) with accumulated request_state/input_responses
injected via ctx. No worker ever blocks on input, so a parked task no longer
holds up shutdown. Imperative ctx.elicit() inside a task is removed and raises
with guard-pattern guidance.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 12:38:46 -04:00
Jeremiah Lowin
ef29b731ea
Add server-side claim production for tasks; emit resultType discriminator
Widen the tools/call result serialization (via a refcounted, modern-gated wrap
installed by TasksExtension) so a CreateTaskResult reaches the client instead of
being stripped by the CallToolResult|InputRequiredResult surface — the SDK ships
claim consumption but no production. Emit the resultType discriminator the
protocol requires (task on CreateTaskResult, complete on the tasks/* results);
the draft schema forbids it (additionalProperties:false), a contradiction
reported upstream. Closes compliance gaps G1/G4/G5.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 08:03:32 -04:00
Jeremiah Lowin
b0d3e653b9
Fix flaky stdio crash-recovery tests: assert eventual recovery (#4594) 2026-07-22 08:01:37 -04:00
Jeremiah Lowin
bc22e517fd
Fix ty diagnostics in task tests, scope ty exclusion to client-task files 2026-07-21 23:10:00 -04:00
Jeremiah Lowin
5fa2883670
Implement SEP-2663 tasks extension: TasksExtension, poll-based task lifecycle
TasksExtension serves io.modelcontextprotocol/tasks on the extension API:
a decide-and-task tools/call interceptor (era-gated to modern connections),
tasks/get with inlined results and inputRequests, tasks/update delivering
poll-based in-task elicitation, tasks/cancel, durable creation, and
auth-scoped task isolation. Wire models validate against the vendored
ext-tasks schema. Worker-side Context hooks are refcounted so sibling
servers cannot strand each other's workers.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 23:00:38 -04:00
Jeremiah Lowin
6fce4e538f
Move task subsystem to fastmcp-tasks package, disconnect SEP-1686 wire from core
Engine modules (keys, context snapshot, docket lifespan, worker CLI,
client handles) move intact; SEP-1686 wire modules park in _legacy_wire
for adaptation to SEP-2663. Core keeps task=True declaration on tools
only and raises at serve time until the tasks extension is registered.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 21:51:45 -04:00
Jeremiah Lowin
d756b99bf6
Sort imports in extensions.py 2026-07-21 20:44:54 -04:00
Jeremiah Lowin
242850c0f3
Scaffold fastmcp-tasks workspace package
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 20:44:54 -04:00
Jeremiah Lowin
094738f68a
Add server extension API: add_extension with capability, methods, tool-call interception, and lifespan
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 20:36:38 -04:00
Jeremiah Lowin
4402b48954
test: vendor ext-tasks draft schema as fixture 2026-07-21 20:19:28 -04:00
Jeremiah Lowin
44d6d739ea
docs: v4 background-tasks design — rebuild on SEP-2663 as fastmcp-tasks 2026-07-21 20:18:58 -04:00
Jeremiah Lowin
36caaa6f56
Document v3->v4 removals and add upgrade-reality tests (#4585)
* Document v3->v4 removals and add upgrade-reality tests

* Check canonical imports in a clean subprocess to avoid suite import pollution

* Address review: import_server semantics note, pin traversal error, drop redundant import

* Address review round 2: real screening test, Depends factory, remove_tool/create_proxy notes

* Validate canonical imports in-process; fix lifespan/timeout/error-code/starlette doc notes

* Reconcile with fastmcp.types trim: import protocol types from mcp_types

* Record v4 release codename arc in dev notes
2026-07-21 17:12:59 -04:00
Jeremiah Lowin
30044c7864
Fix percent-encoded skill file names unreadable in resources mode (#4590)
* Fix percent-encoded skill file names unreadable in resources mode

Encode supporting-file paths explicitly (quote/unquote) when building
and resolving skill:// resource URIs, instead of relying on AnyUrl's
implicit encoding. This also closes the ambiguity where a file literally
named "setup%20guide.md" would collide with "setup guide.md" once both
were percent-encoded.

Fixes #4545

* Quote main_file_name when building its resource URI

Keeps the main-file URI on the same explicit quote/unquote round-trip
as supporting files, so a custom main_file_name containing a literal
'%' still resolves after the shared unquote() in _get_resource().
2026-07-21 15:34:09 -04:00
marvin-context-protocol[bot]
d0f1468fce
chore: Update SDK documentation (#4589)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-21 13:10:24 -05:00
VectorPeak
74b8f1bc1c
Fix File helper extension handling (#4531)
Preserve explicit suffixes when building data-backed File resource URIs, while keeping the inferred-extension fallback for names without a suffix.

Closes #4530

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
2026-07-21 13:04:15 -05:00
苏紫辰
16a09f0151
Fix skill frontmatter with UTF-8 BOM (#4533)
🤖 Generated with Codex
2026-07-21 12:48:40 -05:00
Jeremiah Lowin
f038cf3be7
Add machine-to-machine client authentication (#4583)
* Add M2M client credentials auth providers

Wrap the SDK's client_credentials and private_key_jwt OAuth providers as
FastMCP-idiomatic ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider,
enabling browser-free client authentication via Client(auth=...).

* Fix M2M token cache collision and explicit-scope drop

Namespace the token cache by client_id so distinct clients sharing one store don't overwrite each other's tokens; pin caller-supplied scopes so the token request keeps them; fix CodeQL URL-substring check in tests; drop unused logger.

* Preserve step-up scope union, scope-aware token cache, restore token expiry

Only pin the caller's explicit scopes on initial authorization, leaving the SDK's step-up scope union intact; namespace the token cache by requested scopes as well as client_id; restore persisted absolute expiry on init so an expired stored token is re-fetched.

* Skip expiry restore for non-expiring reloaded tokens

* Distinguish expires_in=0 from omitted when restoring expiry

* Scope step-up flag to the flow via ContextVar; runnable JWT signing example
2026-07-21 12:27:08 -04:00
Jeremiah Lowin
7417e974f4
Let a server answer argument-completion requests (#4582)
* Add server-side argument completion (@mcp.completion)

* Reference CompletionValues directly in cast so the import reads as used

* Import completion types from mcp_types, not the fastmcp.types mirror

* Fix test imports after dropping the fastmcp.types mirror

* Fix change-register example import after dropping the types mirror

* Enforce 100-value completion cap; make docs example runnable

* Document completion authorization contract

* Offload sync completion handlers to threadpool

* Exclude bare str from completion return type

* Pass Any-typed value in bare-string rejection test

* Point completion authoring types to mcp_types in v4 notes
2026-07-21 12:26:24 -04:00
Jeremiah Lowin
611a35861d
Trim fastmcp.types to FastMCP-unique types (#4584)
* Trim fastmcp.types to FastMCP-unique types only

fastmcp.types re-exported 29 mcp_types symbols verbatim, which was
pointless indirection users had to discover. It now holds only Textarea,
the one type FastMCP actually defines; everything else imports from
mcp_types directly. These mirrors were added during unreleased SDK v2
migration work and never shipped, so this is not a breaking change.

* Keep historical mcp.types import in v2/v3 migration examples
2026-07-21 09:45:41 -04:00
Jeremiah Lowin
10af989563
Keep historical mcp.types import in v2/v3 migration examples 2026-07-20 21:04:01 -04:00
Jeremiah Lowin
7814d95990
Merge pull request #4581 from PrefectHQ/docs/v4-notes-refresh
Bring the v4 developer notes up to date with what shipped
2026-07-20 20:58:26 -04:00
Jeremiah Lowin
e32a2098f9
Trim fastmcp.types to FastMCP-unique types only
fastmcp.types re-exported 29 mcp_types symbols verbatim, which was
pointless indirection users had to discover. It now holds only Textarea,
the one type FastMCP actually defines; everything else imports from
mcp_types directly. These mirrors were added during unreleased SDK v2
migration work and never shipped, so this is not a breaking change.
2026-07-20 20:53:11 -04:00
Jeremiah Lowin
07fa270652
Address review: drop tasks from modern capability table; note the reentrancy blocker too 2026-07-20 20:28:23 -04:00
Jeremiah Lowin
2db431f5e5
Refresh v4 notes index overview to match shipped work 2026-07-20 20:02:49 -04:00
Jeremiah Lowin
18b898e42a
Refresh v4 developer notes to match shipped work 2026-07-20 20:00:37 -04:00
nate nowack
9d9bf2b717
Restore upgraded dependency checks (#4576)
* Restore upgraded dependency checks

Generated with Codex

* Clarify settings loading and teardown logging

Generated with Codex

* Align ty checks on the upgraded version

Generated with Codex

* Preserve simultaneous caller cancellation

Generated with Codex
2026-07-20 18:46:30 -04:00
marvin-context-protocol[bot]
4ec2757b6d
chore: Update SDK documentation (#4569)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-20 18:44:54 -04:00
Jeremiah Lowin
d927762003
Drop forked client protocol helpers in favor of the SDK's (#4574)
* Delegate forked client protocol helpers to the SDK

Replace FastMCP's copies of _fold_extensions, _evicting_message_handler,
and _synthesize_discover with imports from mcp.client.client. The fork had
drifted: it was missing validate_extension_identifier, so non-reverse-DNS
extension identifiers were silently accepted.

Full lifecycle composition over mcp.Client stays blocked upstream —
mcp.Client hardcodes ClientSession construction (no session_class hook)
and forbids reentry.

* Drop duplicate local helpers reintroduced by the merge; use SDK versions
2026-07-20 18:21:56 -04:00
Jeremiah Lowin
2bcfae3412
Merge pull request #4572 from PrefectHQ/feature/client-auto-default
Negotiate the best mutual protocol era by default
2026-07-20 18:16:40 -04:00
Jeremiah Lowin
afbe342587
Document on_initialize and session-state loss under the auto default 2026-07-20 18:04:29 -04:00
Jeremiah Lowin
e01c5932bf
Unpin tests whose defects #4579 fixed
Resource/prompt error detail and proxy instructions/connection-error
surfacing now work on the modern protocol era, so the tests pinned to
mode="legacy" with a TODO(defect)/TODO(mode="legacy" pin) marker run
on the default auto mode again.
2026-07-20 18:02:21 -04:00
Jeremiah Lowin
5f428aaced
Merge remote-tracking branch 'origin/main' into feature/client-auto-default 2026-07-20 17:53:27 -04:00
Jeremiah Lowin
57bbc9859e
Surface resource, prompt, and proxy errors on the modern protocol era (#4579)
Three defects hidden by tests pinned to the handshake era, where a raw
exception reaches the wire as str(exc). At 2026-07-28 the runner masks
anything that is not an MCPError/ValidationError as "Internal server error".

- _on_read_resource / _on_get_prompt now translate FastMCPError through
  to_mcp_error, mirroring _on_call_tool. Masking is unchanged.
- FastMCPProxy registers a server/discover handler so upstream instructions
  reach modern clients; on_initialize only fires for the handshake.
- ProxyProvider's list methods normalize transport failures into MCPError.
2026-07-20 17:52:12 -04:00
Jeremiah Lowin
52b37b9a0c
Mark transforming single-server config wrapper legacy-only 2026-07-20 16:34:42 -04:00
Jeremiah Lowin
d048c7e690
Merge branch 'audit/pins-server' into feature/client-auto-default 2026-07-20 16:27:59 -04:00
Jeremiah Lowin
de14ed1b7c
Audit mode="legacy" pins in server tests and top-level stragglers
Removes pins added while making the auto-default suite pass that weren't
actually testing older-protocol-only behavior, and keeps (with a stated
reason) the ones that are. Along the way, fixes two real defects the audit
surfaced in the modern protocol path: PingMiddleware could leak a
_active_sessions entry when a connection's exit_stack closed before its
keepalive task got its first scheduler turn, and FastMCP(experimental_
capabilities=...) was silently dropped from server/discover responses
(it only ever reached the legacy initialize handshake).
2026-07-20 16:00:27 -04:00
Jeremiah Lowin
f2ccb6a32c
Merge branch 'audit/pins-proxy' into feature/client-auto-default 2026-07-20 16:00:18 -04:00
Jeremiah Lowin
bcf90d5ae7
Remove unnecessary mode="legacy" pins from proxy tests
Most pins in tests/server/providers/proxy/ were added only to keep tests
green while unpinning changed which protocol era the proxy's backend
connection used, not because the test's subject cared about the era. With
proxy era-mirroring (#4573) landed, a front client on auto correctly moves
the whole chain to the modern protocol, so plain tool/resource/prompt calls
through a proxy no longer need a pin.

Kept pins fall into three buckets, each commented at the call site: tests
whose subject is genuinely handshake-only (sampling, roots, elicitation
push-forwarding, ping, initialize handshake mechanics); tests whose backend
is a directly-constructed ProxyClient/StatefulProxyClient, which always
defaults to legacy independent of the front era; and two tests left pinned
with a TODO documenting a real defect this audit surfaced (upstream
instructions not forwarded to a modern-era client through a proxy, and
ProxyProvider.list_tools leaking an unwrapped connection error instead of
an MCPError).
2026-07-20 15:50:35 -04:00
Jeremiah Lowin
ae43039d8e
Audit tests/client/ mode="legacy" pins
Remove 4 unjustified pins (proxy header passthrough, connect timeout,
two response_title validation tests that fail before any request is
dispatched). Keep 81 pins that genuinely exercise older-protocol-only
behavior (ctx.elicit back-channel, sampling, roots, ping, session IDs,
initialize handshake, client.set_logging_level).

Flags a real defect: _on_read_resource/_on_get_prompt only catch
(DisabledError, NotFoundError), unlike _on_call_tool which catches
FastMCPError broadly. A ResourceError/PromptError escapes as a raw
exception and the modern protocol's generic exception ladder masks it
as "Internal server error", losing the detailed message tool errors
still get. Left pinned with a TODO in test_client.py and
test_error_handling.py rather than hidden.
2026-07-20 15:43:04 -04:00
Jeremiah Lowin
bf352d8a4a
Make protocol-version notes scannable and drop era jargon from client docs 2026-07-20 15:00:58 -04:00
Jeremiah Lowin
1e1882851d
Keep the CLI URL proxy era-agnostic; monitor claimed-result resolution 2026-07-20 12:46:34 -04:00
Jeremiah Lowin
35c2b52652
Merge remote-tracking branch 'origin/main' into feature/client-auto-default
# Conflicts:
#	fastmcp_slim/fastmcp/server/providers/proxy.py
2026-07-20 12:33:38 -04:00
Jeremiah Lowin
0ba3db1a56
Mirror the frontend's protocol era on a proxy's backend connection (#4573)
* Mirror front protocol era onto proxy backend connection

A proxy created from a non-Client target now negotiates, on its backend,
whatever era its front client negotiated, instead of pinning one era.
Explicit create_proxy(mode=...) still overrides. Guards the eager backend
initialize() so an explicit modern pin behind a handshake front no longer
crashes.

* Carry the mirrored proxy era into multi-server config backends

A multi-server MCPConfig target mounts one proxy per configured server on a
composite router, so setting the era on the outer client stopped at the router
and every real backend stayed on its default era. TransportOptions.backend_mode
carries it down, resolved per request alongside the outer mirroring.

The router is also sealed under a policy held on the transport rather than a
fresh per-router ephemeral key, so a guard tool's request_state survives the
router being rebuilt between rounds.
2026-07-20 12:31:02 -04:00
Jeremiah Lowin
1a788cf349
Merge remote-tracking branch 'origin/main' into feature/client-auto-default
# Conflicts:
#	tests/client/test_streamable_http.py
#	tests/server/middleware/test_initialization_middleware.py
#	tests/server/tasks/test_task_status_notifications.py
2026-07-20 12:02:38 -04:00
Jeremiah Lowin
effbc568ff
Document Windows CI parallelism and the subprocess_heavy marker (#4575)
* Document Windows CI parallelism and the subprocess_heavy marker

* Exclude subprocess_heavy from the process-free test command
2026-07-20 11:52:42 -04:00
Rach Granville
dd803a0d7f
docs: quote pip extras install examples (#4568)
* docs: quote pip extras install examples

* docs: quote remaining unquoted pip install extras

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-20 11:09:50 -04:00
Jeremiah Lowin
c8b8911226
Stop gather() from creating coroutines it may never schedule (#4559)
* Fix: gather() eagerly creates coroutines before scheduling them

AggregateProvider fans out Provider.get_tool() (and sibling calls) across
child providers via gather(*[p.get_tool(x) for p in providers]). The list
comprehension builds every coroutine up front, then gather()'s scheduling
loop hands them to an anyio task group one at a time. If that loop is
interrupted partway through - e.g. by pytest-timeout's SIGALRM-based
per-test timeout, which can fire between any two bytecode instructions,
unlike normal async cancellation - any coroutine not yet scheduled is
abandoned and silently garbage collected later, producing a "coroutine
'Provider.get_tool' was never awaited" warning attributed to whatever
unrelated test happens to be running when the GC gets to it.

Change gather() to take a single iterable consumed lazily, one awaitable
at a time, right before each is scheduled, and close any awaitable that
was just retrieved if scheduling it raises. Update call sites to pass
generator expressions instead of eagerly-built lists so coroutine
creation and scheduling stay tightly coupled.

* Close unscheduled awaitables from eager callers; make get_tasks lazy
2026-07-20 11:01:30 -04:00
Jeremiah Lowin
c33a3c3b29
Only fail triage when a granted tool is denied, and grant get_pull_request (#4562)
The guard failed on any denial, so an agent falling back to an unlisted tool
during a GitHub outage tripped it — and the error blamed the allowlist, which
was intact. It now fails only when a command the workflow actually grants is
refused, which is the signal that a pattern was mangled.

mcp__github__get_pull_request was never granted, so on a PR the agent could
only read via get_issue and reached for denied fallbacks when that failed.
2026-07-20 10:51:42 -04:00
Jeremiah Lowin
b0e782a2ee
Make the unit suite fast: in-process HTTP tests, no real sleeps, parallel Windows CI (#4554) 2026-07-20 10:51:14 -04:00
Marcelo Trylesinski
7934124fb5
Make transformed tool required order deterministic (#4564)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-20 07:12:45 -05:00
Jeremiah Lowin
d2ac7ed3d2
Default fastmcp.Client to mode="auto"; surface extensions=/result_claims=
Client negotiates the newest mutual protocol era by default (probe
server/discover, fall back to the initialize handshake). ProxyClient and the
inspect utility explicitly pin the handshake era so proxy forwarding and
server_info reads are unchanged. SSE and multi-server config transports are
legacy-only. extensions= and result_claims= (SEP-2133) are thin passthroughs
to the SDK session.
2026-07-19 21:22:49 -04:00
Jeremiah Lowin
33ed688a8f
Bump pinned Claude models to current versions (#4561) 2026-07-19 21:09:43 -04:00
Jeremiah Lowin
2676864163
Fix AI workflow allowlists being destroyed by tokenization (#4560) 2026-07-19 20:46:29 -04:00
Jeremiah Lowin
c6e31a3be6
Rename martian workflows to marvin (#4558) 2026-07-19 20:46:02 -04:00
Jeremiah Lowin
a3163bc275
Add 'prs welcome' label to waive the PR assignment gate (#4557)
* Add 'prs welcome' label to waive the PR assignment gate

Also documents contributor accountability, maintainer edit access, and
branch targeting in CONTRIBUTING.

* Protect 'prs welcome' from prompt-injected triage labeling
2026-07-19 20:37:40 -04:00
Jeremiah Lowin
3213776b25
Run FastMCP middleware for every inbound message (#4553)
* Make the SDK seam the root of FastMCP middleware dispatch (D3)

Notifications, cancellations, and malformed/unroutable messages now reach
on_message/on_request/on_notification at the SDK seam. Component methods keep
their interior dispatch (typed hooks, tool-exception visibility) unchanged; the
seam covers only messages the interior never dispatches, so each hook fires once.

* Document the middleware seam coverage and suspend semantics (D3)

* Align seam docs and ask-visibility test with the result-cycle MRTR model

An InputRequiredResult is the full result of a complete request->response
cycle, not a suspension: component hooks observe an asking round's
InputRequiredToolResult as an ordinary return value.

* Replace 'seam' language with plain dispatch terminology

* Keep the raw middleware __call__ signature; forward middleware message edits

* Cover fires-once across an MRTR continuation round

* Align cherry-picked coverage test with renamed recorder

* Rewrite only the message, never the dispatch destination
2026-07-19 20:29:08 -04:00
Jeremiah Lowin
cef327d0f2
Fix label triage applying no labels, and make blocked tool calls fail (#4555) 2026-07-19 19:24:20 -04:00
Jeremiah Lowin
1e529ee27d
Stop proxies from validating backend results or mutating shared transports (#4552) 2026-07-19 19:24:11 -04:00
Jeremiah Lowin
b9b1deacb6
Speed up the unit test suite, and fix the task-notification race it surfaced (#4550) 2026-07-19 18:52:04 -04:00
Jeremiah Lowin
eee5e91334
Fix stale MRTR/elicitation framing in client and upgrade docs (#4551) 2026-07-19 18:10:15 -04:00
Jeremiah Lowin
717f3535f6
Add guard-mode multi-round-trip tools (SEP-2322) (#4544)
* Add guard-mode MRTR server support (SEP-2322)

* Add server-side MRTR guard tests

* Add MRTR guard docs, exports, and output-schema handling

* Apply formatting to MRTR guard changes

* Fix MRTR review round 1: middleware-safe suspend, Annotated strip, stable audience

- ToolInputRequired subclasses BaseException (CancelledError precedent) so
  error middleware's broad except Exception cannot swallow a suspension
- Strip InputRequiredResult arms inside Annotated return types
- Reject a custom RequestStateSecurity without a stable audience (random
  per-replica server names would break shared-key verification)

* Fix static analysis: rewrite tuple([...]) as tuple literal (C409)

* Recognize InputRequiredResult inside Annotated union arms

_is_input_required_type now peels Annotated first, so a metadata-carrying
guard arm (str | Annotated[InputRequiredResult, Field(...)]) is stripped
and the data arm's output schema survives.

* docs: frame multi-round tools as elicitation on the modern protocol

Fold multi-round-tools.mdx into elicitation.mdx as two eras of one
capability; drop pause/suspend framing for the stateless per-round model.

* Transport MRTR asks as InputRequiredToolResult, not a raised signal

An input-required result is the full result of a stateless MRTR leg, so it
flows through the middleware chain as an ordinary ToolResult subclass instead
of a raised ToolInputRequired(BaseException). Middleware observes it, caching
skips it, and response-limiting leaves it untouched.

* Document MRTR middleware interaction and the isinstance pattern

* Update MRTR change-register verify note to InputRequiredToolResult

* Align test module docstring with result-cycle framing

* Fix MRTR review: bypass cache on continuation legs; soften audience guard

- ResponseCachingMiddleware skips read AND write on continuation legs:
  the cache key is name+arguments only, so a continuation's final result
  would be served to later fresh calls, which would never be asked
- The stable-audience check is a warning, not an error: a policy object
  cannot reveal whether its keys are shared, and single-process
  customization (ephemeral ttl, custom codec) is legitimate unnamed

* Treat state-only rounds as continuations in the response cache

A round carrying request_state but no questions retries with
input_responses=None; request_state alone must bypass the cache or its
terminal result is stored under the fresh-call key.

* Fix MRTR review round: preserve asks through transforms, empty-name audience, docs predicate

- TransformedTool.run returns an InputRequiredToolResult intact instead of
  reshaping it into an empty ToolResult for non-object output schemas
- audience warning uses a falsy-name check (empty string also autogenerates
  a per-replica name)
- the elicitation docs continuation predicate checks request_state too

* Add create_proxy(mode=) opt-in for guard round-tripping through proxies

An auto-created proxy client stays handshake-era by default (a dual-era
backend serves both, and one proxy session is one era; handshake preserves
server-initiated push forwarding). Pass create_proxy(target, mode="auto")
to negotiate modern so an upstream guard's InputRequiredResult round-trips —
the two are mutually exclusive per session.

* Wrap raw InputRequiredResult returned by a transform_fn

A custom transform function may return the raw ask directly, like any tool
body — wrap it into InputRequiredToolResult so it survives output
normalization and reaches the wire, not only pre-wrapped forwarded guards.

* Reject input-required results from background tasks

* Unwrap type aliases before stripping guard arms

* Apply ruff format

* Recursively strip guard arms through nested and composed aliases

* Reflect MRTR continuation fields on the middleware message

* Suppress output schema for InputRequiredResult subclasses

* Forward progress on modern proxy tool calls

* Suppress output schema for bare aliased guard returns

* Suppress output schema for any surviving guard return wrapping
2026-07-19 16:42:06 -04:00
marvin-context-protocol[bot]
0781e723c2
chore: Update SDK documentation (#4442)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-19 15:06:18 -04:00
dependabot[bot]
87fa361239
chore(deps): bump actions/setup-node from 6 to 7 (#4546)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 15:06:07 -04:00
Bill Easton
3041aa241e
Align client, Apps, and integration docs (#4261)
* docs: align client and integration docs

Generated with Codex.

* docs: align Descope local URL

Generated with Codex.

* docs: load .env explicitly in Descope setup

* docs: load .env in Scalekit setup, guard non-mapping logging extra

* docs: handle null response_type in elicitation template, qualify STDIO env allowlist by platform

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-19 14:30:51 -04:00
Bill Easton
149a7aa2ce
Align CLI, deployment, and config docs (#4259)
* docs: align CLI and deployment docs

Generated with Codex.

* docs: restore install config support, fix CIMD placeholder, add missing CLI flags

* docs: restore contrib guidance, correct --copy availability

* docs: remove dead redirect-shadowed pages

* Fix stale --path default in run command help

* docs: correct Goose flag support, fix README link to moved testing page

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-19 14:24:07 -04:00
Bill Easton
d3b7922615
Align server component docs (#4260)
* docs: align server component docs

Generated with Codex.

* docs: clarify resource return shapes

Generated with Codex.

* docs: clarify initialize middleware response

Generated with Codex.

* docs: lead visibility filtering with names, scope keys to version targeting

* docs: correct initialize result semantics, template mime type, docket scope, visibility tip

* Warn when a visibility key omits the @ version delimiter

* Honor a resource template's declared mime_type and meta on read

* Strip internal visibility meta from resource content; document filter intersection

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-19 14:23:36 -04:00
Jeremiah Lowin
67e8448389
[codex] Add OAuthProxy RFC 9207 issuer responses (#4438)
* Add OAuthProxy issuer response parameter

* Cover OAuthProxy issuer error redirects

* Relax host origin guard defaults (#4439)

* Use exact issuer in authorize errors

* Restore HTTP host guard compatibility (#4472)

* Hugging Face Auth Integration (#4385)

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>

* Docs: add v3.4.4 changelog entries (#4473)

* Explain unnormalized issuer; cover consent-denial path base_url

* Revert "Merge remote-tracking branch 'origin/release/3.x' into codex/oauth-proxy-rfc9207-issuer"

This reverts commit 9e34b1686c, reversing
changes made to 640dc60fe0.

* Preserve callback query bytes when appending iss/code/state params

add_query_params previously decoded the existing query with parse_qsl
and re-encoded it, mutating opaque or signed query strings (a valueless
?flag became ?flag=, non-UTF-8 percent-encoded bytes got replaced).
Append the newly-encoded params to the existing query string instead of
round-tripping it through parse/encode.

Also fixes a stray bare `httpx` reference in a test that should use
httpx2 following the SDK v2 migration.

* Attach RFC 9207 iss to authorize() success redirects too

AuthorizationHandler only added iss to error redirects from the SDK's
base handler, not to code redirects returned directly by authorize()
overrides that bypass consent/upstream (as GitHub's mocked test does).
Since metadata now unconditionally advertises
authorization_response_iss_parameter_supported, any client-facing
redirect missing iss hard-fails RFC 9207-aware clients.

Also fixes HeadlessOAuth, which parsed code/state from the redirect
but silently dropped iss, so the same regression would have masked
itself across every other provider integration test too.

* Carry RFC 9207 iss through the production OAuth callback path

OAuthProxy advertises authorization_response_iss_parameter_supported and
sends iss on every authorization redirect, but the client's production
callback chain (CallbackResponse -> OAuthCallbackResult -> OAuth.callback_handler)
had no iss field, so it was silently dropped and the SDK's
validate_authorization_response_iss rejected the callback. HeadlessOAuth
already carried iss through, which is why CI stayed green while real
clients failed.

Add iss to CallbackResponse and OAuthCallbackResult, thread it through
store_result_once for both success and error branches, and pass it into
AuthorizationCodeResult in OAuth.callback_handler.

* Don't duplicate iss when a provider redirect already carries one

* Consolidate RFC 9207 iss handling into a single redirect helper

Every client-facing authorization redirect must carry exactly one iss.
That invariant was being enforced by hand at five separate call sites,
each building its own params dict -- which is how the success-redirect
path shipped without iss in the first place, and how a registered
redirect_uri that already carries its own iss could end up duplicated.
Route all five sites through build_client_redirect(), which owns the
idempotent replace-or-append behavior so no caller can get it wrong.

---------

Co-authored-by: shaun smith <1936278+evalstate@users.noreply.github.com>
2026-07-19 09:52:43 -04:00
Jeremiah Lowin
252a29e5e6
Preserve telemetry attributes when a sampler does not forward them (#4539)
* Reapply span attributes after creation to survive non-forwarding samplers

Tracer.start_span builds the span from sampling_result.attributes, not
the attributes kwarg — a custom Sampler that returns
SamplingResult(RECORD_AND_SAMPLE) without forwarding attributes
silently drops everything FastMCP passed at creation time. Reapply the
same attributes immediately after span creation (guarded by
is_recording()) so on_start hooks and samplers still see them, while
the finished span is guaranteed to carry FastMCP's telemetry
regardless of sampler behavior.

* Restore only missing span attributes, not a blanket reapply

Reapplying all attributes after span creation overwrote values a
sampler deliberately set (e.g. a redacted mcp.method.name) and
inflated dropped-attribute counts when the SDK's attribute limit was
hit. Compare against the span's existing attributes and restore only
the keys a non-forwarding sampler actually dropped, via a shared
restore_missing_attributes() helper in fastmcp.telemetry.

* Gate attribute restore on all-or-nothing, not per-key

Restoring only missing keys reinserted attributes the SDK's bounded
attribute map had already evicted under a low
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, evicting a different retained key and
inflating dropped_attributes beyond what the sampler actually dropped.
Gate on none of our attributes being present (plus dropped_attributes
== 0) instead — the regression this exists to fix is a sampler
dropping everything, and eviction under a limit always leaves some.
Renamed restore_missing_attributes to restore_dropped_attributes to
match.

* Gate attribute restore on empty span, not per-key presence

A sampler that intentionally supplies only its own attributes (e.g. to
strip component names or resource URIs for privacy/cardinality
control) left none of FastMCP's keys on the span, so the previous
all-or-nothing gate treated it identically to a bare non-forwarding
sampler and restored everything, defeating the filter. Key off the
span having no attributes at all instead — a bare sampler leaves it
empty, a filtering sampler doesn't.
2026-07-19 09:00:04 -04:00
Alexander Savchuk
2899ffb6f3
Fix #4292: SSRF guard breaks OAuth/JWKS fetches behind a corporate HTTP proxy (#4412)
* Add FASTMCP_SSRF_TRUST_PROXY to allow SSRF fetches through a corporate proxy

🤖 Generated with Claude Code

* Make SSRF fetch client trust_env explicit for proxy routing

🤖 Generated with Claude Code

* Warn when SSRF proxy trust is enabled without a configured proxy

🤖 Generated with Claude Code

* Warn when NO_PROXY would send an SSRF-trust-proxy fetch direct

🤖 Generated with Claude Code

* Refuse SSRF-trust-proxy fetches when no proxy would route the target

🤖 Generated with Claude Code

* Fix TestProxyMode mocks to patch httpx2.AsyncClient

main's httpx -> httpx2 migration (#4503) landed after these tests were
written; ssrf.py's fetch path already uses httpx2.AsyncClient, but
TestProxyMode still patched the old httpx module, so the mock silently
stopped intercepting and requests escaped to the real network.

* Fix port-qualified NO_PROXY bypass in SSRF proxy-trust guard

proxy_bypass(hostname) discarded the port, so a NO_PROXY entry like
127.0.0.1:8443 went undetected while httpx2 honored it and sent the
request direct with the blocklist already disabled. Pass host:port
instead, except for IPv6 literals, where httpx2 ignores port when
matching NO_PROXY and neither bracketed nor unbracketed host:port
reliably matches through proxy_bypass()'s own parser.

* Replace NO_PROXY prediction with explicit proxy control in SSRF trust-proxy mode

Predicting httpx2's proxy routing (via proxy_bypass(), then via httpx2's own
get_environment_proxies()/URLPattern internals) kept diverging from its real
NO_PROXY handling — three rounds, three different divergences, always in the
unsafe direction. Read HTTPS_PROXY/ALL_PROXY directly and pass it to httpx2
explicitly with trust_env=False, so the request provably goes through that
proxy instead of being predicted to. NO_PROXY is no longer evaluated in this
mode: a NO_PROXY'd host is now routed through the proxy rather than refused,
since that's strictly safer than the alternative (direct with the blocklist
already off).

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 21:42:52 -04:00
Jeremiah Lowin
cee327d8f7
Restore Mintlify's fixed banner positioning (#4542) 2026-07-18 21:25:39 -04:00
Viktor Szépe
81fada4922
Fix typos (#4498)
* Fix typos

* Document Cachable* -> Cacheable* rename as v4 breaking change

Adds the response-cache model rename to the change register, per
maintainer decision to skip compatibility aliases in favor of clear
documentation.

* Skip invalid Before import in doc test; use inline codespell ignore

The Cachable* -> Cacheable* breaking-change entry showed the old,
now-invalid import for contrast, which the doc-example test picked up
as a real import and flagged as a regression. Comment out the
deliberately-broken "Before" line (matching the McpError entry just
above it) so only the working "After" import is exercised.

Also swap the blanket codespell ignore-words-list entry for a
narrower inline `codespell:ignore` directive on the one line that
needs it, so codespell keeps flagging "cachable" everywhere else.

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 21:18:39 -04:00
Pierre Audonnet
a57f1c8b20
Add subject field to AccessToken initialization (#4267)
* Add subject field to AccessToken initialization

Fixes #4266

Add `subject` property to the AccessToken.

```python
        return AccessToken(
            token=access_token_as_dict["token"],
            client_id=access_token_as_dict["client_id"],
            scopes=access_token_as_dict["scopes"],
            subject=access_token_as_dict["subject"],
            # Optional fields
            expires_at=access_token_as_dict.get("expires_at"),
            resource=access_token_as_dict.get("resource"),
            claims=access_token_as_dict.get("claims") or {},
        )
```

* Populate AccessToken.subject across all token verifiers

Closes #4266. get_access_token().subject was always None: the SDK's
AccessToken.subject wasn't carried into FastMCP's AccessToken by the
dependency-layer conversion, and none of the built-in TokenVerifiers
(JWT, introspection, and the OAuth-provider verifiers for Discord,
Clerk, Google, WorkOS, HuggingFace, GitHub, and Cognito) populated it
from the sub claim/field they already extract.

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 21:15:13 -04:00
vijaydeepsinha
654335607c
Fix-issue-4284 : Add Auth0MCPProvider for Auth0 Auth for MCP (#4411)
* Add Auth0MCPProvider for Auth0 Auth for MCP

* Document Auth0 MCP provider integration

* Add Auth0MCPProvider scope and auth rejection tests

Cover permissions-based required_scopes enforcement and unauthenticated MCP 401 responses.

* fixed documentation

* Narrow Auth0 docs to integration guide only

* Fix Auth0 provider: use httpx2 instead of httpx

httpx is a dev-only transitive dependency in this repo; runtime installs
declare httpx2 exclusively. The module-level 'import httpx' in auth0.py
broke import on a clean install of fastmcp or fastmcp-slim[server].

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 21:15:02 -04:00
Jeremiah Lowin
62d32c6a90
Add 4.0.0 version badge to Path Security section (#4540) 2026-07-18 20:58:32 -04:00
Jeremiah Lowin
2ebf19e5e1
Make examples/ actually trigger the ty gate (#4541)
#4466 added examples/ to [tool.ty.src] include, but two filters still
excluded it: the ty prek hook's files: scope and the static-analysis
workflow's push path triggers. An examples-only commit or direct push
to main could skip the gate entirely.
2026-07-18 20:58:24 -04:00
Jeremiah Lowin
83702a41f8
Document icon theme support (#4537)
* Document icon theme support and add round-trip tests

MCP SDK v2 added a `theme` field to `Icon` (light/dark), letting a
server ship complementary icon variants for clients that render in
different UI themes. Document the field on the icons page and cover
it with round-trip tests through the server/client protocol.

* docs: add 4.0.0 version badge to Theme Variants section
2026-07-18 20:57:36 -04:00
Jeremiah Lowin
243f054f65
Include scopes in auth challenges (#4527) 2026-07-18 20:53:52 -04:00
Jeremiah Lowin
998b37f32b
Add server-side identity assertion (SEP-990 ID-JAG) (#4483)
* Add server-side SEP-990 identity assertion (ID-JAG)

* Test SEP-990 identity assertion token endpoint

* Format identity assertion test

* Document SEP-990 identity assertion

* Thread identity_assertion through OIDCProxy

* Harden ID-JAG: authoritative scopes and grant-type enforcement

Scopes for the issued token now derive only from the signed assertion (or server policy when it omits scopes); the client-supplied request scope may narrow but never widen them. Enforce the registered grant-type constraint the SDK check bypassed, and have proxy DCR add the jwt-bearer grant to registered clients when identity assertion is enabled.

* Harden ID-JAG: honor nbf, reject non-object payload, bound jti cache, preserve required_scopes

* Document per-process ID-JAG replay limitation and nbf check

* Harden ID-JAG round 3: resource indicator, non-object header, algorithm config

- Honor RFC 8707 resource on the jwt-bearer grant (invalid_target on
  mismatch), mirroring authorize()'s invariant incl. skip-when-unconfigured
- Reject JSON-array JOSE headers with invalid_grant instead of a 500
- Add IdentityAssertion.algorithm so ES256/PS256 issuers can be verified
  (JWTVerifier otherwise defaults to RS256)

* Bind ID-JAG exchange to the assertion's signed client_id and resource

SEP-990: the IdP signs which client and which resource the assertion was
minted for. With public proxy clients the presented client_id is
self-asserted, so the signed binding is what stops client B redeeming
client A's leaked assertion — and the signed resource claim stops an
assertion for server A being redeemed at server B behind the same IdP.

* Harden ID-JAG round 4: check bindings before jti consumption; validate temporal claims, algorithm, and discovery body

- Move the client_id/resource binding checks into the validator itself,
  before jti is recorded as consumed, so an assertion presented with the
  wrong binding is rejected without burning replay protection for whoever
  it actually belongs to
- Reject non-numeric exp/iat/nbf with invalid_grant instead of a 500
- Validate IdentityAssertion.algorithm at config time (must be an
  asymmetric JWS algorithm verifiable via JWKS)
- Reject a non-object OIDC discovery body with invalid_grant instead of a 500
- Centralize the resource-URL comparison helpers used by both the
  validator and OAuthProxy.authorize()

* Rebase onto httpx2/SDK b2 and harden ID-JAG round 5

- Migrate identity assertion + tests to httpx2 and the local httpx2_mock
  (legacy httpx is now banned; pytest-httpx no longer intercepts)
- Add is_optional to the shared httpx2_mock, mirroring pytest-httpx
- Tighten the algorithm allowlist to JWTVerifier's exact supported set
  (prefix check accepted typos like RS999 -> 500 on first exchange)
- Reject non-string jti before the cache lookup (unhashable -> 500)
- Track revocation for self-contained ID-JAG tokens: revoke_token records
  the jti and load_access_token rejects it until natural expiry
- Dedupe resource-URL helpers: proxy now imports the shared
  normalize_resource_url/server_url_has_query from identity_assertion

* Advertise 'none' token-endpoint auth method when ID-JAG is enabled without CIMD

DCR clients are public, so metadata consumers must see 'none' to use the
advertised jwt-bearer grant; previously only the CIMD path added it.

* Document 2026-07-28 protocol support as a distinct feature catalog

SEP-990 identity assertion leads: the SDK provides the wire contract and
provider hook; FastMCP provides the complete server-side implementation.
Inventories the full modern-era capability set for v4.

* Harden ID-JAG round 6: lazy re-export, dual-form audience, per-issuer algorithms, discovery backoff

- IdentityAssertion re-exported lazily from server.auth (the eager import
  bypassed the package's documented lazy-import boundary)
- Accept the ID-JAG aud both with and without base_url's trailing slash;
  metadata advertises the slashed form, so IdPs echoing it verbatim work
- algorithms={issuer: alg} per-issuer override, mirroring jwks_uris
- OIDC discovery serializes per-issuer and backs off 30s after a failure
  (discovery runs pre-signature, so garbage could amplify into HTTP floods)
2026-07-18 19:52:15 -04:00
nate nowack
f018f68bbf
Expose telemetry attributes on span start (#4487)
* Expose telemetry attributes on span start

🤖 Generated with Codex

* Expose sampling attributes on span start

🤖 Generated with Codex

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 19:46:19 -04:00
Jeremiah Lowin
7d76c9d055
Add examples/ to the ty static-analysis gate (#4466)
* Add examples/ to ty static-analysis gate

* Fix example type errors and stale SDK idioms for ty

* Use typing_extensions.TypedDict for the quiz tool-param type

Question is a take_quiz parameter, so FastMCP builds a Pydantic schema
for it; typing.TypedDict raises PydanticUserError on Python 3.10/3.11
(only 3.12+ accepts it). ty and 3.12 runs miss this, so it slipped in.

* Guard get_access_token() None case in huggingface_oauth example

Caught by the ty gate this PR adds: the example, merged separately,
had never been type-checked against examples/. Matches the existing
aws_oauth/keycloak_oauth pattern.

* Print actual YAML text in custom serializer example
2026-07-18 19:44:13 -04:00
Kevin J Gao
3fdeedb567
Improve DescopeProvider scope discovery and well-known URL support (#4489)
* Improve DescopeProvider scope discovery and well-known URL support

Co-authored-by: Cursor <cursoragent@cursor.com>

* Simplify DescopeProvider scope and URL handling

Co-authored-by: Cursor <cursoragent@cursor.com>

* Make DescopeProvider scope discovery async and lazy

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with Claude Code

* Use generic scope in Descope tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with Claude Code

* Address Descope discovery edge cases

* Deduplicate Descope metadata fallback

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 16:18:45 -04:00
dependabot[bot]
c241cd4698
chore(deps): bump mcp from 1.26.0 to 1.27.2 in /examples/testing_demo in the uv group across 1 directory (#4514)
Signed-off-by: dependabot[bot] <support@github.com>
2026-07-18 15:49:30 -04:00
Jeremiah Lowin
7e077186fc
Clean up task sessions on connection exit (#4535) 2026-07-18 15:45:11 -04:00
Jeremiah Lowin
16383a64d6
Preserve component metadata in response cache (#4521) 2026-07-18 15:42:20 -04:00
Jeremiah Lowin
00cab8ba8f
Fix docs banner contrast (#4522)
* Fix docs banner contrast

* Banner: readable animated brand-rainbow in both themes
2026-07-18 15:38:03 -04:00
Jeremiah Lowin
d7eda92a2b
Fix OAuth request annotation (#4534) 2026-07-18 15:29:32 -04:00
Jeremiah Lowin
981a69d839
Handle expired OAuth client registrations (#4520) 2026-07-18 15:16:27 -04:00
Jeremiah Lowin
18b5ab5852
Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
Jeremiah Lowin
66c0270bc1
Stabilize upgraded ty checks (#4526) 2026-07-17 17:46:53 -04:00
Jeremiah Lowin
bdb76ef4b2
Clean up disconnected task sessions (#4519) 2026-07-17 17:46:13 -04:00
Jeremiah Lowin
a3ecd1edb1
Clarify PR-reopen flow and fix label-race that broke auto-reopen (#4518)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-17 17:43:05 -04:00
Jeremiah Lowin
d779414f8a
Screen templated resource parameters for path traversal by default (#4482)
* Add ResourceSecurity screening for templated resources (defaults on)

* Add tests for resource path-security screening

* Document resource path-security; fix ty in tests

* Carry child template security policy through provider mount

Preserve a mounted template's explicit ResourceSecurity (per-param
exemptions or a deliberate opt-out) through FastMCPProviderResourceTemplate.wrap
so the parent read chokepoint honours it instead of the parent default.

* Defer mcp SDK import so fastmcp.resources loads without the [mcp] extra

* Make resource path-security docs examples self-contained and runnable

* Match exempt_params under both hyphen and underscore spellings

Template placeholders like {git-ref} extract as git_ref, so an exemption
written with the natural URI-template spelling never matched.

* Docs: describe net-depth traversal rule accurately; make example runnable

The screening only rejects .. segments that escape the starting depth
(foo/../bar passes) — saying any standalone .. is rejected overstated
the guarantee. Also define DOCS_ROOT so the example runs.
2026-07-17 17:42:48 -04:00
Jeremiah Lowin
918b85f9b2
Reject positional-only tool parameters (#4524) 2026-07-17 17:37:28 -04:00
Jeremiah Lowin
ff2fc234b2
Trace client task management requests (#4525) 2026-07-17 17:37:12 -04:00
Jeremiah Lowin
b623c23183
Serialize deep object query parameters (#4523) 2026-07-17 17:33:57 -04:00
Grégoire
977f02347b
Forward upstream instructions through create_proxy (#4512)
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
2026-07-17 17:29:15 -04:00
WinkleMad
6202008cf3
Don't mutate the caller's schema in compress_schema (#4492) 2026-07-17 17:29:01 -04:00
Burt Matthews
1fca15abe6
Skip unsupported JWKS keys instead of failing the whole key set (#4515) (#4517) 2026-07-17 17:28:43 -04:00
石岳峰
291fab8789
fix(server): omit ScalarElicitationType wrapper title from elicitation schemas (#4502) 2026-07-17 17:28:30 -04:00
Jeremiah Lowin
a04f6fd911
Add telemetry off-switch and mcp.protocol.version span attribute (#4481)
* Turn OpenTelemetry instrumentation on by default with explicit off-switch

Add FASTMCP_ENABLE_TELEMETRY setting (default true) and mcp.protocol.version
span attribute for SDK parity.

* Make disabled telemetry a transparent pass-through, not a NoOpTracer

The stock NoOpTracer.start_as_current_span attaches a NonRecordingSpan, hijacking the current OTel context from any enclosing application span. When telemetry is disabled, get_tracer() now returns a non-attaching pass-through tracer so trace.get_current_span() inside handlers still resolves to the caller's span.
2026-07-17 17:02:48 -04:00
Jeremiah Lowin
266c129b62
Test lifespan fires once per process over HTTP (#4480)
* Add regression test: HTTP lifespan fires once per process across sessions

* Drop redundant enter-count assertion at teardown (CodeQL)

* Assert session-manager lifespan entry directly, not user-lifespan count
2026-07-17 17:02:26 -04:00
Jeremiah Lowin
836ceac30e
Add KeyValueResponseCacheStore for distributed client response caching (#4479)
* Add KeyValueResponseCacheStore adapter for client response cache

* Test KeyValueResponseCacheStore round-trip, isolation, and distributed sharing

* Document distributed response cache store
2026-07-17 16:41:35 -04:00
nate nowack
1d932cc778
Fix Azure scope fallback (#4469) 2026-07-09 15:29:50 -04:00
Jeremiah Lowin
9f251bad00
Forward-port Hugging Face auth provider (#4475) 2026-07-08 20:56:07 -04:00
Jeremiah Lowin
4ad78a60ef
Forward-port HTTP host guard compatibility (#4474) 2026-07-08 20:55:56 -04:00
Jeremiah Lowin
00a7745994
Docs: forward-port v3.4.4 changelog entries (#4476) 2026-07-08 20:55:43 -04:00
Jeremiah Lowin
fd5d98bd13
Test: HTTP lifespan fires once per process across sessions (#4470) 2026-07-08 20:55:26 -04:00
Jeremiah Lowin
8ba5b89918
Add server-level cache hints (SEP-2549) (#4464) 2026-07-08 09:10:41 -04:00
Jeremiah Lowin
3c43038860
Fix stale mcp.types imports in examples (#4452) 2026-07-07 08:07:07 -04:00
Jeremiah Lowin
515a2244a2
Teach fastmcp.Client the modern protocol: mode negotiation, MRTR driver, response cache (#4450) 2026-07-07 08:00:45 -04:00
Jeremiah Lowin
f30f847e1f
Merge pull request #4449 from PrefectHQ/modernize/path-security
Route skill file access through SDK path-security primitives
2026-07-07 08:00:21 -04:00
Jeremiah Lowin
f0e350942f
Merge pull request #4448 from PrefectHQ/modernize/sampling-deprecation
Deprecate ctx.sample and add clear errors for push features on 2026 connections
2026-07-07 08:00:08 -04:00
Jeremiah Lowin
7832f884c6
Merge pull request #4453 from PrefectHQ/remove/deprecated-params
Remove 3.x deprecated parameters and object-mode decorators
2026-07-07 07:59:53 -04:00
Jeremiah Lowin
3cb34034d2
Merge pull request #4451 from PrefectHQ/remove/server-method-deprecations
Remove 3.0-deprecated FastMCP server methods
2026-07-07 07:59:40 -04:00
Jeremiah Lowin
bf3a079f87
Merge pull request #4447 from PrefectHQ/remove/module-shims
Remove 3.x deprecated module shims and dead parameters
2026-07-07 07:59:16 -04:00
Jeremiah Lowin
4a8852af10
Docs: register removed deprecations in v4 change register 2026-07-07 07:53:12 -04:00
Jeremiah Lowin
7c2133a52f
Remove deprecated component-import __getattr__ shims 2026-07-07 07:53:12 -04:00
Jeremiah Lowin
805ce96689
Remove deprecated decorator_mode setting and object-mode machinery 2026-07-07 07:53:12 -04:00
Jeremiah Lowin
45475bd072
Remove deprecated exclude_args tool parameter 2026-07-07 07:53:12 -04:00
Jeremiah Lowin
da5754671b
Document as_proxy backend keyword migration 2026-07-07 07:53:11 -04:00
Jeremiah Lowin
7f032bb82e
Remove deprecated tool-level serializer parameter 2026-07-07 07:53:11 -04:00
Jeremiah Lowin
396fb876d3
Apply ruff-format: drop now-unused imports and reflow 2026-07-07 07:53:11 -04:00
Jeremiah Lowin
508a08475f
Docs: mark removed-in-4.0 deprecations in upgrade guide and change register
Annotates the v2->v3 upgrade guide's deprecated server methods as removed in
v4, and adds a Removed in 4.0 section to the change register.
2026-07-07 07:53:11 -04:00
Jeremiah Lowin
6a6fdcb2bb
Repoint tests and examples off removed deprecations
Replaces FastMCP.as_proxy() helper calls with create_proxy(), rewrites the
mount() as_proxy=/prefix= kwarg tests to plain mount() (the params are gone),
and deletes deprecation-only tests for as_proxy() and remove_tool().
2026-07-07 07:53:11 -04:00
Jeremiah Lowin
14373cc60b
Repoint examples off removed shim paths 2026-07-07 07:53:10 -04:00
Jeremiah Lowin
e5d9d1f17d
Remove deprecated FastMCP server methods for 4.0
Removes deprecations that shipped replacements in 3.0:
- FastMCP.as_proxy() classmethod -> create_proxy()
- import_server() -> mount()
- mount(prefix=) -> namespace=
- mount(as_proxy=) -> now meaningless; mounts always invoke lifespan/middleware
- add_tool_transformation() -> add_transform(ToolTransform({...}))
- remove_tool_transformation() -> pure no-op that warned callers it had no
  effect; removed entirely
- FastMCP.remove_tool() -> mcp.local_provider.remove_tool()

Also drops the now-unused URI_PATTERN/re import and FastMCPDeprecationWarning
import. The _REMOVED_KWARGS TypeError shim is retained.
2026-07-07 07:53:10 -04:00
Jeremiah Lowin
be8aee3a96
Skip live-import validation for frozen v2 doc snapshots 2026-07-07 07:53:10 -04:00
Jeremiah Lowin
ad02710e9b
Docs: register 4.0 deprecation removals in change register 2026-07-07 07:53:10 -04:00
Jeremiah Lowin
36cbef6813
Remove no-op sse_read_timeout param from StreamableHttpTransport
Tier 2 aggressive-window removal: the parameter was a deprecated no-op
on the streamable-HTTP transport (the SDK v2 client no longer supports
it). SSETransport still accepts sse_read_timeout.
2026-07-07 07:53:10 -04:00
Jeremiah Lowin
d74f7b5996
Remove deprecated PromptToolMiddleware / ResourceToolMiddleware (3.1)
Use the PromptsAsTools / ResourcesAsTools transforms instead. The
non-deprecated ToolInjectionMiddleware base class is retained.
2026-07-07 07:53:10 -04:00
Jeremiah Lowin
d1c51ea4db
Remove deprecated fastmcp.server.apps / server.app shims (3.2)
Tier 2 aggressive-window removal: these shims were deprecated in 3.2,
a shorter deprecation window than the usual policy. Canonical imports
are fastmcp.apps / fastmcp.FastMCPApp.
2026-07-07 07:53:10 -04:00
Jeremiah Lowin
9d95e34e19
Remove deprecated experimental openapi shims (2.14) 2026-07-07 07:53:10 -04:00
Jeremiah Lowin
497ed2ea00
Remove deprecated fastmcp.server.openapi shim + FastMCPOpenAPI (3.0) 2026-07-07 07:53:10 -04:00
Jeremiah Lowin
e89763d709
Remove deprecated fastmcp.server.proxy shim (3.0) 2026-07-07 07:53:09 -04:00
Jeremiah Lowin
6621024ce4
Drive the FastMCP lifespan through the SDK session manager (#4446) 2026-07-07 07:49:16 -04:00
Jeremiah Lowin
ac78e6f693
Emit one SERVER span per request and adopt spec-correct error codes (#4445) 2026-07-07 07:49:06 -04:00
Jeremiah Lowin
023a578279
Capture SharedContext for task-enabled Docket servers (#4443) 2026-07-07 07:48:49 -04:00
Jeremiah Lowin
13b9ab80ab
Use a single fastmcp import style in protocol-era tests 2026-07-06 22:06:22 -04:00
Jeremiah Lowin
77131edc00
Don't era-gate server-side sampling handlers on modern connections
The era-gate blocked every ctx.sample/sample_step on a 2026-07-28
connection, but a server-configured sampling handler answers server-side
without the client back-channel. Gate only when the request would hit the
removed client path; force the handler path (client_available=False) on
modern so "fallback" goes straight to the handler instead of a bare
client-attempt failure.
2026-07-06 21:49:18 -04:00
Jeremiah Lowin
05be554e85
Apply ruff formatting to attack corpus tests 2026-07-06 21:32:47 -04:00
Jeremiah Lowin
b023aae51a
Docs: mark sampling deprecated, update era matrix and change register 2026-07-06 21:32:17 -04:00
Jeremiah Lowin
389e3b78e7
Add path-safety attack corpus tests and document skill file confinement 2026-07-06 21:31:56 -04:00
Jeremiah Lowin
17954f569d
Deprecate ctx.sample/sample_step and era-gate sampling+elicit on modern connections 2026-07-06 21:30:03 -04:00
Jeremiah Lowin
1966e619f7
Route skill file reads through SDK safe_join for path safety 2026-07-06 21:29:22 -04:00
Jeremiah Lowin
3522a98766
Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
16 changed files with 16 additions and 16 deletions

View file

@ -15,7 +15,7 @@ runs:
using: "composite" using: "composite"
steps: steps:
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
with: with:
enable-cache: true enable-cache: true
cache-dependency-glob: "uv.lock" cache-dependency-glob: "uv.lock"

View file

@ -26,7 +26,7 @@ jobs:
private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }} private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Auto-close duplicate issues - name: Auto-close duplicate issues
run: uv run scripts/auto_close_duplicates.py run: uv run scripts/auto_close_duplicates.py

View file

@ -26,7 +26,7 @@ jobs:
private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }} private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Auto-close needs MRE issues - name: Auto-close needs MRE issues
run: uv run scripts/auto_close_needs_mre.py run: uv run scripts/auto_close_needs_mre.py

View file

@ -28,7 +28,7 @@ jobs:
uses: actions/checkout@v7 uses: actions/checkout@v7
- name: Install UV - name: Install UV
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
with: with:
enable-cache: true enable-cache: true
cache-dependency-glob: "uv.lock" cache-dependency-glob: "uv.lock"

View file

@ -30,7 +30,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Install UV - name: Install UV
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
with: with:
enable-cache: true enable-cache: true
cache-dependency-glob: "uv.lock" cache-dependency-glob: "uv.lock"

View file

@ -41,7 +41,7 @@ jobs:
# Install UV package manager # Install UV package manager
- name: Install UV - name: Install UV
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
# Install dependencies # Install dependencies
- name: Install dependencies - name: Install dependencies

View file

@ -24,7 +24,7 @@ jobs:
ref: ${{ github.event.workflow_run.head_sha || github.sha }} ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Build fastmcp-remote - name: Build fastmcp-remote
run: uv build --package fastmcp-remote run: uv build --package fastmcp-remote

View file

@ -21,7 +21,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Build fastmcp-slim - name: Build fastmcp-slim
run: uv build --package fastmcp-slim run: uv build --package fastmcp-slim

View file

@ -38,7 +38,7 @@ jobs:
fi fi
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Build fastmcp-tasks - name: Build fastmcp-tasks
if: steps.package_present.outputs.present == 'true' if: steps.package_present.outputs.present == 'true'

View file

@ -27,7 +27,7 @@ jobs:
ref: ${{ github.event.workflow_run.head_sha || github.sha }} ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Build fastmcp - name: Build fastmcp
run: uv build --package fastmcp run: uv build --package fastmcp

View file

@ -37,7 +37,7 @@ jobs:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
- name: Set up Python - name: Set up Python
run: uv python install 3.12 run: uv python install 3.12

View file

@ -37,6 +37,6 @@ jobs:
resolution: locked resolution: locked
- name: Run prek - name: Run prek
uses: j178/prek-action@v2 uses: j178/prek-action@v3.0.0
env: env:
SKIP: no-commit-to-branch SKIP: no-commit-to-branch

View file

@ -90,7 +90,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: "22" node-version: "24"
- name: Run conformance tests - name: Run conformance tests
uses: ./.github/actions/run-pytest uses: ./.github/actions/run-pytest

View file

@ -38,7 +38,7 @@ jobs:
resolution: upgrade resolution: upgrade
- name: Run prek - name: Run prek
uses: j178/prek-action@v2 uses: j178/prek-action@v3.0.0
env: env:
SKIP: no-commit-to-branch SKIP: no-commit-to-branch

View file

@ -33,7 +33,7 @@ jobs:
token: ${{ steps.marvin-token.outputs.token }} token: ${{ steps.marvin-token.outputs.token }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
with: with:
enable-cache: true enable-cache: true
cache-dependency-glob: "uv.lock" cache-dependency-glob: "uv.lock"

View file

@ -33,7 +33,7 @@ jobs:
token: ${{ steps.marvin-token.outputs.token }} token: ${{ steps.marvin-token.outputs.token }}
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v9.0.0
with: with:
enable-cache: true enable-cache: true
cache-dependency-glob: "uv.lock" cache-dependency-glob: "uv.lock"