fastmcp/tests/server
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
..
auth Fix #4292: SSRF guard breaks OAuth/JWKS fetches behind a corporate HTTP proxy (#4412) 2026-07-18 21:42:52 -04:00
http Add subject field to AccessToken initialization (#4267) 2026-07-18 21:15:13 -04:00
middleware Fix typos (#4498) 2026-07-18 21:18:39 -04:00
mount Apply ruff-format: drop now-unused imports and reflow 2026-07-07 07:53:11 -04:00
providers Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
sampling Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
tasks Clean up task sessions on connection exit (#4535) 2026-07-18 15:45:11 -04:00
telemetry Preserve telemetry attributes when a sampler does not forward them (#4539) 2026-07-19 09:00:04 -04:00
transforms Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
versioning Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
__init__.py restore 1.x code 2025-04-09 11:54:42 -04:00
test_app_state.py Update docs and test 2025-06-20 13:06:48 -04:00
test_auth_integration.py Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
test_auth_integration_errors.py Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
test_cache_hints.py Add server-level cache hints (SEP-2549) (#4464) 2026-07-08 09:10:41 -04:00
test_context.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_dependencies.py Capture SharedContext for task-enabled Docket servers (#4443) 2026-07-07 07:48:49 -04:00
test_dependencies_advanced.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_event_store.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_fastapi_testclient_compat.py fix: FastAPI TestClient compatibility and lifespan re-initialization (#3736) 2026-04-06 19:53:27 -04:00
test_file_server.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_icons.py Document icon theme support (#4537) 2026-07-18 20:57:36 -04:00
test_input_validation.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_log_level.py Allow pre-bound HTTP sockets (#4222) 2026-05-23 10:08:49 -04:00
test_logging.py Refactor server.py into mixins (#2939) 2026-01-19 11:36:00 -05:00
test_pagination.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_protocol_eras.py Use a single fastmcp import style in protocol-era tests 2026-07-06 22:06:22 -04:00
test_providers.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_server.py Repoint tests and examples off removed deprecations 2026-07-07 07:53:11 -04:00
test_server_docket.py Make pydocket optional and unify DI systems (#2835) 2026-01-10 16:23:32 -05:00
test_server_lifespan.py Update ty ignore comments for 0.0.25 compatibility (#3614) 2026-03-24 20:26:26 -04:00
test_server_safety.py fix: reject self-mount to prevent infinite recursion (#3925) 2026-04-14 12:10:19 -04:00
test_session_visibility.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_streamable_http_no_redirect.py Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
test_tool_annotations.py Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
test_tool_transformation.py Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
test_transport.py Forward-port HTTP host guard compatibility (#4474) 2026-07-08 20:55:56 -04:00