Research guide · MCP tool schemas · updated 13 September 2026
MCP outputSchema unsupported dialect: fix draft-07 vs 2020-12 errors
If tools/list succeeds but a tool call immediately fails with “invalid outputSchema” or “unsupported dialect”, check the JSON Schema dialect before rewriting the tool. A second failure class looks similar but is different: the call succeeds on the wire and structuredContent disappears later in the client pipeline. This guide separates those boundaries.
Published 13 September 2026 · refreshed 13 September 2026
2020-12
MCP default JSON Schema dialect when $schema is absent
draft-07
Permitted when explicitly declared, but not universally implemented
tools/list
First place to inspect the schema actually advertised on the wire
structuredContent
Machine-readable result channel after a call is dispatched
Fast diagnosis
First decide whether the tool was rejected before dispatch
| Observed signal | Likely boundary | First action |
|---|---|---|
| tools/list succeeds; every tool call fails with unsupported dialect | Client-side JSON Schema dialect validation | Inspect outputSchema.$schema before changing tool business logic. |
| $schema is draft-07; client supports only 2020-12 | Server/client dialect mismatch | Prefer a real 2020-12 emission path; do not blindly relabel a non-equivalent schema. |
| Raw response has no structuredContent | Server or server-SDK serialization boundary | Inspect the exact tools/call result before changing the client. |
| Raw response has structuredContent; model cannot see it | Client, bridge or model-transcription boundary | Compare transport evidence with the model-visible function result. |
| Array/scalar result fails but object works | Older object-only assumption | Verify the negotiated revision and the tool's declared schema. |
| Returned structured value fails outputSchema validation | Result does not match its published contract | Validate the exact returned JSON against the advertised schema and dialect. |
Protocol boundary
MCP requires 2020-12 support, not 2020-12-only schemas
MCP's JSON Schema rules make 2020-12 the default when $schema is absent. A schema may explicitly declare another dialect. Implementations must support at least 2020-12, and when they do not support an explicitly declared alternative they should fail with an appropriate unsupported-dialect error.
That distinction matters. A draft-07 outputSchema is not automatically invalid MCP. But a server that advertises draft-07 can still be unusable in a client whose validator only implements 2020-12. The practical fix is interoperability: emit a schema the target client can correctly validate, or use a client that honors the declared dialect.
The 2026-07-28 specification also expands tool schemas to the full JSON Schema 2020-12 vocabulary. That makes honest dialect conversion more important: new constructs such as $defs, conditionals and composition should not be silently relabeled as an older or newer dialect without checking semantics.
Fresh implementation evidence
A current TypeScript SDK issue reproduces draft-07 emission against strict clients
TypeScript SDK issue #2795, opened 12 September 2026, reproduces registerTool advertising http://json-schema.org/draft-07/schema# and tracks older open issues and fixes around the same emission path. The reporter notes that SDK-side tolerance for draft-07 does not solve rejection by a different strict client.
Independent client reports in August 2026 show the exact high-intent symptom: tools are discovered successfully, then invocation fails before the request reaches the MCP server because the client rejects a draft-07 outputSchema. Reports span multiple MCP servers, which is a strong signal to inspect the schema boundary rather than one server's business logic.
Treat those reports as implementation evidence, not a protocol rewrite. MCP explicitly permits a declared alternative dialect; the compatibility failure occurs when the consuming implementation does not support that dialect.
Safe repair sequence
Fix the dialect without lying about the schema
- 1. Capture
tools/list. Record the exactinputSchemaandoutputSchemathat leave the server. Do not infer them from your Zod or framework source. - 2. Read
$schema. If it is absent, MCP treats the schema as 2020-12. If it explicitly says draft-07, a 2020-12-only client can reject it before dispatch. - 3. Confirm where the failure occurs. If no
tools/callreaches the server, changing handler logic orstructuredContentcannot fix a client-side schema-registration failure. - 4. Prefer native 2020-12 generation. Use the SDK/schema-library path that actually generates 2020-12 rather than post-processing the label when one is available.
- 5. If you must rewrite on the wire, prove equivalence. Test every advertised schema for dialect-sensitive constructs. A changed
$schemastring is safe only when the schema means the same thing under the target dialect. - 6. Add an interoperability test. Assert the advertised dialect and validate the emitted schema with the same class of validator your target client uses. A test that checks only tool names will miss this defect.
- 7. Re-test
structuredContentafter dispatch works. Once the tool is callable, separately verify that the returned machine-readable result survives the client/model boundary.
Do not apply these false fixes
- Do not delete
outputSchemajust to suppress validation. That removes useful contract information instead of fixing interoperability. - Do not globally replace “draft-07” with “2020-12”. Dialects differ. Relabeling without semantic checks can advertise a contract the server never authored.
- Do not assume the server is broken because the error names its tool. A client can reject the schema before any request reaches the server.
- Do not confuse schema acceptance with result visibility. A callable tool can still lose
structuredContentlater in a client bridge or model transcription layer.
Result-channel check
If the call does reach the server, test structuredContent separately
If tools/call executes successfully but the model sees an empty result, capture the raw response. When structuredContent is present on the wire but absent from the UI or model, the failure is downstream of the server. For broad compatibility, keep the structured value authoritative and mirror equivalent serialized JSON in a TextContent block as recommended by the tools specification.
const payload = { orderId: "ord_123", status: "ready" };
return {
content: [{ type: "text", text: JSON.stringify(payload) }],
structuredContent: payload,
};Next checks
Keep debugging the actual MCP boundary
Sources
- Model Context Protocol — JSON Schema usage — 2020-12 default, explicit alternative dialects and implementation requirements.
- MCP 2026-07-28 release notes — full JSON Schema 2020-12 vocabulary for tool schemas.
- modelcontextprotocol/typescript-sdk #2795 — fresh draft-07 emission reproduction and upstream status, opened 12 September 2026.
- anthropics/claude-code #86142 — strict-client unsupported-dialect failure before server dispatch.