Skip to content

ListTools request handler fails to generate inputSchema (jsonSchema) #1028

@juanlluva

Description

@juanlluva

Describe the bug

When a tool - either with or without an input schema - is registered onto the mcp server, it gets registered correctly with its input schema being a ZodObject ({type: 'object', shape: <accessor>}), the server starts and the MCP inspector is able to connect to it.
When a list tools request is sent from the mcp inspector, all toolDefinitions are generated, converting the existing tool inputSchema (Zod) into a jsonSchema. However, despite the shape and type of the zod input schema, the zodToJsonSchema function always returns {type: "string", $schema: "http://json-schema.org/draft-07/schema#"}. This turns into an error on the MCP inspector, being unable to list tools, thus unable to execute any of them.

To Reproduce
Steps to reproduce the behavior:

  1. Create an instance of McpServer:
server = new McpServer({...serverInfo}, {
      capabilities,
      instructions,
    });
  1. Register a tool with an inputSchema:
server.registerTool(
      name,
      {
        title: name,
        description: description,
        inputSchema: z.object({...schema}).shape,
      },
      handler,
    );
  1. Start MCP inspector
  2. Connect to MCP server from inspector
  3. Try to list tools
  4. Get the error:
Uncaught (in promise) ZodError: [
  {
    "received": "string",
    "code": "invalid_literal",
    "expected": "object",
    "path": [
      "tools",
      0,
      "inputSchema",
      "type"
    ],
    "message": "Invalid literal value, expected \"object\""
  }
]

Expected behavior
The input Schema of the tool should be converted into a valid, matching jsonSchema.

Additional Context
Debugging the application, I could see that the zodToJsonSchema function calls the parseDef function with the zod definition. When the jsonSchemaOrGetterconstant gets calculated through the selectParser function, it passes def, def.typeName and refs. The second argument is undefined. Then teh selectParser function switches typeName on all possible ZodFirstPartyTypeKind.<ZodType>. However, ZodFirstPartyTypeKind is {}, so the first one matches, which is the string matcher.

I have @modelcontextprotocol/[email protected] dependency installed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featurebugSomething isn't workingready for workEnough information for someone to start working on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions