MCP tool schema reference
A reference for everything in an MCP tool definition and a tool result, as of spec 2026-07-28. Rules marked MUST, SHOULD or MAY come from the specification; everything else is labelled as advice.
The tool definition#
| Field | Required | What it's for |
|---|---|---|
name | Yes | Unique identifier used in tools/call |
title | No | Human-readable display name |
description | No (but needed in practice) | What the tool does. This is what the model reads to choose it. |
icons | No | Icons a client can show |
inputSchema | Yes | JSON Schema for the arguments |
outputSchema | No | JSON Schema for structuredContent in results |
annotations | No | Behaviour hints such as readOnlyHint |
Tool names#
- SHOULD be 1 to 128 characters long, and case-sensitive.
- SHOULD use only
A-Z,a-z,0-9, underscore, hyphen and dot. No spaces or commas. - SHOULD be unique within a server.
Advice: use verb_noun names such as search_orders or create_invoice, so the action is obvious from the name alone.
inputSchema#
- MUST be a valid JSON Schema object, not
null. - Any JSON Schema 2020-12 keywords are allowed. Schemas without
$schemadefault to 2020-12; a draft-07$schemais also allowed. - For a tool with no parameters, the spec recommends
{"type": "object", "additionalProperties": false}.
{
"type": "object",
"properties": {
"query": { "type": "string", "description": "Search text" },
"limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 }
},
"required": ["query"]
}Advice: describe every property, list only real properties in required, and use enum, minimum and maximum to stop the model guessing. Servers MUST still validate inputs; the schema is a contract, not a guarantee.
x-mcp-header#
New in 2026-07-28. Marking a property with x-mcp-header asks clients to copy its value into an Mcp-Param-* HTTP header, so gateways can route on it without parsing the body.
"region": {
"type": "string",
"description": "Data region",
"x-mcp-header": "Region"
}- The value MUST be a non-empty HTTP token, and unique within the tool ignoring case.
- Only properties of type
integer,stringorbooleancan use it, notnumber, objects or arrays. Integers must stay within the safe integer range. - Don't mark sensitive values. Headers are visible to proxies and logs.
outputSchema and structured results#
If a tool declares an outputSchema, the server MUST return structuredContent that conforms to it, and SHOULD also return the serialised JSON in a text content block for clients that don't read structured output. Clients SHOULD validate structured results against the schema.
Annotations#
readOnlyHint, destructiveHint, idempotentHint and openWorldHint describe behaviour. They're hints for well-behaved clients and are untrusted from unknown servers. See tool annotations explained for meanings and defaults.
The tool result#
A tools/call result has a content array, optional structuredContent, and isError. In 2026-07-28 every result also carries resultType, normally "complete". Content items can be:
text: plain textimageandaudio: base64 data with a MIME typeresource_link: a link to a resource the client can fetchresource: an embedded resource
{
"resultType": "complete",
"content": [{ "type": "text", "text": "{\"total_cents\": 4200, \"currency\": \"AUD\"}" }],
"structuredContent": { "total_cents": 4200, "currency": "AUD" },
"isError": false
}Two kinds of errors#
- Protocol errors are JSON-RPC errors for problems with the request itself, such as an unknown tool (
-32602). - Tool execution errors are normal results with
isError: true, for things like an API failure or invalid business input. Put an actionable message incontentso the model can correct itself and retry.
{
"resultType": "complete",
"content": [{ "type": "text", "text": "Order 1234 not found. Check the order number and try again." }],
"isError": true
}State across calls#
2026-07-28 has no protocol sessions. If tools need shared state, one tool returns an explicit handle (for example a basket_id) and later tools accept it as an argument. Handles aren't authentication: check the caller's authorization on every call. See security best practices.
Check your definitions#
The MCP tool linter checks names, inputSchema, x-mcp-header and annotations against these rules in your browser.
Frequently asked questions#
Is description required on an MCP tool?
The schema doesn't require it, but in practice the model chooses tools from their names and descriptions, so a tool without one is hard to use well. The linter flags missing and very short descriptions as guidance, not as spec errors.
Which JSON Schema version does MCP use?
JSON Schema 2020-12 by default. A schema can declare draft-07 with $schema.
Should errors be JSON-RPC errors or isError results?
Use JSON-RPC errors for protocol problems like an unknown tool, and isError: true results for failures while running the tool, so the model sees the message and can recover.