Going all the way to FastMCP 4? You need this page and Upgrading from FastMCP 3, in that order. The two describe different transitions: this one covers the v3 API changes, while the FastMCP 3 guide covers the MCP Python SDK v2 rebuild underneath v4. Where a v3 deprecation was later removed outright, this page marks it Removed in v4.
v3.0.0
For most servers, upgrading to v3 is straightforward. The breaking changes below affect deprecated constructor kwargs, sync-to-async shifts, a few renamed methods, and some less commonly used features.Install
Since you already havefastmcp installed, you need to explicitly request the new version — pip install fastmcp won’t upgrade an existing installation:
pyproject.toml, update your pin to fastmcp>=3.0.0,<4. Going on to FastMCP 4 is a second hop: finish this page, then work through Upgrading from FastMCP 3 and move the pin to fastmcp>=4.0.0 at the end of it.
New repository home. As part of the v3 release, FastMCP’s GitHub repository has moved from If you reference the repository URL in dependency specifications (e.g.,
jlowin/fastmcp to PrefectHQ/fastmcp under Prefect’s stewardship. GitHub automatically redirects existing clones and bookmarks, so nothing breaks — but you can update your local remote whenever convenient:git+https://github.com/jlowin/fastmcp.git), update those to the new location.Copy this prompt into any LLM along with your server code to get automated upgrade guidance.
Breaking Changes
Transport and server settings removed from constructor In v2, you could configure transport settings directly in theFastMCP() constructor. In v3, FastMCP() is purely about your server’s identity and behavior — transport configuration happens when you actually start serving. Passing any of the old kwargs now raises TypeError with a migration hint.
host,port,log_level,debug,sse_path,streamable_http_path,json_response,stateless_http— pass torun(),run_http_async(), orhttp_app(), or set via environment variables (e.g.FASTMCP_HOST)message_path— set via environment variableFASTMCP_MESSAGE_PATHonly (not arun()kwarg)on_duplicate_tools,on_duplicate_resources,on_duplicate_prompts— consolidated into a singleon_duplicate=parametertool_serializer— returnToolResultfrom your tools insteadinclude_tags/exclude_tags— useserver.enable(tags=..., only=True)/server.disable(tags=...)after constructiontool_transformations— useserver.add_transform(ToolTransform(...))after construction
DiskStore to FileTreeStore to address a pickle deserialization vulnerability in diskcache (CVE-2025-69872).
If you were using the default storage (i.e., not passing an explicit client_storage), clients will need to re-register on their first connection after upgrading. This happens automatically — no user action required, and it’s the same flow that already occurs whenever a server restarts with in-memory storage.
If you were passing a DiskStore explicitly, you can either switch to FileTreeStore (recommended) or keep using DiskStore by adding the dependency yourself.
Component enable()/disable() moved to server
In v2, you could enable or disable individual components by calling methods on the component object itself. In v3, visibility is controlled through the server (or provider), which lets you target components by name, tag, or type without needing a reference to the object:
.enable() or .disable() on a component object now raises NotImplementedError. See Visibility for the full API, including tag-based filtering and per-session visibility.
Listing methods renamed and return lists
The get_tools(), get_resources(), get_prompts(), and get_resource_templates() methods have been renamed to list_tools(), list_resources(), list_prompts(), and list_resource_templates(). More importantly, they now return lists instead of dicts — so code that indexes by name needs to change:
Message class instead of mcp.types.PromptMessage. The new class is simpler — it accepts a plain string and defaults to role="user", so most prompts become one-liners:
role and content keys, those also need to change. v2 silently coerced dicts into prompt messages, but v3 requires typed Message objects (or plain strings for single user messages):
ctx.set_state() and ctx.get_state() are now async because state in v3 is session-scoped and backed by a pluggable storage backend (rather than a simple dict). This means state persists across multiple tool calls within the same session:
serializable=False — these values are request-scoped and only available during the current tool call:
FastMCP instance has its own state store. In v2 this wasn’t noticeable because mounted tools ran in the parent’s context, but in v3’s provider architecture each server is isolated. Non-serializable state (serializable=False) is request-scoped and automatically shared across mount boundaries. For serializable state, pass the same session_state_store to both servers:
GitHubProvider could auto-load configuration from environment variables with a FASTMCP_SERVER_AUTH_* prefix. This magic has been removed — pass values explicitly:
StreamableHttpTransport instead:
timeout parameter removed
OpenAPIProvider no longer accepts a timeout parameter. Configure timeout on the httpx2 client directly. The client parameter is also now optional — when omitted, a default client is created from the spec’s servers URL with a 30-second timeout:
meta dicts changed from _fastmcp to fastmcp. If you read metadata from tool or resource objects, update the key:
include_fastmcp_meta parameter has been removed from FastMCP() and to_mcp_tool(), so there is no way to suppress it.
Server banner environment variable renamed
FASTMCP_SHOW_CLI_BANNER is now FASTMCP_SHOW_SERVER_BANNER.
Decorators return functions
In v2, @mcp.tool transformed your function into a FunctionTool object. In v3, decorators return your original function unchanged — which means decorated functions stay callable for testing, reuse, and composition:
FunctionTool (e.g., accessing .name or .description), the v2-compatible object-returning behavior was available in v3 via FASTMCP_DECORATOR_MODE=object. That escape hatch was removed in FastMCP 4.0 — decorators always return the original function now.
Background tasks require optional dependency
FastMCP’s background task system is now behind an optional extra. If your server uses background tasks, install with:
task=True or TaskConfig will raise an import error at runtime. See Background Tasks for details.
Deprecated Features
These were deprecated in v3. Items marked Removed in v4 no longer work at all — update to the replacement shown. The rest still work but emit warnings; update when convenient. mount() prefix → namespace (Removed in v4)providers to reflect v3’s provider-based architecture. The old fastmcp.server.proxy and fastmcp.server.openapi compatibility shims were removed in 4.0 — import from the providers location instead:
FastMCPOpenAPI was removed in 4.0 — use FastMCP with an OpenAPIProvider instead:
backend= to target=.
v2.14.0
OpenAPI Parser Promotion
The experimental OpenAPI parser is now standard. Thefastmcp.experimental.server.openapi and fastmcp.server.openapi shims were both removed in 4.0 — use FastMCP with an OpenAPIProvider instead:
Removed Deprecated Features
A batch of long-deprecated surfaces came out in 2.14. Each fails loudly at import or call time, and each has a direct replacement:
Two of these are worth understanding rather than just swapping.
FastMCPProxy takes a factory instead of a client because a single shared client cannot serve concurrent proxied sessions safely — the factory gives each session its own backend connection. And output_schema=False became output_schema=None because False read as “this tool has a schema, and it is false”; None says plainly that there is no schema.

