docs/getting-started/upgrading/from-mcp-sdk.mdx
If your server starts with from mcp.server.fastmcp import FastMCP, you're using FastMCP 1.0 — the version bundled with v1 of the mcp package. Upgrading to the standalone FastMCP framework is easy. For most servers, it's a single import change.
# Before
from mcp.server.fastmcp import FastMCP
# After
from fastmcp import FastMCP
That's it. Your @mcp.tool, @mcp.resource, and @mcp.prompt decorators, your mcp.run() call, and the rest of your server code all work as-is.
pip install --upgrade fastmcp
# or
uv add fastmcp
FastMCP includes the mcp package as a dependency, so you don't lose access to anything. Update your import, run your server, and if your tools work, you're done.
STEP 1 — IMPORT (required for all servers): Change "from mcp.server.fastmcp import FastMCP" to "from fastmcp import FastMCP".
STEP 2 — CONSTRUCTOR KWARGS (only if FastMCP() receives transport settings):
FastMCP() no longer accepts: host, port, log_level, debug, sse_path, streamable_http_path, json_response, stateless_http.
Fix: pass these to run() instead.
Before: mcp = FastMCP("server", host="0.0.0.0", port=8080); mcp.run()
After: mcp = FastMCP("server"); mcp.run(transport="http", host="0.0.0.0", port=8080)
STEP 3 — PROMPTS (only if using PromptMessage directly or returning dicts):
mcp.types.PromptMessage is replaced by fastmcp.prompts.Message.
Before: PromptMessage(role="user", content=TextContent(type="text", text="Hello"))
After: Message("Hello") — role defaults to "user", accepts plain strings.
Also: if prompts return raw dicts like {"role": "user", "content": "..."}, these must become Message objects or plain strings.
The MCP SDK's FastMCP 1.0 silently coerced dicts; standalone FastMCP requires typed returns.
STEP 4 — OTHER MCP IMPORTS (only if importing from mcp.* directly):
Direct imports from the mcp package (e.g., import mcp.types, from mcp.server.stdio import stdio_server) still work because FastMCP includes mcp as a dependency. However, prefer FastMCP's own APIs where equivalents exist:
STEP 5 — DECORATORS (only if treating decorated functions as objects): @mcp.tool, @mcp.resource, @mcp.prompt now return the original function, not a component object. Code that accesses .name or .description on the decorated result needs updating. Set FASTMCP_DECORATOR_MODE=object temporarily to restore v1 behavior (this compat setting is itself deprecated).
For each issue found, show the original line, explain what changed, and provide the corrected code. </Prompt>
Most servers need nothing beyond the import change. Skim the sections below to see if any apply.
If you passed transport settings like host or port directly to FastMCP(), those now belong on run(). This keeps your server definition independent of how it's deployed:
# Before
mcp = FastMCP("my-server", host="0.0.0.0", port=8080)
mcp.run()
# After
mcp = FastMCP("my-server")
mcp.run(transport="http", host="0.0.0.0", port=8080)
If you pass the old kwargs, you'll get a clear TypeError with a migration hint.
If your prompt functions return mcp.types.PromptMessage objects or raw dicts with role/content keys, you'll need to upgrade to FastMCP's Message class. Or just return a plain string — it's automatically wrapped as a user message. The MCP SDK's bundled FastMCP 1.0 silently coerced dicts into messages; standalone FastMCP requires typed Message objects or strings.
from fastmcp import FastMCP
mcp = FastMCP("prompts")
@mcp.prompt
def review(code: str) -> str:
"""Review code for issues"""
return f"Please review this code:\n\n{code}"
For multi-turn prompts:
from fastmcp.prompts import Message
@mcp.prompt
def debug(error: str) -> list[Message]:
"""Start a debugging session"""
return [
Message(f"I'm seeing this error:\n\n{error}"),
Message("I'll help debug that. Can you share the relevant code?", role="assistant"),
]
mcp.* ImportsIf your server imports directly from the mcp package — like import mcp.types or from mcp.server.stdio import stdio_server — those still work. FastMCP includes mcp as a dependency, so nothing breaks.
Where FastMCP provides its own API for the same thing, it's worth switching over:
| mcp Package | FastMCP Equivalent |
|---|---|
mcp.types.TextContent(type="text", text=str(x)) | Just return x from your tool |
mcp.types.ImageContent(...) | from fastmcp.utilities.types import Image |
mcp.types.PromptMessage(...) | from fastmcp.prompts import Message |
from mcp.server.stdio import stdio_server | Not needed — mcp.run() handles transport |
For anything without a FastMCP equivalent (e.g., specific protocol types you use directly), the mcp.* import is fine to keep.
In FastMCP 1.0, @mcp.tool returned a FunctionTool object. Now decorators return your original function unchanged — so decorated functions stay callable for testing, reuse, and composition:
@mcp.tool
def greet(name: str) -> str:
"""Greet someone"""
return f"Hello, {name}!"
# This works now — the function is still a regular function
assert greet("World") == "Hello, World!"
If you have code that accesses .name, .description, or other attributes on the decorated result, that will need updating. This is uncommon — most servers don't interact with the tool object directly. If you need the old behavior temporarily, set FASTMCP_DECORATOR_MODE=object to restore it (this compatibility setting is itself deprecated and will be removed in a future release).
# Install
pip install --upgrade fastmcp
# Check version
fastmcp version
# Run your server
python my_server.py
You can also inspect your server's registered components with the FastMCP CLI:
fastmcp inspect my_server.py
The MCP ecosystem is evolving fast. Part of FastMCP's job is to absorb that complexity on your behalf — as the protocol and its tooling grow, we do the work so your server code doesn't have to change.