Point imports of mcp.server.fastmcp at the migration guide (#3388)
This commit is contained in:
parent
4d6f87e8d2
commit
0921d94a74
4 changed files with 80 additions and 6 deletions
|
|
@ -17,7 +17,7 @@ Every section heading below names the API it affects, so searching this page for
|
||||||
|
|
||||||
| Change | First symptom | Section |
|
| Change | First symptom | Section |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `FastMCP` renamed to `MCPServer` | `ModuleNotFoundError: No module named 'mcp.server.fastmcp'` | [`FastMCP` renamed](#fastmcp-renamed-to-mcpserver) |
|
| `FastMCP` renamed to `MCPServer` | `ModuleNotFoundError: No module named 'mcp.server.fastmcp'` (newer 2.x releases follow it with a pointer to this guide) | [`FastMCP` renamed](#fastmcp-renamed-to-mcpserver) |
|
||||||
| 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) |
|
| 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) |
|
||||||
| `mcp.types` names removed | `ImportError: cannot import name 'Content' from 'mcp.types'` | [Removed types](#removed-type-aliases-and-classes) |
|
| `mcp.types` names removed | `ImportError: cannot import name 'Content' from 'mcp.types'` | [Removed types](#removed-type-aliases-and-classes) |
|
||||||
| `McpError` renamed to `MCPError` | `ImportError: cannot import name 'McpError' from 'mcp'` | [`McpError` renamed](#mcperror-renamed-to-mcperror) |
|
| `McpError` renamed to `MCPError` | `ImportError: cannot import name 'McpError' from 'mcp'` | [`McpError` renamed](#mcperror-renamed-to-mcperror) |
|
||||||
|
|
@ -672,6 +672,8 @@ All submodules under `mcp.server.fastmcp.*` are now under `mcp.server.mcpserver.
|
||||||
- `ToolError`, `ResourceError` — from `mcp.server.mcpserver.exceptions`
|
- `ToolError`, `ResourceError` — from `mcp.server.mcpserver.exceptions`
|
||||||
- `MCPServerError` (renamed from `FastMCPError`) — from `mcp.server.mcpserver.exceptions`
|
- `MCPServerError` (renamed from `FastMCPError`) — from `mcp.server.mcpserver.exceptions`
|
||||||
|
|
||||||
|
Importing `mcp.server.fastmcp`, or anything below it, raises `ModuleNotFoundError` (newer 2.x releases include a link to this section in its message), so existing `except ImportError` or `except ModuleNotFoundError` fallbacks around the v1 import keep working.
|
||||||
|
|
||||||
### What is unchanged on `MCPServer`
|
### What is unchanged on `MCPServer`
|
||||||
|
|
||||||
Beyond the changes covered in this section, the everyday `FastMCP` surface carries over to `MCPServer` as-is:
|
Beyond the changes covered in this section, the everyday `FastMCP` surface carries over to `MCPServer` as-is:
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,12 @@ API_DIR = ROOT / "docs" / "api"
|
||||||
# it from `src/` would emit the unimportable `mcp-types.mcp_types.*`.
|
# it from `src/` would emit the unimportable `mcp-types.mcp_types.*`.
|
||||||
PACKAGES = (ROOT / "src" / "mcp", ROOT / "src" / "mcp-types" / "mcp_types")
|
PACKAGES = (ROOT / "src" / "mcp", ROOT / "src" / "mcp-types" / "mcp_types")
|
||||||
|
|
||||||
# Alias packages that mirror another package's namespaces (`mcp.types` mirrors
|
# Module paths that get no page, and neither does anything under them: alias
|
||||||
# `mcp_types`, `mcp.types.version` mirrors `mcp_types.version`): the mirrored
|
# packages that mirror another package's namespaces (`mcp.types` mirrors
|
||||||
# package's pages are the canonical rendering, so an alias, and every module
|
# `mcp_types`), whose canonical rendering is the mirrored package's pages; and
|
||||||
# under it, earns no page of its own.
|
# removed v1 import paths (`mcp.server.fastmcp`) that only raise a pointer to
|
||||||
EXCLUDED = frozenset({"mcp.types"})
|
# the migration guide and carry no API.
|
||||||
|
EXCLUDED = frozenset({"mcp.types", "mcp.server.fastmcp"})
|
||||||
|
|
||||||
_KIND_SECTIONS = {
|
_KIND_SECTIONS = {
|
||||||
griffe.Kind.MODULE: "Modules",
|
griffe.Kind.MODULE: "Modules",
|
||||||
|
|
|
||||||
16
src/mcp/server/fastmcp.py
Normal file
16
src/mcp/server/fastmcp.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
"""Removed in mcp 2: `FastMCP` is now `mcp.server.mcpserver.MCPServer`.
|
||||||
|
|
||||||
|
This module has no API. Importing it, or anything below it, raises
|
||||||
|
`ModuleNotFoundError` with a message that points at the migration guide. It
|
||||||
|
exists only because the bare "No module named 'mcp.server.fastmcp'" gave v1
|
||||||
|
code no hint that the installed SDK is a different major version.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_MESSAGE = (
|
||||||
|
"No module named 'mcp.server.fastmcp'. This is mcp 2.x, where FastMCP was renamed to MCPServer "
|
||||||
|
"(from mcp.server.mcpserver import MCPServer) and other APIs changed; see the migration guide at "
|
||||||
|
"https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver "
|
||||||
|
"or pin 'mcp<2' to keep running v1 code."
|
||||||
|
)
|
||||||
|
|
||||||
|
raise ModuleNotFoundError(_MESSAGE, name=__name__)
|
||||||
55
tests/server/test_fastmcp.py
Normal file
55
tests/server/test_fastmcp.py
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
"""The removed v1 import path `mcp.server.fastmcp` fails with a pointer to the migration guide."""
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from inline_snapshot import snapshot
|
||||||
|
|
||||||
|
import mcp.server
|
||||||
|
from mcp.server.mcpserver import MCPServer
|
||||||
|
|
||||||
|
|
||||||
|
def test_importing_fastmcp_raises_module_not_found_that_points_at_the_migration_guide() -> None:
|
||||||
|
"""SDK-defined: the v1 path fails with the same exception type and `.name` as a module
|
||||||
|
that genuinely does not exist, but the message names the replacement and the guide."""
|
||||||
|
with pytest.raises(ModuleNotFoundError) as exc_info:
|
||||||
|
importlib.import_module("mcp.server.fastmcp")
|
||||||
|
|
||||||
|
assert exc_info.value.name == "mcp.server.fastmcp"
|
||||||
|
assert str(exc_info.value) == snapshot(
|
||||||
|
"No module named 'mcp.server.fastmcp'. This is mcp 2.x, where FastMCP was renamed to MCPServer "
|
||||||
|
"(from mcp.server.mcpserver import MCPServer) and other APIs changed; see the migration guide at "
|
||||||
|
"https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver "
|
||||||
|
"or pin 'mcp<2' to keep running v1 code."
|
||||||
|
)
|
||||||
|
# A module that raises while executing is never cached, so nothing is left behind.
|
||||||
|
assert "mcp.server.fastmcp" not in sys.modules
|
||||||
|
assert not hasattr(mcp.server, "fastmcp")
|
||||||
|
|
||||||
|
|
||||||
|
def test_importing_a_fastmcp_submodule_raises_the_parent_pointer() -> None:
|
||||||
|
"""SDK-defined: a deep v1 path executes `mcp.server.fastmcp` first, so it fails with that
|
||||||
|
module's message and `.name` rather than a bare error for the leaf."""
|
||||||
|
with pytest.raises(ModuleNotFoundError) as parent:
|
||||||
|
importlib.import_module("mcp.server.fastmcp")
|
||||||
|
with pytest.raises(ModuleNotFoundError) as exc_info:
|
||||||
|
importlib.import_module("mcp.server.fastmcp.utilities.types")
|
||||||
|
|
||||||
|
assert exc_info.value.name == "mcp.server.fastmcp"
|
||||||
|
assert str(exc_info.value) == str(parent.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_v1_first_import_shim_falls_back_to_mcpserver() -> None:
|
||||||
|
"""SDK-defined: projects that support both majors try the v1 import and fall back on
|
||||||
|
`ModuleNotFoundError` (the narrowest guard seen in the wild), which is why the pointer is
|
||||||
|
raised as exactly that type and not as a bare `ImportError` or after a warning."""
|
||||||
|
fell_back = False
|
||||||
|
try:
|
||||||
|
server_class: type = importlib.import_module("mcp.server.fastmcp").FastMCP
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
fell_back = True
|
||||||
|
server_class = MCPServer
|
||||||
|
|
||||||
|
assert fell_back
|
||||||
|
assert server_class is MCPServer
|
||||||
Loading…
Reference in a new issue