In MCP, what is a tool's inputSchema and how is it used by client and server?
answer
- Describes the arguments, not the result
- JSON Schema object on each tool
- The model sees it and fills it
- Server must still validate itself
- Invalid arguments are -32602
basics
~20 sinputSchema is the JSON Schema object in a tool's tools/list entry that describes the arguments the tool accepts. The host uses it to shape and check the arguments object sent in tools/call, and the server validates against it again.
solid answer
~40 sEach entry a server returns from `tools/list` describes one callable function: a `name`, a natural-language `description`, and an `inputSchema` — a JSON Schema object (`"type": "object"` with `properties` and `required`) that defines the arguments the tool accepts. The host renders that schema into whatever tool format its model expects, so the schema is what the model actually sees when it decides how to fill in arguments; the client can also use it to validate arguments or to render a UI. A call then sends `tools/call` with `params.name` and `params.arguments`. The schema is a contract, not enforcement: the server MUST validate the arguments itself and reject a malformed call with JSON-RPC `-32602` (invalid params). In MCP revision 2026-07-28 the tool shape is unchanged, but every request additionally carries `_meta` with `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities`.
code
json · 13 lines{
"name": "search_issues",
"description": "Search the issue tracker by full-text query.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string", "description": "Full-text query" },
"state": { "type": "string", "enum": ["open", "closed", "all"] },
"limit": { "type": "integer", "minimum": 1, "maximum": 100 }
},
"required": ["query"]
}
}go deeper
Know that inputSchema is a JSON Schema object listing the tool's arguments, that it comes from tools/list, and that tools/call sends params.name plus params.arguments matching it.
Explain the three consumers — model, client, server — and be able to say why the server still validates and answers a violation with -32602 rather than a tool-level error result.
Show judgment in schema design: enums over free strings, real descriptions, shallow shapes, minimal required set, and no reliance on state left over from earlier calls on the same connection.
Own the schema as a public API contract across a fleet of servers: naming conventions, how schema changes ripple into model behaviour and evaluation suites, and how much argument surface you are willing to expose to a model at all.
## Where inputSchema lives A Model Context Protocol server advertises its callable functions through `tools/list`. The result is a `ListToolsResult` whose `tools` array holds one `Tool` object per function. The fields that matter for a call are: - `name` — the identifier passed back in `tools/call`. It is 1–128 characters from `A-Za-z0-9_-.`, case-sensitive, and unique within that server. - `description` — free prose. This is a hint aimed at the model: it is what tells the model what the tool is for and when it is appropriate. - `inputSchema` — a JSON Schema object describing the arguments. - `outputSchema` — optional, describing the structured result. - `annotations` — optional behavioural hints. `inputSchema` is always an object schema: `"type": "object"`, a `properties` map, and usually a `required` array. Nested objects, arrays, enums and per-property `description` strings are all ordinary JSON Schema and all legal. ## Who consumes it Three different consumers read the same schema. **The model.** The host application converts the MCP tool definition into whatever tool-definition format its model API expects and passes it along with the conversation. From the model's point of view the schema plus the description *is* the tool: the property names, their types, their enums and their descriptions are the only thing it has to reason from. A schema with a bare `{"type": "string"}` property called `q` produces worse tool calls than one that says `"description": "Full-text search query; supports AND/OR"`. **The client/host.** Because the schema is machine-readable, the client can validate the arguments the model produced before spending a round trip, and can render a confirmation dialog showing exactly which arguments are about to be sent — which matters because the host is the consent boundary for tool execution. **The server.** The schema published in `tools/list` does not constrain what actually arrives on the wire. Anything can POST to an MCP endpoint. The server must re-validate every `tools/call` against its own schema and reject a violation with a JSON-RPC error `-32602`, invalid params. Treating the schema as if the client had already enforced it is the classic mistake. ## Making the call A call is a normal JSON-RPC request with method `tools/call` and `params` of `{ name, arguments }`, where `arguments` is an object matching `inputSchema`. In MCP revision 2026-07-28 the request also carries the mandatory per-request metadata under `params._meta`: `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities` (an empty object is legal). Over Streamable HTTP the tool name is additionally mirrored in the `Mcp-Name` header so intermediaries can route or authorize without parsing the body. If the named tool does not exist, that is a protocol-level failure and the server answers with a JSON-RPC error, not a result. If the tool exists and runs but fails at its own job — the upstream API returned 500, the file was not found — that failure is reported inside a successful result instead, so the model can read it. ## Designing schemas that work A few habits pay off: - Give every property a `description`. The model reads them. - Prefer `enum` over free-form strings for closed sets; it removes a whole class of invalid calls. - Mark only genuinely mandatory properties `required`; over-requiring makes the model invent values. - Keep the shape shallow. Deeply nested argument objects are filled in badly and are harder to show in a consent prompt. - Do not smuggle state into arguments implicitly. Every `tools/call` is self-contained; MCP 2026-07-28 is a stateless protocol and a server MUST NOT rely on earlier requests on the same connection to know what a call means. ## The output side `outputSchema` is the mirror image: when a tool declares one, its result must carry `structuredContent` conforming to that schema, alongside (or instead of) the human-readable `content` blocks. A tool with no `outputSchema` simply returns content blocks. ## Version note The `inputSchema` field itself has been stable across MCP revisions. What changed in 2026-07-28 is the surrounding envelope: results carry a required `resultType` (`"complete"` for an ordinary result), `ListToolsResult` carries the caching fields `ttlMs` and `cacheScope`, and there is no `initialize` handshake any more — capabilities and protocol version travel per request in `_meta`.
- If the client already validated the arguments against inputSchema, why should the server validate again?Because the published schema is documentation, not a gate. The MCP endpoint is reachable by anything that can send JSON-RPC, and a compromised or buggy client can send whatever it likes. The server validates its own inputs and answers a violation with JSON-RPC `-32602`, invalid params. Client-side validation is a latency and UX optimisation, never a security control.
- How does a property description in inputSchema change the model's behaviour?The description is part of what the host passes to the model, so it is the model's only guidance on what a property means. Naming a format ("ISO-8601 date"), a unit ("milliseconds"), or a closed set materially reduces malformed calls. Empty or misleading descriptions are the most common cause of a tool that "works" but is called wrongly.
- Can inputSchema reference external schemas via $ref to a URL?Don't. Clients and hosts inline the schema into a model-facing tool definition and generally do not dereference remote `$ref`s; a schema that cannot be understood standalone will be passed to the model incomplete, and fetching a URL at call time adds a failure and injection surface. Keep the schema self-contained, using local `$defs` if you need to share subschemas.
inputSchema is the function signature published in a header file: it tells the caller what to pass, but the function body still checks its own arguments.
saying these in an interview costs you the question
- Thinking inputSchema describes the tool's return value
- Assuming the client enforces the schema so the server need not
- Reporting schema violations as isError instead of -32602
- Leaving properties undescribed and blaming the model for bad calls
- Believing arguments carry over from a previous call on the connection