Skip to content

FastMCP 3.0.2 eagerly imports heavy unused deps (~4.3s overhead for simple stdio servers) #3292

@theflysurfer

Description

@theflysurfer

Description

Summary
from fastmcp import FastMCP in v3.0.2 takes 2.5–5.5 seconds even for simple stdio tool servers that use no auth, no Redis, no task scheduling, and no runtime type checking. The overhead comes from eager imports of heavy transitive dependencies that are never needed at runtime.

This is different from #2205 (which focused on mcp.types). The MCP SDK has since fixed their lazy-loading (#1508). The remaining bottleneck is FastMCP's own dependency chain.

Environment

  • FastMCP 3.0.2 / MCP SDK 1.26.0
  • Python 3.13.9, Windows 11
  • MetaMcp: HTTP multiplexer proxying 19 MCP backends via create_proxy()

Impact
We proxy 19 backends via create_proxy(). Each stdio backend spawns a Python process that imports FastMCP. Total cold-start cost across all backends: 100+ seconds. This delays tool availability for clients after a restart.

Profiling Data

Profiled with python -X importtime on 3 real-world servers:

Backend Total import FastMCP share Own code
word-mcp (115 tools, COM automation) 2.6s 2.4s (92%) 0.2s
claude-code-admin (124 tools) 5.0s 4.3s (86%) 0.7s
google-workspace (138 tools, Google APIs) 9.3s 5.6s (60%) 1.2s

Breakdown: What FastMCP imports eagerly but never uses

Module Time Loaded via Used by these servers?
beartype (runtime type checking) ~520ms docket → dependency injection No
docket + key_value.aio + redis ~550ms fastmcp.server.dependencies No (no Redis, no task queue)
authlib + cryptography (OAuth/JWT) ~1,100ms fastmcp.server.auth.oauth_proxy No (stdio servers, no OAuth)
mcp.client.session ~1,400ms FastMCP internal imports No (these are servers, not clients)
httpx ~800ms Auth proxy, client transports No (stdio transport only)

Total avoidable overhead: ~4.3 seconds for a simple FastMCP("my-server") + @mcp.tool() server.

Self-time leaders

Module Self-time What it does
mcp.types 150–320ms Pydantic model compilation (already addressed in MCP SDK)
beartype._check.code._pep... ~49ms PEP 484/585 type-check codegen
key_value.aio.stores.base ~35ms Abstract key-value store
key_value.aio.stores.redis.store ~29ms Redis adapter (never used)
fastmcp.server.providers.skills.skill_provider ~89ms Skill provider class defs

Suggested fix

Lazy-import the following behind their actual use sites:

  1. Auth stack (fastmcp.server.auth.oauth_proxy, authlib, cryptography, httpx) → only load when OAuth is configured. Saves ~1.1s
  2. docket + key_value + redis → only load when storage backend is configured or dependency injection is used. Saves ~550ms
  3. beartype → only load when runtime type checking is actually enabled. Saves ~520ms
  4. mcp.client.session → only load in proxy/client contexts, not for pure server usage. Saves ~1.4s

This would bring import fastmcp from ~2.5s down to ~0.3–0.5s for the common case of a simple stdio tool server.

Example Code

# This alone costs 2.5s+ even though no auth, Redis, or beartype is needed:
from fastmcp import FastMCP

mcp = FastMCP("my-simple-tool-server")

@mcp.tool()
def hello(name: str) -> str:
    return f"Hello {name}"

Version Information

FastMCP version: 3.0.2
MCP version: 1.26.0
Python version: 3.13.9
Platform: Windows-11-10.0.26200-SP0

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementImprovement to existing functionality. For issues and smaller PR improvements.high-prioritypotential-duplicateBot-suggested duplicate awaiting human review. Auto-closes after 3 days if unchallenged.serverRelated to FastMCP server implementation or server-side functionality.v3Targeted for FastMCP 3

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions