Skip to content

fix(schema): close oneOf type-check bypass and render SEP-2106 Tool examples - #3185

Open
olaservo wants to merge 5 commits into
mainfrom
fix/composition-example-oneof
Open

fix(schema): close oneOf type-check bypass and render SEP-2106 Tool examples#3185
olaservo wants to merge 5 commits into
mainfrom
fix/composition-example-oneof

Conversation

@olaservo

@olaservo olaservo commented Aug 2, 2026

Copy link
Copy Markdown
Member

This addresses an issue where the find_resource example distinguished its oneOf branches with branch-local properties. Failing a branch on a type error is exactly what makes oneOf succeed, so a wrongly-typed value in the inactive branch was accepted, eg:

{"id": "r1", "name": 123}    validated
{"id": 123, "name": "alpha"} validated

This means that the mutual exclusivity the example is meant to demonstrate was bypassable by supplying both fields and malforming one, and neither field was type-checked while it was the non-selected branch.

This change hoists properties to the schema root and reduces oneOf to the exclusivity assertion. Verified against ajv (2020-12):

instance before after
{"id": "r1"} pass pass
{"name": "alpha"} pass pass
{"id": "r1", "name": "alpha"} fail fail
{"id": "r1", "name": 123} pass fail
{"id": 123, "name": "alpha"} pass fail
{"id": 123} fail fail
{} fail fail

Tradeoff

The original pattern exercised composition harder: a client that ignores oneOf entirely would render no fields at all. The corrected version degrades gracefully, since a naive client shows id and name as two optional strings. This seems like better authoring guidance.

Also in this PR: the authoring guidance that was missing

The inputSchema documentation already grants composition keywords (oneOf, anyOf, allOf, not) but never said how to use them safely, which is how the original example came to be written the way it was. Two sentences are added to that same paragraph, so the caveat arrives with the permission:

When using composition keywords, declare properties at the schema root and keep the branches to presence assertions such as required. A subschema that fails on a type error is indistinguishable from one that does not apply, so type constraints placed inside oneOf branches are not enforced for whichever branch does not match.

Also in this PR: wiring up the SEP-2106 Tool examples

tool-with-composition-input-schema.json and tool-with-array-output-schema.json shipped with SEP-2106 as files, but neither was referenced by an @includeCode, so neither appeared on the rendered Tool page. Both are now wired into schema/draft/schema.ts and schema/2026-07-28/schema.ts, with schema.mdx regenerated for both revisions.

Non-goal: SEP-2106 itself

SEP-2106 contains the same bypassable pattern in two places. It is deliberately left alone: the SEP is Final and carries the historical-record notice added in #3166, so it is preserved as the design as accepted rather than corrected in place. The spec examples are the authoritative reference, which is part of why rendering them matters.


🦉 AI assistance disclosure

Developed with Claude Code (Opus 5). It reviewed the original fix, then authored the 2026-07-28 example wiring, the inputSchema guidance paragraph, the regenerated artifacts, and this description. The oneOf behaviour in the table above was verified by running both schema variants through ajv rather than by inspection, and the generated files were checked against the repo's own generator output. I reviewed and directed each step, and understand and stand behind the changes.

Per AI_POLICY.md.

@mintlify

mintlify Bot commented Aug 2, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcp-staging 🟢 Ready View Preview Aug 2, 2026, 12:55 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@mintlify

mintlify Bot commented Aug 2, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcp 🟢 Ready View Preview Aug 2, 2026, 12:55 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MCP Tool schema documentation and examples to prevent a oneOf-based example from allowing a type-check bypass, adds explicit authoring guidance for safe use of JSON Schema composition keywords, and ensures SEP-2106 Tool examples are rendered on the Tool schema reference pages for both draft and 2026-07-28 schema revisions.

Changes:

  • Fix the find_resource Tool example by hoisting properties to the schema root and using oneOf only for mutual exclusivity (required-based presence assertions).
  • Add guidance text to the Tool.inputSchema documentation warning about type constraints inside oneOf branches.
  • Wire additional Tool examples into schema.ts and regenerate the derived schema.json + schema.mdx artifacts for both draft and 2026-07-28.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
schema/draft/schema.ts Adds Tool examples (composition + array output) and adds inputSchema composition-keyword guidance.
schema/draft/schema.json Regenerated schema JSON reflecting the updated inputSchema description text.
schema/draft/examples/Tool/tool-with-composition-input-schema.json Fixes the composition example to avoid the oneOf branch-local type-check bypass.
schema/2026-07-28/schema.ts Mirrors the Tool example wiring and inputSchema guidance for the 2026-07-28 revision.
schema/2026-07-28/schema.json Regenerated schema JSON reflecting the updated inputSchema description text.
schema/2026-07-28/examples/Tool/tool-with-composition-input-schema.json Mirrors the fixed composition example for the 2026-07-28 revision.
docs/specification/draft/schema.mdx Regenerated schema reference page showing the new examples and guidance.
docs/specification/2026-07-28/schema.mdx Regenerated schema reference page showing the new examples and guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread schema/draft/schema.ts
Comment thread schema/2026-07-28/schema.ts
olaservo and others added 4 commits August 9, 2026 15:36
The `find_resource` example distinguished its `oneOf` branches with
branch-local `properties`. Failing a branch on a type error is exactly
what makes `oneOf` succeed, so a wrongly-typed value in the inactive
branch was accepted:

  {"id": "r1", "name": 123}    validated
  {"id": 123, "name": "alpha"} validated

The mutual exclusivity the example demonstrates was therefore bypassable
by supplying both fields and malforming one, and neither field was
type-checked while it was the non-selected branch.

Hoist `properties` to the schema root and reduce `oneOf` to the
exclusivity assertion. Validation is otherwise unchanged: `{}` and
`{id, name}` are still rejected, each field alone still passes. The root
`properties` map is also no longer empty, so consumers that build a
parameter list from `inputSchema.properties` advertise the tool's
arguments instead of showing none.

Applied to both draft and 2026-07-28. The 2026-07-28 copy is not
referenced by any `@includeCode`, so that revision's rendered schema page
is unchanged.

Also wire the two SEP-2106 examples into the draft `Tool` docs. Both were
added as files but never referenced, so neither appeared on the rendered
page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The composition and array-output-schema examples shipped with SEP-2106
but were never referenced by an `@includeCode`, so they did not appear
on the rendered Tool page for the current protocol version. Wire both
in, matching the ordering already applied to draft, and regenerate
docs/specification/2026-07-28/schema.mdx.

The Tool doc-comment blocks in schema/2026-07-28/schema.ts and
schema/draft/schema.ts are now identical. 2026-07-28 is the Current
revision, which per the versioning policy may receive backwards
compatible changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The inputSchema documentation grants composition keywords but does not
say how to use them safely. A subschema that fails on a type error is
indistinguishable from one that does not apply, so type constraints
written inside `oneOf` branches are skipped for whichever branch does
not match -- the bug this PR fixes in the `find_resource` example.

Add two sentences to the paragraph that grants composition, so the
caveat arrives with the permission. Non-normative: the bypassable
pattern is legal JSON Schema, just rarely what the author meant.

Applied to draft and 2026-07-28, with both schema.mdx regenerated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Doc-comment prose feeds the generated `description`, so the composition
note requires schema.json to be regenerated for draft and 2026-07-28.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants