MCP Output Schema Error? Align structuredContent With outputSchema

MCP Output Schema Error? Align structuredContent With outputSchema

Aident AI

A translucent cobalt lattice, coral shell, cream core, and teal bridge align into one precise abstract contract.

MCP Output Schema Error? Align structuredContent With outputSchema

If an MCP client says a tool "has an output schema but did not return structured content" or that structured content does not match the output schema, do not retry the same call. The server declared one result contract and returned another. Capture the advertised outputSchema, capture the raw tools/call result, validate structuredContent against that exact schema, and fix the producer or adapter that changed the shape.

For a successful tool call, the invariant is simple:

declared outputSchema == actual structuredContent shape

The human-readable content field is useful, but it does not satisfy a declared structured result contract by itself.

Identify Which Output Contract Failed

The error wording usually points to one of three boundaries.

Symptom

What it means

First check

has an output schema but did not return structured content

The successful result omitted structuredContent

Raw tools/call result

Structured content does not match the tool's output schema: data...

A key, type, required field, enum, or nesting level does not match

Validator error path plus the advertised schema

The original tool error is replaced by an output-schema validation failure

An SDK or adapter validated an error result as if it were success

isError, SDK version, and client behavior

These are response-contract failures. They are different from invalid tool arguments, authentication failures, timeouts, and provider errors. A generic retry loop cannot repair them.

Know What MCP Requires

The current MCP tools specification separates three fields:

  • outputSchema is the JSON Schema advertised with the tool definition.

  • structuredContent is the server-produced JSON value that machines consume.

  • content is the unstructured result shown to models and people.

When outputSchema exists, a successful server result must include structured data that conforms to it, and clients should validate that data. The current specification allows any JSON value, including an object, array, string, number, boolean, or null. If $schema is omitted, MCP uses JSON Schema 2020-12.

For compatibility, the specification also recommends returning serialized JSON in a text content block. That fallback helps clients that do not consume structured results, but it is not a substitute for structuredContent when an output schema is declared.

Capture the Definition and Result From the Same Run

Do not compare a cached schema with a new result. Tool lists can change after a server release, proxy transformation, or connection refresh.

Preserve these four artifacts from one failing session:

  1. The negotiated MCP protocol version.

  2. The exact tool definition from tools/list, including outputSchema.

  3. The raw tools/call result before a model or UI transforms it.

  4. The full validation path, with secrets and personal data redacted.

Then answer two questions:

Did the successful result contain structuredContent?
Did that JSON value validate against the schema advertised in the same session

If either answer is no, the failure is already isolated to the server, an integration adapter, or a client-side transformation. It is not evidence that the provider operation itself should run again.

Build One Result Object, Then Render It Twice

The safest implementation creates one typed value and uses it as the source for both result surfaces.

server.registerTool(
  'get_order',
  {
    outputSchema: z.object({
      id: z.string(),
      status: z.enum(['pending', 'paid', 'shipped']),
      total: z.number(),
    }),
  },
  async () => {
    const output = {
      id: 'ord_123',
      status: 'paid' as const,
      total: 42.5,
    };

    return {
      structuredContent: output,
      content: [{ type: 'text', text: JSON.stringify(output) }],
    };
  },
);

This avoids two independently maintained shapes. It also makes contract tests straightforward: validate output, then verify the serialized fallback represents the same value.

Do not build structuredContent from one mapper and content from another. That duplication invites field renames, default handling, and nullability to drift between surfaces.

Read the Validator Path Literally

Most schema mismatch messages contain the fastest route to the bug.

Validator path or keyword

Typical cause

Repair

must have required property

Serializer omitted a required field or applied a default late

Include the field or make the schema accurately optional

must be array

The handler returned an object wrapper or empty fallback

Return the array at the declared path

must be string

Number, boolean, or null crossed an adapter boundary

Fix serialization or widen the schema only if contractually valid

must be equal to one of...

Runtime value is outside the enum

Update the producer or version the contract deliberately

must NOT have additional...

