MCPmatic

MCP tool schema reference

Published · Updated · Written against MCP spec 2026-07-28

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#

FieldRequiredWhat it's for
nameYesUnique identifier used in tools/call
titleNoHuman-readable display name
descriptionNo (but needed in practice)What the tool does. This is what the model reads to choose it.
iconsNoIcons a client can show
inputSchemaYesJSON Schema for the arguments
outputSchemaNoJSON Schema for structuredContent in results
annotationsNoBehaviour 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 $schema default to 2020-12; a draft-07 $schema is 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, string or boolean can use it, not number, 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 text
  • image and audio: base64 data with a MIME type
  • resource_link: a link to a resource the client can fetch
  • resource: 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 in content so 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.

Sources#