python-sdk icon indicating copy to clipboard operation
python-sdk copied to clipboard

MCP SDK Pydantic v2 Compatibility Bug Report

Open rijovarghese9 opened this issue 2 months ago • 3 comments

Initial Checks

  • [x] I confirm that I'm using the latest version of MCP Python SDK
  • [x] I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue

Description

Problem Description

Symptoms

MCP clients consistently fail to connect to MCP servers with the error:

Error executing MCP tool: Not connected

This occurs despite MCP servers being properly configured and running.

Root Cause

The MCP Python SDK uses Pydantic v1-style serialization patterns that are incompatible with Pydantic v2. When the SDK attempts to serialize CallToolResult objects in tool responses, it produces malformed data structures.

Impact Assessment

Functional Impact

  • Critical: Complete loss of MCP server functionality through the standard MCP client interface
  • Universal: Affects all stdio-based MCP servers using the official Python SDK
  • Workaround Required: Manual JSON-RPC implementation needed to bypass MCP framework

Affected Components

  • MCP client-server communication layer
  • Tool response serialization
  • All MCP Python SDK versions (confirmed across multiple versions)
  • Stdio transport protocol implementation

Suggested Implementation

# In MCP SDK - replace problematic serialization
def serialize_tool_result(result: CallToolResult) -> dict:
    # Use Pydantic v2 compatible serialization
    return result.model_dump()  # Direct dictionary conversion

Example Code

Expected Behavior:

# MCP server returns properly structured response
result = CallToolResult(
    content=[TextContent(type="text", text="analysis result")],
    isError=False
)
# Should serialize to: {"content": [...], "isError": false}

Actual Behavior:

# MCP SDK with Pydantic v2 produces tuple corruption
result = CallToolResult(...)  
# Incorrectly serializes to: [("content", [...]), ("isError", false)]
# Instead of: {"content": [...], "isError": false}

Error Manifestation: Input should be a valid dictionary or instance of TextContent [type=model_type, input_value=('meta', None), input_type=tuple]

This indicates the MCP framework is receiving Python tuples where it expects dictionaries.

Reproduction Steps

  1. Environment Setup

Install MCP SDK (any current version)

pip install mcp

Create a basic MCP server

test_server.py:

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import CallToolResult, TextContent

app = Server("test-server")

@app.call_tool()
def test_tool():
    return CallToolResult(
        content=[TextContent(type="text", text="Hello World")],
        isError=False
    )

@app.list_tools()
def list_tools():
    return [{"name": "test_tool", "description": "Test tool"}]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await app.run(read_stream, write_stream, app.create_initialization_options())

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
  1. MCP Client Configuration
{
  "mcpServers": {
    "test-server": {
      "command": "python",
      "args": ["test_server.py"]
    }
  }
}
  1. Attempt Tool Usage
# This will fail with "Not connected" error
use_mcp_tool(
    server_name="test-server",
    tool_name="test_tool",
    arguments={}
)

Python & MCP Python SDK

__Environment Versions for MCP Bug Report:__

## Python & MCP Python SDK Versions

__Python Version:__ `3.13.5`

__MCP SDK Version:__ `1.18.0`

__Pydantic Version:__ `2.12.3`

## Additional Context

__Installation Method:__ Virtual environment (`venv`)

__Platform:__ Windows 11 Pro (x64)

__MCP Server Implementation:__ Custom stdio-based MCP server for WinDbg crash analysis

__Issue Confirmed On:__ MCP SDK version 1.18.0 with Pydantic 2.12.3

## Version History Tested

During troubleshooting, we tested multiple MCP SDK versions:

- ✅ `1.18.0` (current) - __Bug confirmed__
- ✅ `1.12.3` (downgraded) - __Bug still present__
- ❌ `<1.12.4` (earlier versions) - Still had serialization issues

__Note:__ The bug persists across MCP SDK versions and appears to be a fundamental Pydantic v1/v2 compatibility issue in the MCP framework's serialization logic.

This issue prevents the adoption and use of MCP servers through standard MCP clients and requires urgent attention to restore compatibility with modern Python environments.

rijovarghese9 avatar Oct 24 '25 16:10 rijovarghese9

+1 - I have also experienced this bug, any workarounds?

BJWRD avatar Nov 11 '25 11:11 BJWRD

I'm unable to reproduce this. Additionally your code isn't a valid server, for example:

@app.call_tool()
def test_tool():

The call_tool decorator requires test_tool to take on two arguments, name: str, and args: dict[str, str].

Please supply a full code example for both the client and server which reproduces this issue. A maintainer should be able to copy/paste the code and run it locally and immediately see the issue reproduced.

maxisbey avatar Nov 11 '25 16:11 maxisbey

@maxisbey I can't speak for @rijovarghese9, but here is a breakdown what I've experienced -

This occurred while running mcpo as a proxy to an mcp-atlassian (ghcr.io/sooperset/mcp-atlassian:latest server via uvx in Docker:

Dockerfile:

FROM python:3.11-slim
WORKDIR /app
RUN pip install mcpo uv
EXPOSE 8000

CMD ["uvx", "mcpo", "--host", "0.0.0.0", "--port", "8000", "--", "uvx", "mcp-atlassian", "--transport", "streamable-http", "--host", "ai-alb-dns.com", "--port", "8000"]

Logs of docker ps of docker container runtime following the docker build etc -

2025-11-13 10:47:08,204 - INFO - Starting MCPO Server...
2025-11-13 10:47:08,205 - INFO - Configuring for a single Stdio MCP Server with command: uvx mcp-atlassian --transport streamable-http --host ai-alb-dns.com --port 8000
Traceback (most recent call last):
  ...
  File "fastmcp/settings.py", line 74, in <module>
    class ServerSettings(BaseSettings):
TypeError: cannot specify both default and default_factory
This triggers downstream in mcpo:

mcp.shared.exceptions.McpError: Connection closed
ERROR: Application startup failed. Exiting.

The error happens before mcp-atlassian completes initialisation, causing MCPO to fail on startup (Connection closed).

Looks like building with pydantic<2.0 would resolve it currently?

BJWRD avatar Nov 13 '25 11:11 BJWRD