Provider added a field under a closed schema

Normalize once or intentionally expand the schema

Do not weaken the schema until the error disappears. First decide whether the runtime value is wrong or the declared contract is stale. A permissive schema can hide a breaking provider change and pass malformed data downstream.

Keep Tool Errors Out of the Success Shape

An execution error is not a successful output with placeholder fields. Return a tool error through isError: true and place the actionable message in content.

return {
  isError: true,
  content: [{ type: 'text', text: 'Order ord_123 was not found' }],
};

The current official TypeScript SDK error guidance says output-schema validation is skipped when isError is true. Historical SDK defects did not always preserve that boundary. The closed TypeScript SDK issue 654 documents a server-side case where output validation hid the original error, while an open client consistency issue tracks differences in how clients consume content and structuredContent.

If a valid isError: true result is still replaced by a schema error, reproduce it with the newest compatible SDK before changing the tool contract. Record the client and server versions because that behavior can be version-specific.

Test the Contract at Three Layers

A unit test alone can prove the handler's object is valid while missing a transport or adapter bug. Test the same fixtures at three boundaries.

1. Handler contract

Validate representative success values directly against the schema. Include:

  • the smallest valid result;

  • a normal populated result;

  • empty arrays and empty strings when allowed;

  • every nullable field;

  • enum boundaries; and

  • an intentional missing-field fixture that must fail.

2. MCP wire contract

Call the tool through a real client and assert that:

  • the advertised outputSchema is the expected version;

  • the result contains structuredContent on success;

  • the value passes the same JSON Schema draft;

  • the text fallback is present; and

  • an intentional tool error arrives with isError: true instead of a schema exception.

3. Host compatibility

Run the server in the clients you support. Some older clients ignore structured content, some validate it, and some display only text. A matching structured value plus a useful text fallback serves all three behaviors.

The Go SDK issue 386 is a useful example of why this final layer matters: a result shape that looked reasonable in server code still produced a client validation error because the returned value at sessions was not the declared array.

Inspect an Integration Contract Before Execution

If the mismatch appears in an integration-backed Action, inspect the current catalog contract before running the provider again.

Start with the canonical setup instruction:

Follow https://aident.ai/SETUP.md

Then keep the investigation read-only:

aident account auth status
aident vault vault --action status

aident capabilities search \
  --query "describe the operation you need" \
  --types '["action"]'

ACTION_NAME="copy-the-exact-canonical-name-from-search"

aident capabilities get \
  --name "$ACTION_NAME" \
  --parts '["description","inputSchema","outputSchema","examples"]'

aident capabilities preflight \
  --name "$ACTION_NAME" \
  --input '{"replace":"with redacted, schema-valid input"}'

Search discovers the current Action, get exposes its contract, and preflight validates input and quotes cost without dispatching the provider. None of these steps proves that a live result matches outputSchema, but they establish which result contract the runtime currently advertises.

Do not execute a write merely to reproduce an output mismatch. Prefer a documented read-only fixture, a mocked provider response, or a previously captured redacted result.

Use a Release Gate for Every Output-Schema Change

Treat a changed output schema like an API change.

Before release:

  1. Diff the old and new schemas.

  2. Classify required-field, type, enum, nesting, and closed-object changes.

  3. Test old clients against the new server when compatibility matters.

  4. Test the error path separately from success.

  5. Pin a raw tools/list and tools/call fixture in CI.

  6. Roll out the schema and result producer together.

If consumers cannot upgrade atomically, expand the result contract first or version the tool. Do not deploy a required field before every producer can populate it.

Fix the Contract, Not the Retry Count

An MCP output-schema failure is deterministic evidence: the declared contract and returned value disagree. Save the exact schema and raw result, repair one source of truth, preserve a serialized text fallback, and test both success and isError paths through a real client.

Next, use the MCP Inspector testing guide to capture the wire contract. If discovery is wrong before execution, follow the empty TypeScript inputSchema guide or the stringified tool arguments guide instead.

