MCP outputSchema Validation Failures: Why Structured Output Breaks and How to Fix It (2026)
MCP outputSchema validation errors are breaking tools across IBM ContextForge, WooCommerce, edgartools, mastra-ai, and more. Learn the 5 failure patterns and exact fixes for 2026.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →MCP outputSchema Validation Failures: Why Structured Output Breaks and How to Fix It (2026)
If you've added outputSchema to your MCP tool definition and started seeing errors like Tool has an output schema but no structured content was provided or Structured content does not match the tool's output schema, you're not alone.
Since the MCP 2025-06-18 specification formalized outputSchema and structuredContent, a wave of validation failures has hit projects across the ecosystem — IBM ContextForge (#4042, #4202), WooCommerce (#64195), edgartools (#662), mastra-ai (#5488), TypeScript SDK (#654, #911), and Claude Code (#14465).
With the MCP Python SDK v2 beta dropping June 30 and the full RC on July 28, this is the worst possible time for your tools to be throwing schema errors. Here's what's breaking and how to fix it.
What Is outputSchema in MCP?
The MCP 2025-06-18 specification added optional outputSchema to tool definitions. When declared, the server must return structured output in the structuredContent field that conforms to that schema:
{
"tools": [{
"name": "get_user",
"description": "Fetch a user record",
"inputSchema": { "type": "object", "properties": { "id": { "type": "string" } }, "required": ["id"] },
"outputSchema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"email": { "type": "string" }
},
"required": ["id", "email"]
}
}]
}
A conforming tools/call response looks like this:
{
"content": [{ "type": "text", "text": "User fetched" }],
"structuredContent": { "id": "u123", "email": "[email protected]" }
}
The rule: if outputSchema is declared, structuredContent must be present and schema-valid. Every SDK that validates this contract strictly will reject anything that doesn't match — and with the v2 beta, that validation is getting stricter.
The 5 Failure Patterns (and Exact Fixes)
Pattern 1: Tool returns text content but declares outputSchema
The error:Tool has an output schema but no structured content was provided
Output validation error: outputSchema defined but no structured output returned
What happened: You added outputSchema to your tool definition but the handler still returns only content (text), not structuredContent. The SDK validates that if a schema is declared, conforming content must be present — and it isn't.
GitHub instances: edgartools#662, mastra-ai#5488
Fix — Option A: Remove outputSchema (fastest)
If you don't need typed structured responses, remove outputSchema from your tool definition entirely. The client falls back to text content, which is always safe.
# Before (breaks — outputSchema declared but handler returns text)
@mcp.tool(output_schema={"type": "object", "properties": {"id": {"type": "string"}}})
def get_user(user_id: str) -> str:
return json.dumps(fetch_user(user_id)) # Returns string, not structuredContent
After (safe — no outputSchema, text content always valid)
@mcp.tool()
def get_user(user_id: str) -> str:
return json.dumps(fetch_user(user_id))
Fix — Option B: Return structuredContent (correct implementation)
If you need typed output, update your handler to return both content and structuredContent:
from mcp.types import CallToolResult, TextContent
@mcp.tool(output_schema=UserSchema.model_json_schema())
async def get_user(user_id: str) -> dict:
user = await fetch_user(user_id)
return {
"content": [TextContent(type="text", text=f"Fetched user {user_id}")],
"structuredContent": user.model_dump()
}
Pattern 2: structuredContent shape doesn't match outputSchema
The error:-32602: Structured content does not match the tool's output schema
What happened: Your handler returns structuredContent, but the shape doesn't match the declared outputSchema. Common causes: missing required fields, wrong types, extra properties when additionalProperties: false is set.
GitHub instances: WooCommerce#64195, TypeScript SDK#911
Diagnosis — validate your output against your schema:
import jsonschema
output_schema = your_tool_definition["outputSchema"]
structured_content = your_handler_result["structuredContent"]
try:
jsonschema.validate(structured_content, output_schema)
print("Schema valid")
except jsonschema.ValidationError as e:
print(f"Schema mismatch: {e.message}")
print(f"At path: {' > '.join(str(p) for p in e.absolute_path)}")
Common shape mismatches and fixes:
# ❌ Schema says required: ["id", "name"] but you return:
{"structuredContent": {"id": "u123"}} # Missing "name"
✅ Fix: include all required fields
{"structuredContent": {"id": "u123", "name": "Dev User"}}
❌ Schema says type: "number" but you return:
{"structuredContent": {"count": "42"}} # String, not number
✅ Fix: return the correct type
{"structuredContent": {"count": 42}}
❌ Schema says additionalProperties: false but you return:
{"structuredContent": {"id": "u123", "name": "Dev User", "debug_info": "..."}}
✅ Fix: strip undeclared properties
{"structuredContent": {"id": "u123", "name": "Dev User"}}
Paste your structuredContent and outputSchema into the AI JSONMedic repair tool — it validates the content against the schema and shows the exact mismatched fields.
Pattern 3: Error responses fail outputSchema validation
The error:Output validation error: isError response fails schema validation
What happened: Some SDK or gateway implementations validate every tools/call response against outputSchema, including responses where isError: true. Per the MCP spec, error responses should not be validated against outputSchema — but some implementations (notably IBM ContextForge pre-fix) apply validation unconditionally.
GitHub instances: IBM ContextForge#4202
Fix — ensure error responses omit structuredContent:
# ✅ Correct error response format — omit structuredContent entirely
if error_occurred:
return {
"content": [TextContent(type="text", text=f"Error: {error_message}")],
"isError": True
# No structuredContent — error responses are exempt from outputSchema validation
}
If you're using a gateway like ContextForge, check the version — the unconditional validation was a regression in v1.0.0-RC2 and later patched. Pin to a release after the fix.
Pattern 4: Proxy strips or doesn't forward structuredContent
The error:Tool has an output schema but no structured content was provided
What happened: A proxy or remote adapter (e.g., @automattic/mcp-wordpress-remote) sits between your MCP server and the client. The proxy passes through outputSchema in tools/list responses, but doesn't forward structuredContent in tools/call responses — so the client sees a declared schema with no conforming structured content.
GitHub instances: WooCommerce#64195
Workaround — strip outputSchema at the proxy layer:
The fastest fix is to strip outputSchema from tool definitions before forwarding, so clients never expect structuredContent:
// In your proxy's tools/list handler
const tools = await upstream.listTools();
return {
tools: tools.map(tool => {
const { outputSchema, ...rest } = tool;
return rest; // Drop outputSchema until proxy relays structuredContent end-to-end
})
};
This forces clients to use the text content fallback — always present, always valid.
Pattern 5: TypeScript SDK version mismatch — Zod union schema generation changed
The symptom: Tools silently drop structured output or clients reject calls with schema errors. What happened: TypeScript SDK v1.26.0+ changed how Zod union types (z.union([...])) convert to JSON Schema — from anyOf to oneOf. If your client was built against an older SDK and your server runs a newer one (or vice versa), the schema shape doesn't match across the connection.
GitHub instances: TypeScript SDK#654
This is the same Zod→schema generation change that breaks Anthropic tool definitions (detailed in our Anthropic tool schema validation errors guide).
Fix — pin SDK version and use explicit schemas:// package.json — pin both client and server to the same SDK version
{
"dependencies": {
"@modelcontextprotocol/sdk": "1.25.0"
}
}
Better long-term: use explicit JSON Schema instead of Zod-generated output schemas to avoid SDK version sensitivity:
// Instead of Zod union (behavior changes across SDK versions):
const ResultSchema = z.union([SuccessSchema, ErrorSchema]);
// Use explicit JSON Schema (stable across all SDK versions):
const outputSchema = {
anyOf: [
{
type: "object",
properties: { success: { type: "boolean", const: true }, data: { type: "object" } },
required: ["success", "data"]
},
{
type: "object",
properties: { success: { type: "boolean", const: false }, error: { type: "string" } },
required: ["success", "error"]
}
]
};
Safe outputSchema Template for 2026
This template avoids every known failure pattern:
{
"name": "safe_tool",
"description": "A tool with a safe, compatible outputSchema",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"],
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"properties": {
"result": { "type": "string" },
"status": { "type": "string", "enum": ["ok", "partial"] }
},
"required": ["result", "status"],
"additionalProperties": false
}
}
Python handler:
@mcp.tool(output_schema=safe_output_schema)
async def safe_tool(query: str):
data = await process(query)
if data.error:
return {
"content": [TextContent(type="text", text=f"Error: {data.error}")],
"isError": True
# No structuredContent — error responses skip outputSchema validation
}
return {
"content": [TextContent(type="text", text=f"Processed: {query}")],
"structuredContent": {
"result": data.value,
"status": "ok"
}
}
Decision rule for whether to use outputSchema at all:
| Scenario | Recommendation |
|---|---|
| Direct server→client, matched SDK versions | outputSchema is safe |
| Tool called through a proxy or remote adapter | Skip outputSchema until proxy supports structuredContent relay |
| Mixed SDK versions across client and server | Use explicit JSON Schema, not Zod-generated schemas |
| Any doubt about compatibility | Remove outputSchema, use text content |
Validate Before the June 30 Beta
Before the MCP Python SDK v2 beta ships, run this check against every tool that declares outputSchema:
import json
import jsonschema
def validate_tool_output(tool_definition: dict, sample_output: dict) -> bool:
"""Validate sample structuredContent against the tool's outputSchema."""
output_schema = tool_definition.get("outputSchema")
if not output_schema:
return True # No schema declared = always valid
try:
jsonschema.validate(sample_output, output_schema)
print(f"✅ {tool_definition['name']}: structuredContent schema valid")
return True
except jsonschema.ValidationError as e:
print(f"❌ {tool_definition['name']}: {e.message}")
print(f" Path: {' > '.join(str(p) for p in e.absolute_path)}")
return False
Run against all your tools
for tool, sample in tools_with_samples:
validate_tool_output(tool, sample)
Or paste your structuredContent JSON into the AI JSONMedic repair tool — it runs schema validation inline and shows mismatched fields with plain-English error messages.
MCP SDK Timeline: What Changes June 30 and July 28
June 30, 2026 — MCP Python SDK v2 beta:outputSchemavalidation becomes stricter in Python SDK v2- Tools that currently produce silent errors may start throwing loudly
- Test your tools against the v2 beta:
pip install "mcp>=2.0.0b1" - The
output_schemaparameter in FastMCP validates on every call — no more silent drops
- Full JSON Schema 2020-12 support:
oneOf,anyOf,allOfare all valid and preserved - Existing normalization code that strips
oneOf/anyOfwill break valid schemas after July 28 - Review your schema-normalization middleware before this date
See our MCP 2026 JSON Schema Migration Checklist for the full July 28 preparation guide.
Frequently Asked Questions
Is outputSchema required in MCP tools?
No. outputSchema is entirely optional. If omitted, the client uses the text content field — which is always present and always valid. Only add outputSchema if you specifically need typed, schema-validated structured responses that clients can process programmatically.
Why does removing outputSchema fix the validation error immediately?
The MCP spec says: if outputSchema is declared, structuredContent must be present and conform to it. Removing outputSchema tells the SDK there's no structured output contract to validate — the tool falls back to text content, which is always safe. It's the fastest fix when you need to unblock a deployment.
Does outputSchema work reliably behind a proxy?
Not with most current proxy implementations. Proxies typically pass through outputSchema in tools/list but don't relay structuredContent in tools/call responses. The client sees a schema declaration with no conforming content and throws. Strip outputSchema at the proxy layer until your proxy explicitly supports structured content passthrough.
What changed in TypeScript SDK v1.26.0 that broke Zod schemas?
SDK v1.26.0+ changed how z.union([...]) converts to JSON Schema — from anyOf to oneOf. If client and server use different SDK versions, the schema shape the client expects doesn't match what the server generates. Pin both to the same version, or switch to explicit JSON Schema definitions for outputSchema.
Will error responses (isError: true) always skip outputSchema validation?
Per the MCP spec, error responses are meant to be exempt from outputSchema validation. However, some gateway implementations (like IBM ContextForge pre-patch) validate unconditionally. To be safe: always omit structuredContent from error responses, and confirm your gateway/SDK version has the correct exemption behavior.
How do I find which specific field is failing schema validation?
Run jsonschema.validate(structured_content, output_schema) in Python and read the ValidationError.absolute_path — it gives the exact JSON path to the failing field. Alternatively, paste the content into the AI JSONMedic JSON repair tool, which runs validation inline and highlights mismatched fields.
Summary
| Pattern | Error message | Fix |
|---|---|---|
| Text-only handler, outputSchema declared | no structured content provided | Remove outputSchema or add structuredContent to response |
| structuredContent shape mismatch | -32602: does not match schema | Validate output against schema, fix missing/wrong-type fields |
| Error response fails validation | Schema validation on isError: true | Omit structuredContent from all error responses |
| Proxy doesn't forward structuredContent | no structured content provided | Strip outputSchema at proxy layer |
| SDK version mismatch, Zod union changed | Schema rejection or silent drop | Pin SDK versions, use explicit JSON Schema |
The safest path for June 2026: don't add outputSchema unless you've tested end-to-end with matched SDK versions and no proxy. When you do add it, validate your structuredContent against your schema before deploying — or let AI JSONMedic catch the mismatch for you.
Related: Anthropic Tool Schema Validation Errors · MCP JSON Schema Errors: Complete Fix Guide · MCP Python SDK v2 Beta · MCP 2026 JSON Schema Migration
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles