outputSchema is generated for the deserialize contract; tool results are serialised

Fechada
#1,374 2 comentários 0 reações 1 responsável Ver no GitHub

Mantenedores costumam responder em até 3 dias

@connor4312 já está trabalhando nisso.

Desde 17/10/2026.

  • #1378 de @atarutin — aberto

Avaliação

Esta issue ainda não foi avaliada.

Descrição

bug P2 ready for work T-handler

Problem

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)]
struct Out {
    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.

Linguagem predominante
Rust
Estrelas
4.1k
Forks
694
Merge médio
4d 9h
PRs com merge (30d)
41

Preparar o ambiente

Abrir no Codespaces

Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de modelcontextprotocol/rust-sdk

Todas as issues de modelcontextprotocol/rust-sdk

Issues semelhantes

Mais issues de Rust

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.