You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
outputSchema is generated for the deserialize contract; tool results are serialised #1374
schema_for_output::<T>() builds a tool's outputSchema through schema_for_type, which uses SchemaSettings::draft2020_12(), i.e. schemars' default Contract::Deserialize (crates/rmcp/src/handler/server/common.rs, still the case on main at ad5a284). A tool result is a value the server serialises, so its schema should describe what Serialize writes. Under the deserialize contract the advertised schema is wrong for common shapes:
an Option<T> field without skip_serializing_if is always written (as null), but is advertised as optional;
a #[serde(default)] field is always written, but is advertised as optional;
a type that accepts several forms and writes one (e.g. rust_decimal::Decimal: string or number in, string out) is advertised with every accepted form.
A client or model reading outputSchema is told a field may be absent when the server always sends it, or may be a number when the server sends a string.
Repro
#[derive(serde::Serialize, schemars::JsonSchema)]structOut{always:Option<i32>,#[serde(skip_serializing_if = "Option::is_none")]sometimes:Option<i32>,}// schema_for_output::<Out>()["required"] is absent; it should be ["always"].
Proposed fix
schema_for_output generates with SchemaSettings::draft2020_12().for_serialize(). Inputs (schema_for_type) stay on the deserialize contract. There is no public API change. For types whose two forms are equal, the output schema is byte-identical.
I have a patch against main with two tests (an always-written Option is required in an output schema; an input Option stays optional). cargo test -p rmcp --features server,client,macros,schemars,transport-io passes. I'm happy to open the PR if this direction is welcome.
Activity
github-actions commentedon Oct 17, 2026
@connor4312 is on triage rotation this week and is the reviewer for this one.
Codex labeled this bug / P2 (T-handler). Please confirm or correct those labels.
Automated triage. Labels are a first pass and the assigned maintainer has the final say.