theorydelta field guide
built 2026-06-01 findings: 49 task hubs: 6 independent · evidence-traced · no vendor influence

FastMCP’s from_openapi() Path Leaked Auth Headers Twice and Corrupted GET Requests

Published: 2026-05-09 Last verified: 2026-04-03 empirical

FastMCP’s from_openapi() Path Leaked Auth Headers Twice and Corrupted GET Requests

What you expect

FastMCP’s from_openapi() provider lets you wrap any OpenAPI/REST API as an MCP server in a few lines. The framework handles schema conversion, request routing, and credential management — MCP client credentials should stay within the MCP transport layer and not cross into backend API calls.

What actually happens

Three separate bugs shipped in the from_openapi() path within three months of the FastMCP 3.0 release:

Auth header leakage to downstream APIs (FastMCP 3.0.0–3.0.1): MCP transport auth headers — Authorization: Bearer <token> received from the calling MCP client — were forwarded verbatim to downstream OpenAPI endpoint calls. Any third-party REST API wrapped via from_openapi() received the client’s MCP credentials. Confirmed in FastMCP 3.0.2 release notes. Fixed in 3.0.2.

Auth headers in debug logging (Issue #3427, March 2026; see also 3.0.2 release notes): MCP transport auth headers also appeared in plaintext in debug log output — separately confirmed from the production API leak, lower severity. The auth layer separation has failed at two independent points within the same release cycle.

Python dict literals instead of JSON in GET query strings (Issue #2857): FastMCP’s OpenAPI provider serialized object-type parameters in GET query strings as Python dict literals — {'myAttribute': True} URL-encoded — instead of JSON ({"myAttribute": true}). Backend APIs that parse query strings as JSON received silently malformed data. The tool call completed without error from FastMCP’s perspective. Fixed via PR #3662 merged 2026-03-28.

Additional confirmed failures in the 3.x lifecycle:

4.3s cold start on stdio servers (FastMCP 3.0.2): Eager import of the full auth stack (authlib, cryptography, httpx), Redis/storage dependencies, beartype, and MCP client modules added 4.3 seconds of avoidable delay at process start (Issue #3292, fixed via PR #3295, 2026-02-25). For deployments where every session spawns a fresh stdio process, this is material latency.

mount() context propagation — two silent bugs: ctx.get_state() returns None in mounted child tools when parent middleware sets state (Issue #3397). Resource URI templates with {?param} query syntax throw "Unknown resource" on mounted subservers (Issue #3366). Both failed silently at runtime rather than at registration time. Fixed in March 2026.

Stateless HTTP permanently hangs on sampling (Issue #1156, open; related #678 closed July 2025): stateless_http=True permanently hangs any tool that calls ctx.sample() — the request never completes, never times out at the MCP layer, and produces no error. Stateless mode creates a new server session per request, so there is no persistent client connection to route sampling callbacks through.

$ref in enum schemas rejected by Claude Opus and VS Code Copilot (Issue #2807, fixed PR #2808): FastMCP auto-generated $ref pointers into $defs for Python Enum parameters but omitted the $defs entries under certain code paths. Claude Opus returns "Invalid $ref in schema".

FastMCP and the official MCP Python SDK have permanently diverged (discussion #2557): FastMCP runs at approximately triple the weekly PR merge rate of the official Python SDK but deviates from strict spec compliance — prompts/get with image content fails conformance tests in FastMCP 3.x (Issue #3395). An Anthropic maintainer confirmed the projects remain diverged through SDK v2.0.

What this means for you

The native @mcp.tool() decorator path is production-viable. Most failures above affect the from_openapi() path or specific 3.0.x versions that have been patched. The concentrated risk is in wrapping existing REST APIs via OpenAPI ingestion:

  • Auth exposure in multi-server setups: Before 3.0.2, any multi-server deployment using from_openapi() exposed MCP client credentials to every backend API in the composition.
  • Silent data corruption: The Python-dict GET serialization bug sent malformed data with no error surface — backends silently received invalid query parameters.
  • Two separate auth layer failures in three months is a pattern, not an anomaly.

The stateless_http=True + sampling combination is a silent production trap in any version as of March 2026.

What to do

  1. Pin to FastMCP ≥ 3.0.2 to get the auth header fix. Verify the exact release containing PR #3662 (merged 2026-03-28) for the GET serialization fix.

  2. Use native @mcp.tool() decorators instead of from_openapi() for any server handling sensitive credentials. The decorator path has no comparable failure history.

  3. If using from_openapi(): After upgrading, send a GET request with an object-type parameter and inspect the raw HTTP query string — confirm it is valid JSON, not Python repr. Issue #2857 documents the original failure mode.

  4. Do not use stateless_http=True with any tool that calls ctx.sample() or elicitation. Issue #1156 remains open with no confirmed fix — the mode structurally disables sampling.

  5. Test mount() composition: Register middleware state on the parent, verify mounted child tools can read it via ctx.get_state() (Issue #3397). Register a {?param} resource template on a mounted child and verify it resolves (Issue #3366).

  6. Check cold start: Run python -c "import fastmcp" — under 1 second confirms you have the lazy-loading fix from PR #3295. Over 2 seconds indicates an affected version.

  7. v2.x → v3.x migration: Audit all FastMCP() constructor invocations — 16 kwargs were removed in v3.0.0rc1 with no deprecation warning pathway. A TypeError at runtime confirms affected call sites. Weigh migration cost against CVE exposure in fastmcp < 3.0.0 (diskcache CVE-2025-69872, python-multipart CVE-2026-24486, protobuf CVE-2026-0994).

Falsification criterion: This finding would be disproved by a sustained 6-month period after the March 2026 patches with no new auth layer or serialization regressions in the from_openapi() path, combined with a formal conformance test suite added to the FastMCP CI pipeline covering all failure modes documented here.

Evidence

ToolVersionEvidenceResult
jlowin/fastmcp3.0.0–3.0.1source-reviewedMCP transport auth headers leaked to downstream OpenAPI APIs via from_openapi(); fixed in 3.0.2
jlowin/fastmcpv2.14.3 (pre-PR #3662)source-reviewedGET object params serialized as Python dict literals, not JSON; silent backend data corruption
jlowin/fastmcp3.0.2 (pre-PR #3295)source-reviewed4.3s cold start on stdio servers from eager auth/Redis/beartype imports
jlowin/fastmcp3.0.x (pre-March 2026)source-reviewedmount() ctx propagation failure and {?param} template resolution failure — both silent at registration
jlowin/fastmcpall 3.x as of March 2026source-reviewedstateless_http=True + ctx.sample() permanently hangs — no error, no timeout

Confidence: empirical — 5 environments reviewed.

Strongest case against: FastMCP ships at a significantly higher PR merge rate than the official SDK (see discussion #2557), which means bugs are also patched quickly. All four most severe issues documented here have been fixed in 3.0.2 and the March 2026 patches. Teams already on current releases face a materially different risk profile than the historical record suggests. The from_openapi() failures may reflect the complexity of the ingestion problem rather than a persistent quality deficit.

Open questions: Does the auth layer separation hold in FastMCP releases after April 2026? Has the stateless_http=True sampling hang been fixed or formally documented as unsupported? Do the March 2026 mount() fixes cover all composition topologies (3-level nesting, cross-provider state)?

Seen different? Contribute your evidence — share a repro or counter-example and we’ll review it against this finding. Reader evidence is what keeps these findings accurate.

theorydelta.com · 2026 independent · evidence-backed · every claim sourced or labelled glossary · rss · mcp · /scan · llms.txt