[BUG] MCP FastMCP Pydantic model parameters serialized as JSON strings causing validation errors
Environment
- Platform: macOS (Darwin 24.5.0)
- Claude CLI version: Claude Code
- Operating System: macOS
- Terminal: Claude Code integrated terminal
Bug Description
When using FastMCP servers with Pydantic model parameters, Claude Code consistently fails with validation errors because it serializes Pydantic model objects as JSON strings instead of passing them as proper dictionary objects to the MCP server.
Error message:
Input validation error: '{"evaluation_id": "test-eval", "evaluation_name": "Test", "course_name": "Course", "professor_name": "Prof"}' is not of type 'object'
Related to existing issue #2747 which reports the same systematic problem with qdrant-store metadata parameters.
Steps to Reproduce
- Create a FastMCP server with a Pydantic model parameter:
from fastmcp import FastMCP, Context
from pydantic import BaseModel
mcp = FastMCP("test-server", version="1.0.0")
class TestModel(BaseModel):
name: str
age: int
@mcp.tool
def test_pydantic_model(data: TestModel) -> str:
"""Test tool with Pydantic model parameter."""
return f"Hello {data.name}, age {data.age}"
- Configure the server in Claude Code MCP settings
- Attempt to call the tool:
mcp__test-server__test_pydantic_model({
"data": {"name": "John", "age": 30}
})
- Observe the validation error
Expected Behavior
FastMCP should receive the Pydantic model parameter as a proper Python dictionary object that can be validated and instantiated by Pydantic.
According to FastMCP documentation and the MCP specification, complex object parameters should be passed as dictionary objects, not JSON strings.
Actual Behavior
Claude Code's MCP client serializes the dictionary parameter as a JSON string before sending it to the MCP server, causing Pydantic validation to fail because:
- Expected:
dict_type(Python dictionary) - Received:
input_type=str(JSON string) - Value:
'{"name": "John", "age": 30}'(serialized string instead of native dict)
Root Cause Analysis
This appears to be a systematic parameter serialization issue in Claude Code's MCP integration layer, specifically affecting dictionary/object type parameters. The issue occurs because:
- Claude Code receives the parameter as a proper object/dictionary
- Claude Code's MCP client serializes it to a JSON string during transmission
- FastMCP receives a string instead of the expected dictionary
- Pydantic validation fails because it expects an object, not a string
Impact
- Breaks FastMCP servers that use Pydantic models as parameters
- Limits MCP functionality to only simple primitive types (strings, integers, booleans)
- Forces workarounds like using individual parameters instead of structured objects
- Creates inconsistency between documented MCP capabilities and actual functionality
Workaround
Convert Pydantic model parameters to individual parameters:
# Instead of this (doesn't work):
@mcp.tool
def setup_evaluation(config: EvaluationConfig) -> str:
pass
# Use this (works):
@mcp.tool
def setup_evaluation(
evaluation_id: str,
evaluation_name: str,
course_name: str,
professor_name: str
) -> str:
# Create Pydantic model internally
config = EvaluationConfig(
evaluation_id=evaluation_id,
evaluation_name=evaluation_name,
course_name=course_name,
professor_name=professor_name
)
pass
Additional Context
Related Issues:
- Issue #2747: Same problem with qdrant-store metadata parameters
- Forum discussion: https://forum.cursor.com/t/issue-with-mcp-server-and-pydantic-model-object-as-tool-parameter-in-cursor/77110
Why this went unnoticed:
- Most MCP servers use simple parameter types
- FastMCP's Pydantic model feature is relatively new
- Documentation examples often show simple use cases
Technical Details:
- This affects all MCP clients that use Claude Code's MCP integration
- The issue is in the MCP client layer, not in FastMCP itself
- FastMCP works correctly with other MCP clients (confirmed by community)
This is a critical issue that prevents the use of modern structured parameter approaches in MCP servers, forcing developers to use less maintainable individual parameter patterns.
15 Comments
@jsulopzs does this server work in the MCP inspector? https://github.com/modelcontextprotocol/inspector
Nope, just did it and it works on the inspector. Although it keeps failing in Claude Code, attaching conversation below.
<img width="3248" height="2112" alt="Image" src="https://github.com/user-attachments/assets/aaa8c0e4-c0f2-4e58-b285-c271b5df0137" />
I encountered a similar issue that an MCP server expects a boolean value as argument but Claude Code insists to pass a string value.
https://github.com/zereight/gitlab-mcp/issues/142
the same issue for gitlab-mcp has been fixed.
preprocess before boolean
Same issue. Conport MCP server works correctly with other agents.
Hey @ashwin-ant the root cause is that fastmcp sends references in the jsonschema which claude has trouble working with. Dereferencing the schema before sending it to the anthropic api does work.
See https://github.com/jlowin/fastmcp/pull/1427
Any simple schema with oneOf/anyOf results in object being passed as JSON String too.
Results in
Hi ppl,
I want to echo the importance of this issue. There are quite a few Python users, myself included, who rely on FastMCP for building MCP servers. Since these servers are API-based, Pydantic is the go-to library for input validation and schema management.
Unfortunately, this serialization bug in Claude Code's MCP client has forced me to pause all MCP-related development through Claude Code, as structured parameters are essential for maintainable APIs.
Could this issue be prioritized? Fixing it would make a big difference for Python developers using Pydantic and FastMCP.
Thank you for your attention!
I couldn't agree more with you. It seems strange that this compatibility issue has remained unresolved for over a month now. I've noticed that Claude desktop works perfectly with FastMCP when using Pydantic features. I hope the developers will prioritize fixing this issue soon.
Hi @ashwin-ant, thanks for the great work on Claude Code! 🙏
We're experiencing this same bug in our production workflow where we've had to switch from
claude-code-actiontorun-gemini-clias a workaround.Could you provide an update on:
Thank you.
For workaround, just create a version of your MCP server using the newest Annotated feature of FastMCP: https://gofastmcp.com/servers/tools#simple-string-descriptions. With this you can still have a type validation and easy access to descriptions.
Hi @jsulopzs @nikkoxgonzales @yekkhan-liftoff
I made a fix for this on the fastmcp side, here: https://github.com/jlowin/fastmcp/pull/1427
Feel free to go to that issue and add comments to see if we can get it merged as a temporary workaround (until claude code is fixed). Or just use a fork of fastmcp with that patch applied.
Hey all, very sorry for the delayed response on this. This is now working in the latest CC version. We have a fix.
@ollie-anthropic Thanks for the update! Could you confirm if Claude Code Action is already using the latest CC version? I just checked and it seems the issue still persists. Thanks!
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.