-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Point imports of mcp.server.fastmcp at the migration guide #3388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+80
−6
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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__) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟣 Pre-existing: the migration-pointer tombstone covers only the
mcp.server.fastmcpmodule path, but v1 also re-exported the class from the package itself (v1'smcp/server/__init__.pyhadfrom .fastmcp import FastMCP), so the equally common v1 spellingfrom mcp.server import FastMCPstill fails with the bareImportError: cannot import name 'FastMCP' from 'mcp.server'and never sees the new pointer this PR adds. A module-level__getattr__insrc/mcp/server/__init__.pyraising the same guidance forFastMCP(mirroring the_MESSAGEin src/mcp/server/fastmcp.py) would close the gap; docs/migration.md line 675 and the line-20 symptom row also only describe the ModuleNotFoundError path.Extended reasoning...
A v1 user whose server does
from mcp.server import FastMCP(a valid, exported v1 import path) upgrades to a 2.x release containing this change. Instead of the improved message pointing at MCPServer and the migration guide, they still get the uninformativeImportError: cannot import name 'FastMCP' from 'mcp.server'— exactly the confusing experience this PR was written to eliminate — because the tombstone only intercepts imports of themcp.server.fastmcpmodule, not theFastMCPattribute ofmcp.server.Verification: pre-existing — src/mcp/server/init.py defines no
FastMCPand no module-level__getattr__(its imports are only CacheHint, ServerRequestContext, NotificationOptions, Server, MCPServer, InitializationOptions), sofrom mcp.server import FastMCP— a valid v1 spelling, since v1'smcp/server/__init__.pyre-exported FastMCP viafrom .fastmcp import FastMCPand listed it in__all__— raise