Repository navigation
docs: no guidance for supporting SDK 1.x and 2.x at the same time #3309
Description
Activity
Your shim + pin setup is basically the standard dual-support pattern and it's solid — the CI job force-installing 1.x is a nice touch. One gap to keep in mind: it only covers the FastMCP-level surface, so anything else that moved between majors (client config, streamable http, low-level server bits) still breaks fresh installs on 2.0.0. For placement I'd go a separate compat page linked from migration.md rather than stuffing it into a doc that keeps getting trimmed — a one-way migration guide plus a running compat note reads cleaner.
Thanks, that matches my read. A separate compat page linked from
migration.mdkeeps the migration guide one-way and trimmed, so I would scope it that way: a shortdocs/compatibility.mdwith the shim, the pin guidance, and the CI job.Good point on surface coverage. The shim only protects FastMCP-level code, so the page should say that plainly and list the other import moves (client config, streamable HTTP, low-level server) with pointers to their migration entries rather than pretending one shim covers everything.
I will hold off on the PR until a maintainer weighs in on whether they want the page at all.
Hey! Yea unfortunately that's the state of the Python ecosystem, it's pretty common to not have a version cap and it results in breakages when a new major version releases.
As for adding backwards compat shims I decided against doing that for the v2 SDK to avoid having to essentially support two SDK versions in a single SDK. It would have been near double the number of public interfaces in some cases and very gross/hacky to get working.
The best option for those wanting to support both is yes writing shims yourself and trying to import one or the other. This is what the Anthropic SDK for example: anthropics/anthropic-sdk-python@8b327c3
Thanks for the clarification. I'd be interested in contributing the documentation for this use case.
Based on the discussion, my proposed approach would be:
- Add a small
docs/compatibility.mdpage for package authors supporting both SDK 1.x and 2.x during a transition. - Document the explicit import shim pattern rather than adding backward-compatibility shims to the SDK itself.
- Clearly scope the guidance to the FastMCP-level API surface and link to the migration guide for other breaking changes.
- Include dependency and CI testing guidance.
I'll prepare the documentation locally, but before opening a PR I'd appreciate maintainer confirmation that this documentation page is something the project wants to include and where it should live in the docs navigation.
- Add a small
@maxisbey Thanks, that settles the approach, and the anthropic-sdk-python commit is a better precedent than anything I had.
Since the SDK will not carry shims itself, I went ahead and wrote the page on a branch so there is something concrete to evaluate: main...haiiibin:docs-dual-version-support. One new
docs/compatibility.md(~60 lines), a nav entry, and one sentence linking it from the migration guide's "Not ready to migrate yet?" note. It covers:- the import shim, and a warning about the constructor's positional trap (
FastMCP("name", "instructions...")setsinstructionson v1 but silently setstitleon v2) - why both bounds of
mcp>=1.2.0,<3are deliberate - a CI job that forces the v1 line so the fallback path stays tested instead of becoming dead code
- an explicit scope note that the shim only covers the FastMCP rename, deferring everything else to the migration guide
- when and how to retire the v1 path
Everything on the page is lifted from two registry-listed servers that have run this pattern in production since late July, with both SDK lines green in CI.
The contribution policy asks for the linked issue to be assigned before a PR from outside the team, so if you want this page: assign this issue to me and I will open the PR right away. @pragati243 you offered to help here as well, so review on the PR would be very welcome once it is up, and if you spot gaps I am glad to fold in additions.
- the import shim, and a warning about the constructor's positional trap (
Thanks for putting together a concrete implementation. I’d be happy to review the PR once it’s open and test the examples against both SDK versions. I’ll take a close look at the compatibility scope and the v1/v2 behavior, and I’ll share any concrete gaps or findings.
Reacted by Allen Yu- addedv1Affects the v1.x maintenance lineAffects the v1.x maintenance linev2Affects the v2 line (2.x on main)Affects the v2 line (2.x on main)and removedv1Affects the v1.x maintenance lineAffects the v1.x maintenance line
on Aug 18, 2026 Numbers for what you described. On 2026-09-11 I took a seeded random sample of 180 PyPI servers out of the 3,497 stdio PyPI packages listed in the official MCP registry, installed each one into a clean venv with
uv pip install name==version(the version the registry lists, Python 3.13, nothing pinned by me), started the console script and sentinitialize.175 installed. 53 died at import with the 2.x message,
No module named 'mcp.server.fastmcp'. Of the other 122, 65 completed the handshake and 57 failed for other reasons, judging from stderr: other exceptions at startup, a usage banner because the registry entry omits a subcommand, a missing module, a credential check. That is 30% of the cells, but it is not 30% of the ecosystem. 21 of the 53 belong to one publisher, io.github.CSOAI-ORG, which has 353 PyPI servers in the registry; all 21 I sampled failed the same way. Counting publishers instead of packages, 34 of 143 had at least one broken server, 23.8%. The cluster-robust 95% interval for the per-package rate is 15.9 to 44.7%, design effect 4.5. So between a fifth and a third of registry-listed PyPI servers don't start on a fresh install, 45 days after 2.0.0.The registry shows all of them as
status: active. That is the default value at publish time. The registry doesn't claim they run.What I don't know: whether these servers work under
mcp<2(I only ran fresh installs, which resolve to 2.x), how many of the 175 pinmcpat all, and whether the authors have noticed. On the npm side of the same sample I didn't see a comparable pattern, five module errors with different causes.The per-package list is 53 lines and mostly one publisher; if it's useful here I'll add it.
- added a commit that references this issue
on Sep 14, 2026 @nortesoftware thank you, that turns an anecdote into a measurement. A fifth to a third of registry-listed PyPI servers failing a fresh install 45 days after 2.0.0, with a cluster-robust interval, is a much better opening line for this page than my two packages were.
Two updates since the last round:
- Point imports of mcp.server.fastmcp at the migration guide #3388 landed, so the old import path now explains itself instead of looking like a broken install. That helps the person reading the traceback, but the process still dies, and a publisher cannot tell every downstream user to pin
mcp<2. The missing piece is still a page telling package authors how to carry both majors during the transition. - I refreshed the branch onto current
main(after Point imports of mcp.server.fastmcp at the migration guide #3388) and added one paragraph citing the sample above and Point imports of mcp.server.fastmcp at the migration guide #3388: main...haiiibin:docs-dual-version-support. Still one new page, one nav entry, one sentence in the migration guide.
@maxisbey the contribution policy needs this issue assigned before I can open the PR. If you want the page, assign it to me and it is up within the hour; if you would rather not carry it, say so and I will close this out. Either answer is fine, I just do not want to leave it ambiguous.
- Point imports of mcp.server.fastmcp at the migration guide #3388 landed, so the old import path now explains itself instead of looking like a broken install. That helps the person reading the traceback, but the process still dies, and a publisher cannot tell every downstream user to pin
Follow-up on the "how many pin
mcpat all" part, plus one correction to my comment above.I read the
Requires-Distof the same 175 packages from PyPI, no reinstall. 119 declaremcpdirectly. 71 of those give a floor and no ceiling (>=1.0.0,>=1.2,>=1.28.0and so on). Not one of the 71 started: 51 hit the FastMCP import error, 20 failed for other reasons. 26 bound it below 2 (<2, one==1.x); 22 of them started and none hit the error. 17 already require 2.x, 5 declaremcpwith no constraint at all and started fine on 2.x, and 56 don't depend onmcpdirectly (24 go throughfastmcp). So 15% of the installed servers pinned below 2. The whole failure sits in the 41% of installed servers that set a floor and forgot the ceiling, which is the situation your issue describes.The correction: I wrote that 21 of the 53 failures came from one publisher and that all 21 failed the same way. Going cell by cell for this, it is 19 of the 53. That publisher had 21 packages in my sample and none of them started, but two died with different errors. The per-publisher count (34 of 143) and the interval don't change, they were computed on the per-cell flag. Without that publisher the rate is 34 of 154, 22.1%, not the 20.8% I had.
@nortesoftware the pin breakdown is the part the page most needed: 71 floor-without-ceiling packages and none of them started, 26 capped below 2 and none of them hit the error. I added one sentence citing that under the
<3cap bullet, so the pin section now argues from the sample instead of from principle (diff). Noted the 19 of 53 correction; the page only cites the overall range, so nothing there changes.Corrections to my two comments above.
52 of the 175 died with the 2.x message, not 53. darwin-memo was counted because its error text names
mcp.server.fastmcp, but what it hit isNo module named 'mcp':mcpis an optional extra of that package and was not installed. The count is of packages whose error is the rename itself, not any import failure that mentionsmcp, and no other cell carries that message. That is 29.7% of the cells; of the other 123, 65 completed the handshake and 58 failed for other reasons.The rename is not all that 2.0 broke. Ten of those 58, all among the 71 that set a floor and no ceiling, stop at a
list_tools()decorator withAttributeError: 'Server' object has no attribute 'list_tools': 2.0 removed that decorator from the low-levelServer, which now takeson_list_tools=in its constructor. So at least 62 of 175, 35.4%, are broken by 2.0. I did not examine the other 48 PyPI failures for a 2.0 cause.The publisher key split io.github.CSOAI-ORG in two: 18 of its packages under its GitHub owner, 3 under its registry namespace. Counted as one publisher, 32 of 142 publishers had at least one server broken by the rename, 22.5%, and the cluster-robust 95% interval for the per-package rate is 14.1 to 45.3%, design effect 5.3. 19 of the 52 are that publisher's; without it the rate is 33 of 154, 21.4%. The range in my first comment, between a fifth and a third, is the rename alone.
13 packages require
mcp2.x, not 17. The other four declare>=1.x,<3, which accepts both majors, and all four started.51 of the 52 are among the 71 that set a floor and no ceiling, not all of them. The other one, vs-filesystem-mcp-server, gets
mcpthroughfastmcp.Sorry for the slow answer here, and thanks for making it easy by saying either answer works: it's a no. We won't be adding a dual-version page.
We don't want to encourage carrying both majors. 1.x is feature-frozen: it stops at the 2025-11-25 spec and only gets critical bug fixes and security fixes, while the 2026-07-28 spec and everything after it are 2.x only. A shim keeps a package running against an SDK that won't gain anything, and doubles what the package has to test. Our guidance for package authors is to move to 2.x and depend on
mcp>=2,<3. The migration guide lists every change, and since #3388 the old import error points straight at it.Thanks for the clear answer and the reasoning behind it. Pointing the old import error at the migration guide (#3388) fixes the install failures where they happen, which a page would not have. @nortesoftware, thanks for the sample and the corrections above; the
list_toolsremoval was the part I had not seen.- added 2 commits that reference this issue
on Oct 9, 2026
Problem
docs/migration.mdis a one-way guide: it tells you what to change once you move to 2.x. It has no guidance for the case where you cannot hard-cut, which is the situation of anyone maintaining a published MCP server or library while the ecosystem is split across both majors.Concretely: the day 2.0.0 shipped, fresh installs of our published servers started resolving
mcp==2.0.0and crashed at import (ModuleNotFoundError: No module named 'mcp.server.fastmcp'), while existing users were still on 1.x. The realistic fix for a package author in that window is not "migrate", it is "support both majors for a transition period". I could not find a recipe for that anywhere indocs/.What we ended up doing
Running in production since late July on two registry-listed servers (data-profiler-mcp, acb-tax-mcp):
together with:
mcp>=1.2.0,<3so installs may resolve either major, and"mcp>=1.2.0,<2"and re-runs the test suite, so the 1.x fallback path stays tested while the main matrix resolves 2.x.For code that stays on the FastMCP-level API surface (constructor,
@mcp.tool(),run()), this has been sufficient: both lines pass the same test suite unchanged.Proposal
A short section, roughly "Supporting 1.x and 2.x during the transition", covering:
mcp>=1.2.0,<3, and why an upper bound of<2alone strands your users),I would keep it to roughly 40 to 60 lines.
Scoping questions before I write anything
migration.mddown to genuine breaking changes, so this may not belong there. Would you rather see it as a short section inmigration.md, or as a separate small docs page (e.g.docs/compatibility.md)?If maintainers think it is worth having, I will send the PR.