Set up Aident Loadout and inspect one Action contract. Keep the run read-only until the advertised result schema and failure boundary are clear.

Sources

Refresh this article when MCP changes the tool result contract or default JSON Schema draft, the official SDKs change error-validation behavior, or supported clients converge on a different compatibility rule.

Home

Home

Home

Integrations

Integrations

Integrations

Vault

Vault

Vault

Audit

Audit

Audit

Arana Grande

Arana Grande

Arana Grande

Free

Free

Free

30-day audit summary

30-day audit summary

30-day audit summary

Daily action-call volume and the latest receipts from the Loadout audit trail.

Daily action-call volume and the latest receipts from the Loadout audit trail.

Daily action-call volume and the latest receipts from the Loadout audit trail.

View Audit

View Audit

View Audit

Loadout usage

Loadout usage

Loadout usage

617 action calls in the last 30 days

617 action calls in the last 30 days

617 action calls in the last 30 days

May 19 - Jun 17

May 19 - Jun 17

May 19 - Jun 17

10 active days

10 active days

10 active days

Less

Less

Less

More

More

More

Recent activity

Recent activity

Recent activity

Latest action-call receipts from connected agents

Latest action-call receipts from connected agents

Latest action-call receipts from connected agents

Apr 23, 09:23 AM

Apr 23, 09:23 AM

Apr 23, 09:23 AM

Shopify

Shopify

Shopify

Creates Or Updates An Asset For A Theme

Creates Or Updates An Asset For A Theme

Creates Or Updates An Asset For A Theme

Success

Success

Success

Apr 23, 09:21 AM

Apr 23, 09:21 AM

Apr 23, 09:21 AM

Shopify

Shopify

Shopify

Update Products Param Product Id

Update Products Param Product Id

Update Products Param Product Id

Success

Success

Success

Apr 23, 08:53 AM

Apr 23, 08:53 AM

Apr 23, 08:53 AM

Shopify

Shopify

Shopify

Update Products Param Product Id

Update Products Param Product Id

Update Products Param Product Id

Failed

Failed

Failed

Apr 22, 22:13 PM

Apr 22, 22:13 PM

Apr 22, 22:13 PM

Shopify

Shopify

Shopify

Create Product Image

Create Product Image

Create Product Image

Success

Success

Success

Apr 22, 22:12 PM

Apr 22, 22:12 PM

Apr 22, 22:12 PM

Shopify

Shopify

Shopify

Create Product Image

Create Product Image

Create Product Image

Success

Success

Success

Connected integration coverage

Connected integration coverage

Connected integration coverage

162

162

162

of 753 accessible connected

of 753 accessible connected

of 753 accessible connected

Callable actions

Callable actions

Callable actions

1,126

1,126

1,126

Vault credentials

Vault credentials

Vault credentials

8

8

8

Explore what's possible

Explore what's possible

Explore what's possible

See all Integrations

See all Integrations

See all Integrations

Google Ads

Google Ads

Google Ads

All available Goolge Ads tools via...

All available Goolge Ads tools via...

All available Goolge Ads tools via...

X (twitter)

X (twitter)

X (twitter)

All available X tools via...

All available X tools via...

All available X tools via...

Github

Github

Github

All available Github tools via...

All available Github tools via...

All available Github tools via...

Notion

Notion

Notion

All available Notion tools via...

All available Notion tools via...

All available Notion tools via...

Slack

Slack

Slack

All available Slack tools via...

All available Slack tools via...

All available Slack tools via...

Firecrawl

Firecrawl

Firecrawl

All available Firecrawl tools via...

All available Firecrawl tools via...

All available Firecrawl tools via...

753 integrations are available for loadouts.

753 integrations are available for loadouts.

753 integrations are available for loadouts.

The one tool

for every tool

your agent needs.

Give any AI agent real capabilities in seconds. Connect 1,000+ tools once, skip the setup headache, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.

Try Aident Loadout

Give your Agent real capabilities in minutes. Connect 1,000+ tools, and let your agents execute.