Severity: high. Hard deadline: 2026-07-28.
What happens
The Python MCP SDK ships stable 2.0.0 on 2026-07-28, per the 2.0.0b2 release notes ("Stable v2 is still targeted for 2026-07-28 alongside the spec release, keep pinning an exact version"). mcp2cli 3.3.1 declares mcp>=1.0 with no upper bound. The moment 2.0.0 is stable, a fresh uvx mcp2cli resolves it and the streamable-http transport stops working.
Right now everything looks fine, because pre-releases are opt-in and uvx still resolves mcp 1.28.1. The break lands silently on the release date, on any machine whose uvx cache misses: a new clone, a CI runner, a teammate's first run.
Root cause
The v2 SDK removed the streamablehttp_client alias. Only streamable_http_client (with the underscore) survives. mcp2cli imports the old name at three sites in mcp2cli/__init__.py:
- L2555, L3244, L3550:
from mcp.client.streamable_http import streamablehttp_client
I confirmed the SDK side directly: 1.28.1 exports both streamable_http_client and the streamablehttp_client alias; 2.0.0b2 exports only streamable_http_client.
Reproduction
Against a live streamable-http server, macOS, mcp2cli 3.3.1:
| mcp SDK |
Result |
1.28.1 (current stable) |
works, tools list returns |
2.0.0b2 (preview of the 07-28 release) |
hard failure, exit 1 |
ImportError: cannot import name 'streamablehttp_client' from 'mcp.client.streamable_http'.
Did you mean: 'streamable_http_client'?
Scope: I tested every mcp.* import in mcp2cli against 2.0.0b2. Only the streamable-http one breaks; ClientSession, sse_client, the stdio imports, and the OAuth paths all still resolve. So stdio and SSE users are unaffected at the import layer, and streamable-http users lose the transport entirely.
The misleading error path
With --transport streamable you get the clean ImportError above. Without it, mcp2cli catches the ImportError and falls back to SSE, which then returns 405 Method Not Allowed from the server. That points the blame at the server when the fault is client-side, so anyone debugging the fallback will chase the wrong end of the connection.
Why the test suite won't catch it
uv.lock pins mcp 1.26.0. CI tests against v1 while shipping an unbounded >=1.0 to users, so the gap stays invisible until an unpinned install resolves 2.0.0.
Fix
Add an upper bound in pyproject.toml:
- "mcp>=1.0"
+ "mcp>=1.0,<2"
That turns a fixed-date break into a deliberate port. When you do move to the v2 API, the import rename is the first thing to fix, but it may not be the only one: a full v2 pass should re-check the runtime surface (tool-result shapes, inputSchema field access, the OAuth import paths) against 2.0.0 final rather than b2, since the beta surface can still shift.
Workaround for users before that ships
Pin the SDK at the call site:
uvx --with "mcp<2" mcp2cli ...
Verified: byte-identical output to the current unpinned run.
Severity: high. Hard deadline: 2026-07-28.
What happens
The Python MCP SDK ships stable
2.0.0on 2026-07-28, per the2.0.0b2release notes ("Stable v2 is still targeted for 2026-07-28 alongside the spec release, keep pinning an exact version"). mcp2cli3.3.1declaresmcp>=1.0with no upper bound. The moment 2.0.0 is stable, a freshuvx mcp2cliresolves it and the streamable-http transport stops working.Right now everything looks fine, because pre-releases are opt-in and
uvxstill resolvesmcp 1.28.1. The break lands silently on the release date, on any machine whoseuvxcache misses: a new clone, a CI runner, a teammate's first run.Root cause
The v2 SDK removed the
streamablehttp_clientalias. Onlystreamable_http_client(with the underscore) survives. mcp2cli imports the old name at three sites inmcp2cli/__init__.py:from mcp.client.streamable_http import streamablehttp_clientI confirmed the SDK side directly:
1.28.1exports bothstreamable_http_clientand thestreamablehttp_clientalias;2.0.0b2exports onlystreamable_http_client.Reproduction
Against a live streamable-http server, macOS, mcp2cli 3.3.1:
1.28.1(current stable)2.0.0b2(preview of the 07-28 release)Scope: I tested every
mcp.*import in mcp2cli against2.0.0b2. Only the streamable-http one breaks;ClientSession,sse_client, the stdio imports, and the OAuth paths all still resolve. So stdio and SSE users are unaffected at the import layer, and streamable-http users lose the transport entirely.The misleading error path
With
--transport streamableyou get the clean ImportError above. Without it, mcp2cli catches the ImportError and falls back to SSE, which then returns405 Method Not Allowedfrom the server. That points the blame at the server when the fault is client-side, so anyone debugging the fallback will chase the wrong end of the connection.Why the test suite won't catch it
uv.lockpinsmcp 1.26.0. CI tests against v1 while shipping an unbounded>=1.0to users, so the gap stays invisible until an unpinned install resolves 2.0.0.Fix
Add an upper bound in
pyproject.toml:That turns a fixed-date break into a deliberate port. When you do move to the v2 API, the import rename is the first thing to fix, but it may not be the only one: a full v2 pass should re-check the runtime surface (tool-result shapes,
inputSchemafield access, the OAuth import paths) against2.0.0final rather thanb2, since the beta surface can still shift.Workaround for users before that ships
Pin the SDK at the call site:
Verified: byte-identical output to the current unpinned run.