Skip to content

Advertise JSON Schema 2020-12 dialect on emitted tool schemas#342

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:json_schema_2020_12
Open

Advertise JSON Schema 2020-12 dialect on emitted tool schemas#342
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:json_schema_2020_12

Conversation

@koic
Copy link
Copy Markdown
Member

@koic koic commented May 11, 2026

Motivation and Context

MCP 2025-11-25 (SEP-1613) establishes JSON Schema 2020-12 as the default dialect for MCP schema definitions.
modelcontextprotocol/modelcontextprotocol#1613

The Ruby SDK was emitting tool input and output schemas with no $schema field, leaving the dialect implicit and inconsistent with the TypeScript SDK (packages/core/src/util/standardSchema.ts, which emits with target: 'draft-2020-12') and the Python SDK (which preserves $schema in its types and conformance fixtures).

Tool::Schema#to_h now includes "$schema": "https://json-schema.org/draft/2020-12/schema" unless the user supplied a different $schema value, so clients see the canonical dialect URI on the wire.

Runtime metaschema and argument validation remain on draft-04 because the json-schema gem does not yet support 2020-12. Switching the runtime validator is left as a separate change because it requires either replacing the gem or waiting for upstream 2020-12 support.

How Has This Been Tested?

Updated Tool::Schema#to_h expectations across input_schema_test, output_schema_test, tool_test, and the tools/list server tests to reflect the new $schema field. Added focused regression tests:

  • to_h preserves a user-supplied $schema URI rather than overwriting it (covered for both symbol-keyed input and the string-keyed Hash form that goes through the initializer's symbolize_names normalization)
  • validate_arguments / validate_result continue to work when the user supplies a 2020-12 $schema URI on the schema (the validator strips the unknown top-level dialect URI before invoking the draft-04 validator, instead of raising JSON::Schema::SchemaError)
  • tools/list JSON-RPC response includes the 2020-12 $schema on both inputSchema and outputSchema (transport-boundary assertion)

bundle exec rake test and bundle exec rake rubocop both pass.

Breaking Changes

Additive change. Tolerant consumers of the tools/list payload are unaffected. Consumers that strictly assert hash equality on the emitted inputSchema / outputSchema need to account for the new $schema key, but no schema semantics change.

Schemas using 2020-12-only keywords (e.g. prefixItems, nested $schema on subschemas) are still rejected by the draft-04 metaschema validator, as before. Lifting that restriction depends on adopting a 2020-12-capable validator and is out of scope for this change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

## Motivation and Context

MCP 2025-11-25 (SEP-1613) establishes JSON Schema 2020-12 as the default dialect
for MCP schema definitions.
 modelcontextprotocol/modelcontextprotocol#1613

The Ruby SDK was emitting tool input and output schemas with no `$schema` field,
leaving the dialect implicit and inconsistent with the TypeScript SDK
(`packages/core/src/util/standardSchema.ts`, which emits with `target: 'draft-2020-12'`)
and the Python SDK (which preserves `$schema` in its types and conformance fixtures).

`Tool::Schema#to_h` now includes `"$schema": "https://json-schema.org/draft/2020-12/schema"`
unless the user supplied a different `$schema` value, so clients see the canonical dialect URI
on the wire.

Runtime metaschema and argument validation remain on draft-04 because the `json-schema` gem
does not yet support 2020-12. Switching the runtime validator is left as a separate change
because it requires either replacing the gem or waiting for upstream 2020-12 support.

## How Has This Been Tested?

Updated `Tool::Schema#to_h` expectations across `input_schema_test`, `output_schema_test`,
`tool_test`, and the `tools/list` server tests to reflect the new `$schema` field.
Added focused regression tests:

- `to_h` preserves a user-supplied `$schema` URI rather than overwriting it
  (covered for both symbol-keyed input and the string-keyed Hash form that
  goes through the initializer's `symbolize_names` normalization)
- `validate_arguments` / `validate_result` continue to work when the user supplies
  a 2020-12 `$schema` URI on the schema (the validator strips the unknown top-level
  dialect URI before invoking the draft-04 validator, instead of raising `JSON::Schema::SchemaError`)
- `tools/list` JSON-RPC response includes the 2020-12 `$schema` on both `inputSchema`
  and `outputSchema` (transport-boundary assertion)

`bundle exec rake test` and `bundle exec rake rubocop` both pass.

## Breaking Changes

Additive change. Tolerant consumers of the `tools/list` payload are unaffected.
Consumers that strictly assert hash equality on the emitted `inputSchema` / `outputSchema`
need to account for the new `$schema` key, but no schema semantics change.

Schemas using 2020-12-only keywords (e.g. `prefixItems`, nested `$schema` on subschemas)
are still rejected by the draft-04 metaschema validator, as before.
Lifting that restriction depends on adopting a 2020-12-capable validator and is out of scope
for this change.
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