feat(model): add json schema generation support for all model types (#176)

* feat(model): add json schema generation support for all model types

This commit adds JSON Schema support for all model types by implementing
`schemars::JsonSchema` trait. The feature is gated behind the new
`schemars` feature flag. This enables automatic schema generation for
API documentation and validation purposes. Added tests to verify schema
generation for client and server JSON-RPC messages.

* fix(model): add manual json schema implementation for `NumberOrString`

This commit adds a manual implementation of `JsonSchema` trait for the
`NumberOrString` enum to properly represent its union type nature in
JSON Schema. The schema now correctly specifies that the type can be
either a number or a string using the `oneOf` validation keyword.

* fix(model): skip extensions field in json schema generation

The `Extensions` type was incorrectly included in JSON schema
generation, which could lead to confusing API documentation. This commit
adds `#[schemars(skip)]` attribute to all `extensions` fields in request
and notification structs, and removes the manual `JsonSchema`
implementation for the `Extensions` type since it's an internal
implementation detail that shouldn't be exposed in the schema.
This commit is contained in:
Stanley Horwood 2025-05-15 17:56:31 +02:00 • committed by GitHub
commit e9a5ae9901
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,6 +8,7 @@ pub type ExperimentalCapabilities = BTreeMap<String, JsonObject>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PromptsCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
@ -15,6 +16,7 @@ pub struct PromptsCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ResourcesCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub subscribe: Option<bool>,
@ -24,6 +26,7 @@ pub struct ResourcesCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ToolsCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
@ -31,6 +34,7 @@ pub struct ToolsCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct RootsCapabilities {
pub list_changed: Option<bool>,
}
@ -46,6 +50,7 @@ pub struct RootsCapabilities {
/// .build();
/// ```
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ClientCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub experimental: Option<ExperimentalCapabilities>,
@ -70,6 +75,7 @@ pub struct ClientCapabilities {
/// ```
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ServerCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub experimental: Option<ExperimentalCapabilities>,