· via dev.to (home feed)
MCP SDK 2.x and Gemini Interactions API changes break unpinned Python MCP servers
A dev.to walkthrough shows how unversioned mcp and google-genai dependencies broke a Nano Banana 2 Lite MCP server, and how pinning both majors plus small code changes fixed it.

What broke
A dev.to write-up documents how a Python MCP server that drives Google's Nano Banana 2 Lite — the nickname for Gemini 3.1 Flash-Lite Image, Google's low-latency image generation and editing model — stopped working on fresh installs even though nothing in the repository had changed. The culprit was two unbounded dependency lines: a requirements.txt listing mcp and google-genai with no version bounds, both of which resolved to new major versions after the original article was published in July.
The September follow-up walks through the migration and then registers the updated server with three agent clients — Claude Code, Codex and Antigravity CLI — and validates it end to end against the live API.
The Interactions API schema change
The larger of the two breaks came from Google's side. The server calls interactions.create with store=True, and under google-genai 1.75.0 the API answers with a 400 error stating that the legacy Interactions API schema is no longer supported and instructing the user to upgrade to google-genai 2.0.0 or newer, with a pointer to migration notes.
According to the author, that error message deserves credit for naming the fix — but inside an MCP server it is nearly invisible. Each tool catches the exception and returns it as a string, so the agent surfaces a generic image-generation-failed message with the SDK version number buried in the text.
In google-genai 2.x the response follows a new schema in which the model's output arrives as a list of steps, with the generated image exposed as a convenience property, interaction.output_image, carrying data and mime type. Because server.py already read output_image defensively, upgrading the SDK was the entire fix: no tool function changed. The author notes that code which walks the legacy output fields by hand is the part the migration notes cover.
The MCP 2.x rename
The MCP-side migration was smaller. The import moves from mcp.server.fastmcp.FastMCP to mcp.server.mcpserver.MCPServer, and the server object is constructed with the new name. The @mcp.tool() decorator and mcp.run() stay as they are, as do all tool bodies.
Two 2.x details surfaced in the repository. First, list_tools() is now async on MCPServer, so the test changed from reaching into a private _tool_manager attribute to calling the public asyncio.run(mcp.list_tools()). Second, an unversioned 2.x server reports an empty string in the handshake, which shows up in the protocol test.
Why mocked tests missed the break
The unit tests kept passing the whole time the server was broken, because they mock the client factory — the SDK never builds a real response and the API is never called. The fix was a test that constructs a real steps-schema Interaction through the SDK's own model validation and runs it through the response handler. On google-genai 1.x that import does not exist, so the test fails loudly instead of the API failing quietly. A separate verify-live skill covers the remaining gap against the real endpoint.
Pinning both majors
Both breaks originated in unbounded requirements, so both lines now carry a floor and a ceiling: google-genai>=2,<3 and mcp>=2,<3. The floor documents what the code needs; the ceiling means the next major version arrives on purpose rather than through a routine install. A fresh setup reported mcp 2.2.0 and google-genai 2.22.0.
The update also grows the tool surface from four tools to five, adding edit_local_image_with_style. The server still leans on the Interactions API's session model: every call is stored server-side and returns an interaction ID, which is passed back as previous_interaction_id so the model edits the image it already produced instead of redrawing from a fresh prompt.
Why it matters
This is one small repository, but the failure pattern is general. Two major versions landed silently under a project that worked perfectly when it was published, and nothing local flagged it: mocked tests stayed green while every live call failed, and the agent client reduced a descriptive API error to a generic failure string. The repair was cheap — an import rename, one defensive accessor that happened to be forward-compatible, and two pinned dependency lines — but finding it meant reading an error the MCP layer worked hard to hide. For anyone maintaining MCP servers built from older tutorials, the practical takeaways are to pin major versions, keep at least one test that exercises real SDK types rather than mocks, and expect that 1.x-era FastMCP examples now fail on fresh installs.
- #mcp
- #python
- #gemini
- #breaking-changes
- #dependency-management