Skip to content

Commit ac6a957

Browse files
committed
Restore mcp.server.fastmcp as a deprecated import alias for MCPServer
`from mcp.server.fastmcp import FastMCP` (and the Context, Image, Audio, Icon names v1 exported alongside it) resolves again, to the v2 objects, and emits MCPDeprecationWarning at import. Only the package init is shimmed; the fastmcp submodule tree still raises ModuleNotFoundError. The alias is removed in v3. MCPServer's constructor now takes everything after `name` as keyword-only, matching the lowlevel Server. A v1 call that passed `instructions` positionally previously landed the text in the new `title` parameter silently; it now raises TypeError, which matters more once the old import path stops forcing users through the guide.
1 parent 45f2a88 commit ac6a957

5 files changed

Lines changed: 82 additions & 7 deletions

File tree

docs/migration.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Every section heading below names the API it affects, so searching this page for
1212

1313
| Change | First symptom | Section |
1414
|---|---|---|
15-
| `FastMCP` renamed to `MCPServer` | `ModuleNotFoundError: No module named 'mcp.server.fastmcp'` | [`FastMCP` renamed](#fastmcp-renamed-to-mcpserver) |
15+
| `FastMCP` renamed to `MCPServer` | `MCPDeprecationWarning: mcp.server.fastmcp is deprecated`, or `ModuleNotFoundError` for its submodules | [`FastMCP` renamed](#fastmcp-renamed-to-mcpserver) |
1616
| Fields renamed from camelCase to snake_case | `AttributeError: 'Tool' object has no attribute 'inputSchema'` | [snake_case fields](#field-names-changed-from-camelcase-to-snake_case) |
1717
| `mcp.types` moved to the `mcp-types` package | `ModuleNotFoundError: No module named 'mcp.types'` | [`mcp.types` moved](#mcptypes-moved-to-the-mcp-types-package) |
1818
| `McpError` renamed to `MCPError` | `ImportError: cannot import name 'McpError' from 'mcp'` | [`McpError` renamed](#mcperror-renamed-to-mcperror) |
@@ -552,6 +552,8 @@ mcp = MCPServer("Demo")
552552

553553
`Context` is the type annotation for the `ctx` parameter injected into tools, resources, and prompts (see [`get_context()` removed](#mcpserverget_context-removed) below). The `ctx.fastmcp` property is now `ctx.mcp_server`.
554554

555+
The old import path is not gone entirely: `from mcp.server.fastmcp import FastMCP` (and `Context`, `Image`, `Audio`, `Icon` — the names v1 exported there) still resolves, to the v2 objects, and emits an `MCPDeprecationWarning` at import. That is a bridge, not a compatibility layer: `FastMCP` is `MCPServer` under its old name, with every v2 change on this page in effect, and the warning names the ones that don't announce themselves. The path is removed in v3. Nothing beneath it is shimmed, so `mcp.server.fastmcp.server`, `mcp.server.fastmcp.prompts.base`, and the rest raise `ModuleNotFoundError`.
556+
555557
All submodules under `mcp.server.fastmcp.*` are now under `mcp.server.mcpserver.*` with the same structure. Common imports:
556558

557559
- `Image`, `Audio` — from `mcp.server.mcpserver` (or `.utilities.types`)
@@ -581,11 +583,13 @@ mcp = MCPServer() # serverInfo.name == "mcp-server"
581583

582584
If test suites assert on the initialize result, or anything keys configuration or allow-lists off `serverInfo.name`, pass a name explicitly: `MCPServer("FastMCP")` preserves the old value, though a real name for your server is better.
583585

584-
### `MCPServer` constructor: `title`, `description`, and `version` added to the positional parameters
586+
### `MCPServer` constructor: parameters after `name` are now keyword-only
585587

586-
The constructor's positional parameter order changed. v2 inserts `title` and `description` before `instructions`, and `version` after `icons`, so the order is now `name`, `title`, `description`, `instructions`, `website_url`, `icons`, `version`. In v1 the order was `name`, `instructions`, `website_url`, `icons`.
588+
As with the [lowlevel `Server`](#lowlevel-server-constructor-parameters-are-now-keyword-only), only `name` is positional. `title` and `description` were added to the constructor and `version` moved off the installed package (see below), which reshuffled the parameter order relative to v1's `name`, `instructions`, `website_url`, `icons`. Rather than let a v1 call that passed `instructions` positionally quietly land its text in `title`, v2 makes every parameter after `name` keyword-only, so that call raises instead:
587589

588-
A v1 call that passed `instructions` positionally still runs without error on v2, because both slots are `str | None`. The text silently lands in `title` instead: the server sends it as `serverInfo.title` and stops sending `instructions` in the initialize result, which clients feed to the model.
590+
```text
591+
TypeError: MCPServer.__init__() takes from 1 to 2 positional arguments but 3 were given
592+
```
589593

590594
**Before (v1):**
591595

@@ -604,8 +608,6 @@ from mcp.server.mcpserver import MCPServer
604608
mcp = MCPServer("Demo", instructions="You answer questions about the weather.")
605609
```
606610

607-
Keep `name` positional and pass everything else by keyword.
608-
609611
### Unversioned servers report an empty version
610612

611613
In v1, a server constructed without a `version` reported the installed `mcp`

scripts/docs/gen_ref_pages.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
# it from `src/` would emit the unimportable `mcp-types.mcp_types.*`.
3131
PACKAGES = (ROOT / "src" / "mcp", ROOT / "src" / "mcp-types" / "mcp_types")
3232

33+
# Deprecated import shims that warn on import and only re-export names whose
34+
# canonical documentation lives elsewhere. They get no API page of their own.
35+
DEPRECATED_MODULES = frozenset({"mcp.server.fastmcp"})
36+
3337
_KIND_SECTIONS = {
3438
griffe.Kind.MODULE: "Modules",
3539
griffe.Kind.CLASS: "Classes",
@@ -185,6 +189,8 @@ def generate() -> list[NavItem]:
185189
continue
186190

187191
ident = ".".join(parts)
192+
if ident in DEPRECATED_MODULES:
193+
continue
188194
documented.add(ident)
189195
stubs[API_DIR / doc_path] = _stub(parts[-1], f"::: {ident}")
190196
pages[ident] = API_DIR / doc_path

src/mcp/server/fastmcp/__init__.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Deprecated import path: `FastMCP` was renamed to `MCPServer` in v2.
2+
3+
This module keeps `from mcp.server.fastmcp import FastMCP` working so v1 code
4+
runs, but importing it emits an `MCPDeprecationWarning`. It is not a
5+
behaviour-preserving alias: v2 changed defaults and semantics beyond the name
6+
(the default server name, transport parameters moving off the constructor,
7+
sync handlers running on a worker thread). Read the migration guide before
8+
relying on it:
9+
10+
https://py.sdk.modelcontextprotocol.io/v2/migration/
11+
12+
Only this package init is shimmed. Submodules such as
13+
`mcp.server.fastmcp.server` or `mcp.server.fastmcp.prompts.base` no longer
14+
exist; their contents live under `mcp.server.mcpserver`. This module is removed
15+
in v3.
16+
"""
17+
18+
import warnings
19+
20+
from mcp.server.mcpserver import Audio, Context, Icon, Image
21+
from mcp.server.mcpserver import MCPServer as FastMCP
22+
from mcp.shared.exceptions import MCPDeprecationWarning
23+
24+
warnings.warn(
25+
"mcp.server.fastmcp is deprecated: FastMCP was renamed to MCPServer "
26+
"(from mcp.server.mcpserver import MCPServer). This is not just a rename; "
27+
"defaults and behaviour changed in v2, see the migration guide: "
28+
"https://py.sdk.modelcontextprotocol.io/v2/migration/. "
29+
"This import path will be removed in v3.",
30+
MCPDeprecationWarning,
31+
stacklevel=2,
32+
)
33+
34+
__all__ = ["FastMCP", "Context", "Image", "Audio", "Icon"]

src/mcp/server/mcpserver/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class MCPServer(Generic[LifespanResultT]):
148148
def __init__(
149149
self,
150150
name: str | None = None,
151+
*,
151152
title: str | None = None,
152153
description: str | None = None,
153154
instructions: str | None = None,
@@ -156,7 +157,6 @@ def __init__(
156157
version: str = "",
157158
auth_server_provider: OAuthAuthorizationServerProvider[Any, Any, Any] | None = None,
158159
token_verifier: TokenVerifier | None = None,
159-
*,
160160
tools: list[Tool] | None = None,
161161
resources: list[Resource] | None = None,
162162
extensions: Sequence[Extension] | None = None,

tests/server/test_fastmcp.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""The `mcp.server.fastmcp` import path is a deprecated alias for `mcp.server.mcpserver`."""
2+
3+
import importlib
4+
import sys
5+
from types import ModuleType
6+
7+
import pytest
8+
9+
from mcp import MCPDeprecationWarning
10+
from mcp.server.mcpserver import Audio, Context, Icon, Image, MCPServer
11+
12+
13+
def _import_fastmcp_fresh() -> ModuleType:
14+
# The warning fires on module execution, so drop any cached module first.
15+
sys.modules.pop("mcp.server.fastmcp", None)
16+
return importlib.import_module("mcp.server.fastmcp")
17+
18+
19+
def test_importing_fastmcp_warns_and_names_the_replacement():
20+
with pytest.warns(MCPDeprecationWarning, match="renamed to MCPServer"):
21+
_import_fastmcp_fresh()
22+
23+
24+
def test_fastmcp_reexports_the_v1_surface_as_the_v2_objects():
25+
with pytest.warns(MCPDeprecationWarning):
26+
fastmcp = _import_fastmcp_fresh()
27+
28+
assert fastmcp.__all__ == ["FastMCP", "Context", "Image", "Audio", "Icon"]
29+
assert fastmcp.FastMCP is MCPServer
30+
assert fastmcp.Context is Context
31+
assert fastmcp.Image is Image
32+
assert fastmcp.Audio is Audio
33+
assert fastmcp.Icon is Icon

0 commit comments

Comments
 (0)