Issue with MCP Server and Pydantic Model object as tool parameter in Cursor

Problem Description

Whenever I create an MCP server using fastmcp, and in my tools when I add a Pydantic model as an argument, Cursor throws an error when it tries to call the tool:

Logs in Cursor:

{
    "clientMessage": "Invalid type for parameter 'agent' in tool get_agent_model",
    "modelMessage": "Parameter 'agent' must be of type undefined, got object",
    "actualError": "Type mismatch for get_agent_model.agent: expected undefined, got object"
}

It seems to try to pass the correct object. I checked the tool call in Cursor logs:

{
    "params": {
        "case": "mcpParams",
        "value": {
            "tools": [
                {
                    "name": "get_agent_model",
                    "description": "\n        An AI assistant that helps gather agent details and return the agent model\n        \n        # Rules\n        - Ask the user for the agent name\n        - Ask the user for the agent description\n        \n        Then return the agent model JSON\n\n        Args:\n            agent: The agent to get the model for\n        Returns:\n            agent: The agent to get the model for\n        ",
                    "parameters": "{\"agent\":{\"name\":\"RandomAgent\",\"description\":\"An experimental agent designed to explore random data patterns and generate unexpected insights.\"}}",
                    "serverName": "mcp_test"
                }
            ]
        }
    }
}

Example Code

Example using Pydantic Model as Input

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field

mcp = FastMCP("test-mcp")

class Agent(BaseModel):
    """Agent class for managing agent definitions."""
    
    name: str = Field(..., description="Name of the agent")
    description: str = Field("", description="Description of the agent")

@mcp.tool()
def get_agent_model(agent: Agent):
    """
    An AI assistant that helps gather agent details and return the agent model
    
    # Rules
    - Ask the user for the agent name
    - Ask the user for the agent description
    
    Then return the agent model JSON

    Args:
        agent: The agent to get the model for
    Returns:
        agent: The agent to get the model for
    """
    return agent

def main():
    mcp.run(transport="stdio")

Example without Using Pydantic Model as Input

I tried using the tool without a Pydantic model as an argument, and it works fine.

@mcp.tool()
def get_agent_model(name: str, description: str):
    """
    An AI assistant that helps gather agent details and return the agent model
    
    # Rules
    - Ask the user for the agent name
    - Ask the user for the agent description
    
    Then return the agent model JSON

    Args:
        name: The name of the agent
        description: The description of the agent
    Returns:
        agent: The agent to get the model for
    """
    return Agent(name=name, description=description)

Question

This works fine in Claude Desktop. Is this a current limitation in Cursor?

2 Likes

I had something similar happen! For some reason this happens less now… So not sure what has changed now. But just to give another data point :slight_smile:

Thanks,

As a workaround I ended up using the lower level implementation of mcp server instead of FastMCP in python like in here: python-sdk/examples/servers/simple-tool/mcp_simple_tool/server.py at main · modelcontextprotocol/python-sdk · GitHub

And in the input schema I render the Pydantic models to json schema like:

 inputSchema={
                "type": "object",
                "properties": {
                    "agent_metadata": AgentMetadata.model_json_schema(),
                },
                "required": ["agent_metadata"],
            },

That seems to work better,

1 Like

+1 to this issue. Here’s a simple test case.

Cursor has no problems calling this add tool:

@mcp.tool()
async def add(a: int, b: int):
    return a + b

But Cursor is unable to compose the request for this add_pydantic tool:

class AddRequest(BaseModel):
    a: int
    b: int

@mcp.tool()
async def add_pydantic(request: AddRequest):
    return request.a + request.b

Claude Desktop and Windsurf do not have this problem. I’ve also made sure to use the Claude 3.7 Sonnet model (same as I used in Claude Desktop), just in case it was an issue at the LLM layer.

The same behavior happens with the typescript sdk using zod based definitions.
I’m trying to build a more complex mcp tool at the moment and this is a show stopper for me :frowning:

1 Like