Skip to content

fix(rmcp): preserve elicitation requestedSchema $schema dialect - #1176

Open
latent-9 wants to merge 1 commit into
modelcontextprotocol:mainfrom
latent-9:fix/elicitation-schema-dialect
Open

fix(rmcp): preserve elicitation requestedSchema $schema dialect#1176
latent-9 wants to merge 1 commit into
modelcontextprotocol:mainfrom
latent-9:fix/elicitation-schema-dialect

Conversation

@latent-9

Copy link
Copy Markdown
Contributor

What

ElicitationSchema (de)serializes through an internal ElicitationSchemaWire
bridge. The bridge had no field for the top-level $schema keyword, so a
dialect declared on an incoming requestedSchema was accepted but silently
dropped when the schema was re-serialized.

The 2025-11-25 protocol revision allows a requestedSchema to carry a
$schema dialect identifier, and ElicitationSchema::from_type already emits
one (schemars draft-07), so the value was being lost on any round-trip.

Change

  • Add a schema: Option<Cow<'static, str>> field (serde rename = "$schema")
    to both ElicitationSchema and the ElicitationSchemaWire bridge.
  • Thread it through the two From conversions.
  • Add a with_schema setter, matching the existing with_title and
    with_description builders. The struct is #[non_exhaustive], so an
    external caller needs a setter to populate the field.

The field uses skip_serializing_if = "Option::is_none", so a schema without a
dialect serializes exactly as before. Adding a field to a #[non_exhaustive]
struct is semver compatible.

Tests

Three unit tests in elicitation_schema.rs:

  • a $schema value survives a deserialize then serialize round-trip,
  • a schema without a dialect emits no $schema key,
  • the with_schema setter serializes the dialect.

Scope

This handles the $schema half of #1168. The other half (preserving unknown
property-level keywords) needs a data-model decision on where arbitrary
keywords should live, so I left it out of this change and kept the issue open
for it.

Refs #1168

ElicitationSchema round-trips through ElicitationSchemaWire, which had no
field for the top-level `$schema` keyword. A dialect declared on an incoming
requestedSchema (allowed since protocol revision 2025-11-25) was therefore
accepted but silently dropped on re-serialization.

Add a `schema` field to both the public struct and the wire bridge, thread it
through the two `From` conversions, and expose a `with_schema` setter. The
field is `skip_serializing_if = "Option::is_none"`, so schemas without a
dialect serialize unchanged.

Refs modelcontextprotocol#1168
@latent-9
latent-9 requested a review from a team as a code owner August 14, 2026 13:54
@github-actions github-actions Bot added T-core Core library changes T-model Model/data structure changes labels Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-core Core library changes T-model Model/data structure changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant