How to fix cannot import name streamablehttp_client and McpError in MCP SDK 2
Table of contents
- Key takeaways
- ImportError: cannot import name 'streamablehttp_client' from 'mcp.client.streamable_http'
- ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'
- Why do these errors appear when you changed nothing?
- Immediate fix: pin mcp below 2
- If the failing piece is a server started with uvx
- How to port the client to mcp 2.x
- httpx2, not httpx
- How to check that the migration works
- ClientSession negotiates 2025-11-25; Client reaches 2026-07-28
- Frequently asked questions
- Is there a compatibility alias for streamablehttp_client in mcp 2?
- Can I write one client that works with both mcp 1.x and 2.x?
- How long will mcp 1.x keep getting patches?
- Conclusion
- Sources
Fix cannot import name streamablehttp_client and McpError after mcp 2: pin mcp
The error cannot import name 'streamablehttp_client' from 'mcp.client.streamable_http' means you have the mcp 2.x package installed and your code was written for 1.x. Version 2.0.0 of the Model Context Protocol (MCP) Python SDK, released on 28 July 2026, deleted that function and renamed McpError to MCPError, which is the second ImportError you will hit. The immediate fix is to pin mcp<2; the lasting one is to port the client to streamable_http_client. I reproduced both on 18 October 2026 in Docker with Python 3.14.7, mcp 1.30.0 and mcp 2.3.0. There is a Spanish version of this guide.
Key takeaways
mcp2.0.0 shipped on 28 July 2026 and the current release is 2.3.0, from 2 October; apip install -U mcpor a requirement with no upper bound installs it on its own.- Both errors fire on the first line that imports the old name: first
streamablehttp_clientand, once you fix that,McpError. - Pinning
mcp<2resolves to 1.30.0 today, the maintenance line that still gets security patches, and the 1.x client works again without a code change. - The port is four changes:
streamable_http_client, headers and timeouts on anhttpx2.AsyncClient, a(read, write)pair instead of three values, andMCPErrorwithe.codeande.message. - The reference servers
mcp-server-fetchandmcp-server-time2026.7.10 put no ceiling onmcp; underuvxthey fail with theMcpErrorImportError, and--with "mcp<2"or an upgrade fixes them.
ImportError: cannot import name ‘streamablehttp_client’ from ‘mcp.client.streamable_http’
This is the first error, and it fires at import time, before any connection opens. I got it by running a client that worked on 1.30.0 against mcp 2.3.0:
Traceback (most recent call last):
File "/work/v1/client.py", line 5, in <module>
from mcp.client.streamable_http import streamablehttp_client
ImportError: cannot import name 'streamablehttp_client' from
'mcp.client.streamable_http' (/work/venv2/lib/python3.14/site-packages/
mcp/client/streamable_http.py)
In your terminal the message is one line; I wrapped it to fit here. The function did not move: it is gone. The 1.x line carried two names, streamablehttp_client and streamable_http_client, and in mcp 1.30.0 the first one already carries a @deprecated decorator pointing to streamable_http_client. Release 2.0.0 deleted the old alias, and in this case Python adds no name suggestion to the message.
Check your version with pip show mcp. If it says 2.x and the code imports streamablehttp_client, that is your diagnosis.
ImportError: cannot import name ‘McpError’ from ‘mcp.shared.exceptions’
This is the second error, and you will see it as soon as you rename the function, or straight away if your code only catches exceptions. With the first import fixed, the same client stopped here:
File "/work/v1/client_half.py", line 6, in <module>
from mcp.shared.exceptions import McpError
ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'
(/work/venv2/lib/python3.14/site-packages/mcp/shared/exceptions.py).
Did you mean: 'MCPError'?
This time Python’s suggestion is right, but renaming is not enough. In 2.x the exception exposes e.code and e.message directly, whereas 1.x kept them in e.error.code and e.error.message. If you also raise the error from a server, the constructor changed from McpError(ErrorData(...)) to MCPError(code, message); that side is covered in the guide to migrating an MCP server to FastMCP 4 and SDK 2.
Why do these errors appear when you changed nothing?
Because something installed mcp 2.x for you. These are the three causes I ran into:
- Requirement with no ceiling:
mcp>=1.2in arequirements.txtorpyproject.tomlhas resolved to 2.3.0 since 2 October 2026 pip install -Uor a rebuilt image: any fresh environment without a lock file takes the latest releaseuvxwith an old server:uvx mcp-server-fetch==2026.7.10builds a temporary environment and picks the newestmcpthe package allows
This is the PyPI timeline that explains when each case started failing:
| Version | PyPI date | What it means |
|---|---|---|
mcp 2.0.0 and 1.29.0 |
28 July 2026 | The 2.x line ships; 1.x continues alongside |
mcp-server-fetch 2026.8.18 |
18 August 2026 | Reference servers move to mcp>=1.29.0,<2 |
mcp 1.30.0 |
7 September 2026 | Latest 1.x release as of today |
mcp 2.3.0 |
2 October 2026 | The release an unbounded requirement installs |
Immediate fix: pin mcp below 2
Put a ceiling on mcp and the 1.x code works again without changing a line. The SDK’s own migration guide[1] recommends exactly that: "The v1.x maintenance line keeps receiving critical bug fixes and security patches", and "If your package depends on mcp, keep a <2 upper bound until you’ve migrated". These are the commands I ran in an environment that already had 2.3.0:
pip install "mcp<2"
python v1/client.py http://b9p04-srv1:8000/mcp
pip uninstalled 2.3.0, installed 1.30.0 along with httpx 0.28.1 and httpx-sse 0.4.3, and the untouched client answered as it did on day one:
server: demo proto: 2025-11-25
session: True
add -> 5
McpError: 0 Error creating resource from template: ... 'missing'
The last line is the expected exception, a read of a resource that does not exist. In pyproject.toml, write the dependency as "mcp>=1.25,<2"; in a clean environment that constraint also resolved to 1.30.0. The downgrade leaves mcp-types 2.3.0 and httpx2 2.13.1 installed, which 1.30.0 does not use; uninstall them or leave them.
If the failing piece is a server started with uvx
The fix is the same, applied to the temporary uvx environment. This is what I saw with mcp-server-fetch 2026.7.10, which declared mcp>=1.1.3:
$ uvx mcp-server-fetch==2026.7.10
File ".../mcp_server_fetch/server.py", line 6, in <module>
from mcp.shared.exceptions import McpError
ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'
(...). Did you mean: 'MCPError'?
With uv 0.11.3, that environment resolved mcp 2.3.0; adding --with "mcp<2" resolved 1.30.0 and the server started. mcp-server-time 2026.7.10 failed and recovered the same way. The other way out is to drop the ==2026.7.10 from your editor config: version 2026.10.10 already declares mcp>=1.29.0,<2, as the mcp-server-fetch pyproject.toml[2] shows. In an MCP client config file it looks like this:
{
"mcpServers": {
"fetch": {
"command": "uvx",
"args": ["--with", "mcp<2", "mcp-server-fetch==2026.7.10"]
}
}
}
If you run your own servers this way, the guide on how to install a local MCP server for your editor shows where that file lives in each client.
How to port the client to mcp 2.x
Porting a low-level client takes four changes, and the rest of the code (ClientSession, initialize(), call_tool()) stays as it was. This is the 1.x starting client, trimmed to the part that changes:
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
from mcp.shared.exceptions import McpError
HEADERS = {"Authorization": "Bearer your_access_token_here"}
async def main() -> None:
async with streamablehttp_client(URL, headers=HEADERS) as (
read, write, get_session_id,
):
async with ClientSession(read, write) as session:
init = await session.initialize()
print("server:", init.serverInfo.name)
try:
await session.read_resource("notes://missing")
except McpError as e:
print("McpError:", e.error.code, e.error.message)
And this is the same client ported to mcp 2.3.0, which worked first time against a 1.30.0 server and a 2.3.0 one:
import httpx2
from mcp import ClientSession, MCPError
from mcp.client.streamable_http import streamable_http_client
HEADERS = {"Authorization": "Bearer your_access_token_here"}
async def main() -> None:
http = httpx2.AsyncClient(headers=HEADERS,
timeout=httpx2.Timeout(30, read=300))
async with http, streamable_http_client(URL, http_client=http) as (
read, write,
):
async with ClientSession(read, write) as session:
init = await session.initialize()
print("server:", init.server_info.name)
try:
await session.read_resource("notes://missing")
except MCPError as e:
print("MCPError:", e.code, e.message)
The changes, one by one:
- Name and arguments:
streamable_http_client(url, http_client=...)no longer takesheaders,timeout,sse_read_timeoutorauth. Rename only and it fails withTypeError: streamable_http_client() got an unexpected keyword argument 'headers' - Your own HTTP client: headers, timeouts and auth go on an
httpx2.AsyncClient.Timeout(30, read=300)reproduces the 1.x defaults; without it,httpx2applies a flat 5 s, too short for the GET stream that stays open - Two values, not three: the context yields
(read, write). Keep three names and it fails withValueError: not enough values to unpack (expected 3, got 2). For the session ID, the guide uses anhttpx2event hook that reads themcp-session-idheader - snake_case fields and
MCPError:serverInfobecomesserver_info,protocolVersionbecomesprotocol_version, and the exception exposese.codeande.message
I checked that the header gets through with a request event hook: the POST and the GET both went out with Authorization: Bearer your_access_token_here.
httpx2, not httpx
The mcp 2.x package depends on httpx2[3], a fork of httpx with built-in server-sent events (SSE) support, and no longer installs httpx. In my mcp 2.3.0 environment, pip list showed httpx2 2.13.1 and no httpx. If you follow an example that passes an httpx.AsyncClient, you will first hit ModuleNotFoundError: No module named 'httpx'. If you install httpx yourself, the guide warns that such a client "degrades in subtle ways (server-initiated messages stop arriving) instead of raising immediately".
How to check that the migration works
Run the ported client against your server and against one from the other line, because both crossings must work. I set up two servers on a Docker network, one with FastMCP from mcp 1.30.0 and one with MCPServer from mcp 2.3.0, each with an add tool and a notes://{name} resource:
docker network create b9p04-net
docker run -d --name b9p04-srv2 --network b9p04-net --user 1000:1000 \
-e HOME=/work -v "$PWD":/work -w /work/v2 python:3.14-slim-trixie \
/work/venv2/bin/python server.py
docker run --rm --network b9p04-net --user 1000:1000 -e HOME=/work \
-v "$PWD":/work -w /work/v2 python:3.14-slim-trixie \
/work/venv2/bin/python client.py http://b9p04-srv2:8000/mcp
The three combinations answered like this:
== client 2.3.0 -> server 2.3.0
server: demo proto: 2025-11-25
add -> 5
MCPError: -32603 Error creating resource from template notes://missing
== client 2.3.0 -> server 1.30.0
server: demo proto: 2025-11-25
add -> 5
MCPError: 0 Error creating resource from template: ... 'missing'
== client 1.30.0 -> server 2.3.0
server: demo proto: 2025-11-25
session: True
add -> 5
McpError: -32603 Error creating resource from template notes://missing
The same resource error arrives with code 0 from a 1.30.0 server and with -32603 (JSON-RPC internal error) from a 2.3.0 one. If your client branches on e.code, test against both lines.
ClientSession negotiates 2025-11-25; Client reaches 2026-07-28
ClientSession.initialize() always performs the pre-2026 handshake, which is why all three outputs say 2025-11-25. To use revision 2026-07-28 of the MCP specification, SDK 2 ships a high-level Client that takes the same transport:
from mcp import Client, MCPError
async def main(url: str) -> None:
http = httpx2.AsyncClient(headers=HEADERS,
timeout=httpx2.Timeout(30, read=300))
transport = streamable_http_client(url, http_client=http)
async with http, Client(transport) as c:
print("server:", c.server_info.name,
"proto:", c.protocol_version)
r = await c.call_tool("add", {"a": 2, "b": 3})
print("add ->", r.content[0].text)
Against the 2.3.0 server it printed proto: 2026-07-28, and against the 1.30.0 one, proto: 2025-11-25. Client defaults to mode="auto": it sends server/discover first and, if the server does not understand it, retries with initialize. When I started mcp-server-fetch over stdio with --with "mcp<2", the 1.x server wrote a warning with 31 validation errors for that probe to stderr before answering correctly. With Client(..., mode="legacy") the handshake goes straight to initialize and the log stays clean.
Frequently asked questions
Is there a compatibility alias for streamablehttp_client in mcp 2?
Not in the official SDK. In mcp 2.3.0 neither streamablehttp_client nor McpError exists, and the migration guide lists both as removed. FastMCP 4 does keep McpError as an alias in fastmcp.exceptions, but that only helps if you use that package.
Can I write one client that works with both mcp 1.x and 2.x?
Not with the same code. In 1.30.0 streamable_http_client already exists, but it yields three values and expects an httpx.AsyncClient; in 2.x it yields two and expects an httpx2.AsyncClient. MCPError does not exist in 1.30.0 either. Pick one line and pin it in your dependencies.
How long will mcp 1.x keep getting patches?
The official docs promise "critical bug fixes and security patches" for the 1.x line, with no published end date as of 18 October 2026. Release 1.30.0, from 7 September, is the latest so far. Pinning mcp<2 buys you time, but it does not replace the migration.
Conclusion
cannot import name 'streamablehttp_client' and cannot import name 'McpError' are the same problem: SDK 1.x code running on mcp 2.x. To keep working today, pin mcp<2 or add --with "mcp<2" to uvx. When you migrate, replace the function with streamable_http_client, move headers and timeouts onto an httpx2.AsyncClient, unpack two values and catch MCPError. If you also maintain the server, continue with the guide to migrating an MCP server to FastMCP 4, and to start one from scratch, the one on building your own MCP server.
Sources: [1] MCP Python SDK migration guide from v1 to v2[1], [2] Release history of the mcp package on PyPI[4], [3] MCP Python SDK 2.0.0 release notes[5], [4] MCP Python SDK 2.3.0 release notes[6], [5] mcp-server-fetch pyproject.toml[2], [6] mcp-server-fetch releases on PyPI[7], [7] httpx2 repository[3].
Sources
Source code
Access all the source code for this post on GitHub.
View on GitHub