[BUG] MCP FastMCP Pydantic model parameters serialized as JSON strings causing validation errors

Status Fixed / completed
Maintainer reply ✓ Yes — ashwin-ant
Activity 15 comments · opened Jul 6, 2025 · closed Sep 8, 2025
💡 Likely answer: A maintainer (ashwin-ant, collaborator) responded on this thread — see the highlighted reply below.

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

  1. 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}"
  1. Configure the server in Claude Code MCP settings
  2. Attempt to call the tool:
mcp__test-server__test_pydantic_model({
  "data": {"name": "John", "age": 30}
})
  1. 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:

  1. Claude Code receives the parameter as a proper object/dictionary
  2. Claude Code's MCP client serializes it to a JSON string during transmission
  3. FastMCP receives a string instead of the expected dictionary
  4. 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:

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.

View original on GitHub ↗

15 Comments

ashwin-ant collaborator · 1 year ago

@jsulopzs does this server work in the MCP inspector? https://github.com/modelcontextprotocol/inspector

jsulopzs · 1 year ago

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" />

 ✻ Welcome to Claude Code!

   /help for help, /status for your current setup

   cwd: /Users/sota/Library/CloudStorage/Dropbox-datons/Jesus Lopez/2 Business/1 Datons/1 Projects/Server MCP


 ※ Tip: Use /permissions to pre-approve and pre-deny bash, edit, and MCP tools

> /mcp 
  ⎿  (no content)

> Test pydantic model by passing the data with name and age

⏺ I'll test the pydantic model MCP tool by passing data with name and age.

⏺ test-mcp:test_pydantic_model (MCP)(data: "{\"name\": \"John Doe\", \"age\": 30}")
  ⎿  Error: Input validation error: '{"name": "John Doe", "age": 30}' is not of type 
     'object'

⏺ Let me check the correct format for this tool:

⏺ test-mcp:test_pydantic_model (MCP)(data: "{\n  \"name\": \"John Doe\",\n  \"age\":
                                    30\n}")
  ⎿  No (tell Claude what to do differently)

> don't use data, use directly name and age as if they were there parameters

⏺ I'll call the test pydantic model tool with name and age as direct parameters:

⏺ test-mcp:test_pydantic_model (MCP)(name: "John Doe", age: "30")
  ⎿  Error: Input validation error: 'data' is a required property

⏺ The tool requires a "data" parameter that contains the name and age. Let me try with
  the correct structure:

⏺ test-mcp:test_pydantic_model (MCP)(data: "<name>John Doe</name>\n<age>30</age>")
  ⎿  Error: Input validation error: '<name>John Doe</name>\n<age>30</age>' is not of type 
     'object'

⏺ The tool expects the data parameter to be an object with name and age properties. The
  error suggests it needs to be passed as a proper object structure.

╭────────────────────────────────────────────────────────────────────────────────────────────╮
│ >                                                                                          │
╰────────────────────────────────────────────────────────────────────────────────────────────╯
  ? for shortcuts                                                                          ◯
kfstorm · 1 year ago

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

iwakitakuma33 · 1 year ago

the same issue for gitlab-mcp has been fixed.
preprocess before boolean

SurgeonY · 1 year ago

Same issue. Conport MCP server works correctly with other agents.

ibash · 1 year ago

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

shaders · 1 year ago

Any simple schema with oneOf/anyOf results in object being passed as JSON String too.

var schemaDogOrCat = `{
      "oneOf": [
        {
          "properties": {
            "cat": {
              "properties": {
                "age": {
                  "type": "integer"
                },
                "color": {
                  "type": "string"
                }
              },
              "required": [],
              "type": "object"
            }
          },
          "required": [
            "cat"
          ]
        },
        {
          "properties": {
            "dog": {
              "properties": {
                "breed": {
                  "type": "string"
                }
              },
              "required": [],
              "type": "object"
            }
          },
          "required": [
            "dog"
          ]
        }
      ],
  "properties": {},
  "required": [],
  "type": "object"
}`

Results in

Request

{
  `dog`: `{\"breed\": \"terrier\"}`
}
jsulopzs · 1 year ago

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!

nikkoxgonzales · 1 year ago
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.

yekkhan-liftoff · 1 year ago

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-action to run-gemini-cli as a workaround.

Could you provide an update on:

  1. Timeline - Is there a target release for the fix?
  2. Workarounds - Any recommended approaches while waiting for the fix?
  3. Root cause - Is this related to how the action processes MCP tool parameters?

Thank you.

nikkoxgonzales · 1 year ago
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-action to run-gemini-cli as a workaround. Could you provide an update on: 1. Timeline - Is there a target release for the fix? 2. Workarounds - Any recommended approaches while waiting for the fix? 3. Root cause - Is this related to how the action processes MCP tool parameters? 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.

ibash · 1 year ago

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.

ollie-anthropic collaborator · 11 months ago

Hey all, very sorry for the delayed response on this. This is now working in the latest CC version. We have a fix.

yekkhan-liftoff · 11 months ago

@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!

github-actions[bot] · 11 months ago

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.