-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Open
Description
Problem
Models occasionally send tool arguments with incorrect JSON types - for example, numbers serialized as strings ({"thoughtNumber": "1"} instead of {"thoughtNumber": 1}). This causes Zod validation to reject otherwise valid requests.
This issue affects many MCP servers. For example, modelcontextprotocol/servers#2812 added a specific workaround to one part of the sequential-thinking server, but the maintainers noted this feels like the wrong layer to fix it.
The "proper" fix is probably smarter models, or as a consistent layer in the SDKs. This would avoid server authors either having to implement ad-hoc coercion logic OR suffer from these problems.
Proposal
The SDK could provide type coercion for tool arguments, either:
- Built-in coercion - automatically coerce string→number, string→boolean etc. when the schema expects a different primitive type (e.g. similar to https://ajv.js.org/coercion.html)
- Composable helper - export a
coerceToolArgs(schema, args)utility that servers can use - Documentation - guidance on how to handle this with Zod's
.coerceor.preprocess(but doing so safely so that e.g."thing"doesn't becometruewhen coerced to bool)
Example
// Current: fails validation
const args1 = { thoughtNumber: "1" } // model sent number string
const args2 = { thoughtNumber: "one" } // model sent string
const schema = z.object({ thoughtNumber: z.number() })
schema.parse(args1) // ZodError: Expected number, received string
schema.parse(args2) // ZodError: Expected number, received string
// With coercion: works
const coercedSchema = z.object({ thoughtNumber: z.coerce.number() })
coercedSchema.parse(args1) // { thoughtNumber: 1 }
coercedSchema.parse(args2) // ZodError: Expected number, received stringMetadata
Metadata
Assignees
Labels
No labels