fix(schema): close oneOf type-check bypass and render SEP-2106 Tool examples - #3185
fix(schema): close oneOf type-check bypass and render SEP-2106 Tool examples#3185olaservo wants to merge 5 commits into
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
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_resourceTool example by hoistingpropertiesto the schema root and usingoneOfonly for mutual exclusivity (required-based presence assertions). - Add guidance text to the
Tool.inputSchemadocumentation warning about type constraints insideoneOfbranches. - Wire additional Tool examples into
schema.tsand regenerate the derivedschema.json+schema.mdxartifacts for bothdraftand2026-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.
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>
0be882c to
3671d8d
Compare
This addresses an issue where the
find_resourceexample distinguished itsoneOfbranches with branch-localproperties. Failing a branch on a type error is exactly what makesoneOfsucceed, so a wrongly-typed value in the inactive branch was accepted, eg: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
propertiesto the schema root and reducesoneOfto the exclusivity assertion. Verified against ajv (2020-12):{"id": "r1"}{"name": "alpha"}{"id": "r1", "name": "alpha"}{"id": "r1", "name": 123}{"id": 123, "name": "alpha"}{"id": 123}{}Tradeoff
The original pattern exercised composition harder: a client that ignores
oneOfentirely would render no fields at all. The corrected version degrades gracefully, since a naive client showsidandnameas two optional strings. This seems like better authoring guidance.Also in this PR: the authoring guidance that was missing
The
inputSchemadocumentation 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:Also in this PR: wiring up the SEP-2106 Tool examples
tool-with-composition-input-schema.jsonandtool-with-array-output-schema.jsonshipped with SEP-2106 as files, but neither was referenced by an@includeCode, so neither appeared on the renderedToolpage. Both are now wired intoschema/draft/schema.tsandschema/2026-07-28/schema.ts, withschema.mdxregenerated 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
inputSchemaguidance paragraph, the regenerated artifacts, and this description. TheoneOfbehaviour 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.