A tool call result in MCP has always been a content array — blocks of text, images, or embedded resources, built for a model to read. That’s fine when the answer is prose. It’s awkward when the answer is a row of data: a server that looks up an order or runs a search has to serialize that data into a JSON string, wrap it in a text block, and hope the model parses it back out correctly. MCP structured output is the protocol’s fix — a tool can declare the shape its result will take, and the result can carry that data as real, typed JSON alongside the text block, not instead of it.

How it actually works

A tool definition can include an outputSchema field — a JSON Schema describing the shape of what the tool returns, the same way inputSchema already describes a tool’s arguments. When a tool like that is called, its result can include a structuredContent field: an actual JSON object matching that schema, not a string a model has to parse. The spec still requires the ordinary content array to be present too, usually carrying the same data serialized as text, so a client that has no idea what structuredContent is can keep working exactly as it did before. Nothing about this changes how tools, resources, and prompts relate to each other — it’s a refinement of what a tool result can look like, not a new primitive.

The point of declaring outputSchema in the first place is that a client can validate a result against it before trusting it, and can build real UI off a known shape instead of pattern-matching on text. A tool that returns a list of invoices can describe exactly which fields each invoice carries and what type each one is, and a client that reads that schema ahead of time knows what to expect before the first real call ever happens.

What problem this actually solves

Before structured output, a server returning anything data-shaped had two bad options: stuff JSON into a text block and hope the model’s parse of it is faithful, or invent its own ad hoc convention and document it outside the protocol. Both work until they don’t — a model drops a field summarizing a long result, miscounts a list, or just gets the JSON slightly wrong when it has to retype it. A typed, schema-described result removes the retyping step entirely: the data a client renders or hands downstream is the data the server actually produced, not the model’s recollection of it.

It also gives a client something to validate before it acts on a result, which is a different and narrower guarantee than the tool annotations we covered in readOnlyHint, destructiveHint, and why they’re only hints. An annotation describes how risky a tool’s own behavior might be; outputSchema describes what shape a successful result takes. Neither one says anything about the other, and a tool can declare a precise output schema while still being exactly as destructive, or as safe, as it ever was.

What it doesn’t give you

Declaring an outputSchema doesn’t make a server honest. Nothing forces thestructuredContent a server actually returns to match the schema it advertised — validation is something a client has to choose to do, not something the protocol enforces for you. A server can publish a clean schema and then return a result that doesn’t satisfy it, the same way a tool’s description can claim a behavior the tool doesn’t actually have.

It’s also not universally supported yet. A client that predates structured output, or simply hasn’t implemented the validation and rendering side of it, will fall back to the plain content block every tool result still has to carry — which is why that field stays mandatory rather than becoming optional once structuredContent exists. Treat structured output as a quality improvement a well-built client can take advantage of, not as something you can assume every client on the other end of a connection will use.

Where this actually shows up

Structured output earns its keep on tools whose result is naturally tabular or record-shaped — a search that returns matches, a lookup that returns one record, a status check that returns a fixed set of fields. It does almost nothing for a tool whose job is to produce prose: a summarizer, a draft-writer, anything where the useful output is text a person reads, not data a program consumes further. If you’re evaluating a server from gate’s MCP server directory, whether it declares output schemas is a reasonable signal of how carefully its tools were built, but it says nothing about whether the server is safe to connect — that’s still a question for gate’s free MCP security scanner, not the shape of a result.

If you build a server

Add an outputSchema wherever a tool’s result is genuinely structured data — it costs little to write once you already know the shape, and it makes your server easier to integrate against correctly. Keep the schema honest: a schema that’s wider than what you actually return, or that drifts out of sync after you change a field, defeats the whole point and leaves client-side validation either too loose to catch real problems or too strict to pass. If you’re generating a server from an existing API with gate’s MCP server builder, this is one place the underlying OpenAPI spec usually already has what you need — a response schema maps naturally onto outputSchema, which is more than can be said for the gaps we’ve noted before in turning an API into an MCP server, like sampling or subscriptions, that an API definition has no way to express at all.

Where a gateway fits: a typed result is still just a result — it doesn’t change who’s allowed to call the tool that produced it or what happens to the data afterward. The per-tool allow, ask, or block rules in a gateway apply the same way to a tool that returns clean, schema-validated JSON as to one that still hands back a wall of text, and the plain-language log a gateway keeps doesn’t care which shape a given call used either.

The bottom line

Structured output gives a tool a way to declare its result’s shape and return real JSON matching it, instead of leaving a model to parse that shape back out of text every time. It’s a quality-of-implementation detail, not a trust signal and not a new primitive — worth adding when you build a data-shaped tool, and worth checking for when you’re choosing between servers that do similar things. See our tools, resources, and prompts guide for how this fits into MCP’s broader primitive model.