A background task still needs to know who asked for the work, so FastMCP
captures the caller's access token and every inbound HTTP header at
submission time and writes that snapshot to the Docket backend. On a
distributed backend the credentials sit in Redis as plaintext for the
task's TTL, and a rediss:// URL protects only the wire. Set
FASTMCP_ENCRYPTION_KEY and the snapshot becomes a Fernet token instead.
Restore fails closed: a worker that cannot decrypt a snapshot fails the
task rather than run the tool with no caller.
Closes#4747🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
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>
* 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>
* 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.
- Use 10 PBKDF2 iterations in test_mode (vs 1M in production) for
JWT key derivation — cuts auth test setup from ~2.5s to <0.1s
- Add timeout(15) to subprocess-spawning tests (TestKeepAlive,
test_mcp_config) that exceed 5s under parallel CI load
- Remove pytestmark filterwarnings overrides in tests/deprecated/
that were leaking DeprecationWarning to test output
- Fix deprecated add_tool_transformation() usage in test_authorization
- Document new settings in settings.mdx