Home · Guides

Declaring an output schema is a promise the server has to keep

An MCP tool result can carry machine-readable data in structuredContent alongside the human-readable content blocks. A tool may also declare an outputSchema. The two together create an obligation, quoted from the specification, revision 2026-07-28:

Servers MUST provide structured results that conform to this schema. Clients SHOULD validate structured results against this schema.

So an outputSchema is not documentation. Declare one and every result has to satisfy it, including the awkward cases: an empty list, a partial result, a value your upstream returned as null.

The three fields

FieldWhereWhat it is
inputSchemaTool definitionRequired. MUST be a valid JSON Schema object, never null.
outputSchemaTool definitionOptional. Constrains structuredContent.
structuredContentTool resultAny JSON value: object, array, string, number, boolean or null.

Both schemas default to JSON Schema draft 2020-12 when no $schema field is present, and an explicit $schema selects another draft. For a tool that takes no parameters the specification recommends { "type": "object", "additionalProperties": false }, which accepts an empty object and nothing else. { "type": "object" } is also valid and accepts any object.

Return the JSON twice

The specification asks for backwards compatibility: a tool that returns structured content SHOULD also return the serialized JSON in a text content block. Clients written before structured content existed, and clients that never implemented it, read content and nothing else. A result with only structuredContent looks empty to them.

{
  "content": [{ "type": "text", "text": "{\"basket_id\":\"bsk_a1b2c3\"}" }],
  "structuredContent": { "basket_id": "bsk_a1b2c3" }
}

The name collision worth knowing about

The specification says it plainly: structuredContent is server-produced result data and is unrelated to model "structured outputs", meaning schema-constrained generation by a language model. Same words, different mechanism. One is your server returning JSON it built. The other is a model being forced to emit JSON. Nothing in MCP constrains what the model does with your result.

When to declare an output schema

Declare one when the caller is code. A schema lets a client validate, a directory show the shape, and a downstream tool consume the result without parsing prose. Skip it when the honest answer is a free-form document, and skip it when the shape varies with the arguments in a way a single schema cannot express, because a schema you sometimes violate is worse than none: the client is told to validate, and validation failures are yours.

The other reason to be careful is error results. A result with isError: true still travels in the same envelope, so decide whether your schema describes success only, and if it does, do not attach structured content to failures.

Related result fields in this revision

Results in revision 2026-07-28 carry a resultType, with complete for an ordinary answer and input_required for a call that needs more from the user before it can finish. The second returns an inputRequests map and an opaque requestState, and the client retries the call with inputResponses. The specification notes that the JSON-RPC id MUST differ between the first request and the retry.

Source: the tools section of the MCP specification, revision 2026-07-28, at modelcontextprotocol.io, fetched 2026-09-09. Every MUST and SHOULD above is quoted or paraphrased from that page, and the schema defaults and the no-parameter forms are its recommendations.

Questions

Is structuredContent supported everywhere?

Not reliably, which is why the specification asks you to duplicate the JSON as text. Clients advertise a protocol version at initialize, and older versions predate the field entirely. Sending both costs a few hundred bytes and works everywhere.

Can structuredContent be an array?

Yes. It is any JSON value, including an array, a bare string or null. If you declare an outputSchema, the schema has to describe whatever you actually send, so a top-level array needs a schema with type array.

What happens if my result violates my own outputSchema?

The specification says clients SHOULD validate, so behaviour varies from ignoring it to rejecting the result. Neither is good for you. Validate against your own schema in your tests, on the same code path that builds the result.

Does inputSchema have to describe every argument?

It has to be a valid JSON Schema object, and it is what the model reads when deciding how to call you. Leaving arguments undescribed means the model guesses. Marking additionalProperties false on a no-argument tool is the recommended way to say that plainly.

Which JSON Schema draft should I write?

2020-12 is the default when no $schema is present, so writing 2020-12 and omitting the field is the least surprising choice. Set $schema explicitly only when you need an older draft, and then set it on that schema rather than assuming a server-wide default.

Related

All MCP servers and prices · All guides · Buy the bundle $39