From 1e2cf8b6f69cc4acf6361af3479ada99ff4569ee Mon Sep 17 00:00:00 2001 From: Stanley Horwood Date: Thu, 15 May 2025 17:46:18 +0200 Subject: [PATCH 1/3] 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. --- README.md | 1 + crates/rmcp/Cargo.toml | 8 +- crates/rmcp/src/model.rs | 71 + crates/rmcp/src/model/annotated.rs | 2 + crates/rmcp/src/model/capabilities.rs | 6 + crates/rmcp/src/model/content.rs | 5 + crates/rmcp/src/model/extension.rs | 10 + crates/rmcp/src/model/prompt.rs | 5 + crates/rmcp/src/model/resource.rs | 3 + crates/rmcp/src/model/tool.rs | 2 + crates/rmcp/tests/test_message_schema.rs | 22 + .../client_json_rpc_message_schema.json | 1302 ++++++++++++++ .../server_json_rpc_message_schema.json | 1601 +++++++++++++++++ 13 files changed, 3037 insertions(+), 1 deletion(-) create mode 100644 crates/rmcp/tests/test_message_schema.rs create mode 100644 crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json create mode 100644 crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json diff --git a/README.md b/README.md index c420640b..b3804e70 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,7 @@ See [examples](examples/README.md) - `client`: use client side sdk - `server`: use server side sdk - `macros`: macros default +- `schemars`: implement `JsonSchema` for all model structs ### Transports diff --git a/crates/rmcp/Cargo.toml b/crates/rmcp/Cargo.toml index e29ffa51..0079ac34 100644 --- a/crates/rmcp/Cargo.toml +++ b/crates/rmcp/Cargo.toml @@ -28,7 +28,7 @@ paste = { version = "1", optional = true } oauth2 = { version = "5.0", optional = true } # for auto generate schema -schemars = { version = "0.8", optional = true } +schemars = { version = "0.8", optional = true, features = ["chrono"] } # for image encoding base64 = { version = "0.21", optional = true } @@ -89,6 +89,7 @@ tower = ["dep:tower-service"] __auth = ["dep:oauth2", "dep:reqwest", "dep:url"] auth = ["__auth", "reqwest?/rustls-tls"] auth-tls-no-provider = ["auth", "reqwest?/rustls-tls-no-provider"] +schemars = ["dep:schemars"] [dev-dependencies] tokio = { version = "1", features = ["full"] } @@ -131,3 +132,8 @@ name = "test_message_protocol" required-features = ["client"] path = "tests/test_message_protocol.rs" +[[test]] +name = "test_message_schema" +required-features = ["server", "client", "schemars"] +path = "tests/test_message_schema.rs" + diff --git a/crates/rmcp/src/model.rs b/crates/rmcp/src/model.rs index 60182722..fc910ac1 100644 --- a/crates/rmcp/src/model.rs +++ b/crates/rmcp/src/model.rs @@ -87,12 +87,30 @@ macro_rules! const_string { } } } + + #[cfg(feature = "schemars")] + impl schemars::JsonSchema for $name { + fn schema_name() -> String { + stringify!($name).to_string() + } + + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { + // Create a schema for a constant value of type String + schemars::schema::Schema::Object(schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::String.into()), + format: Some("const".to_string()), + const_value: Some(serde_json::Value::String($value.into())), + ..Default::default() + }) + } + } }; } const_string!(JsonRpcVersion2_0 = "2.0"); #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ProtocolVersion(Cow<'static, str>); impl Default for ProtocolVersion { @@ -132,6 +150,7 @@ impl<'de> Deserialize<'de> for ProtocolVersion { } #[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum NumberOrString { Number(u32), String(Arc), @@ -188,8 +207,10 @@ pub type RequestId = NumberOrString; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)] #[serde(transparent)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ProgressToken(pub NumberOrString); #[derive(Debug, Clone)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Request { pub method: M, // #[serde(skip_serializing_if = "Option::is_none")] @@ -210,6 +231,7 @@ impl GetExtensions for Request { } #[derive(Debug, Clone)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RequestOptionalParam { pub method: M, // #[serde(skip_serializing_if = "Option::is_none")] @@ -221,6 +243,7 @@ pub struct RequestOptionalParam { } #[derive(Debug, Clone)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RequestNoParam { pub method: M, /// extensions will carry anything possible in the context, including [`Meta`] @@ -238,6 +261,7 @@ impl GetExtensions for RequestNoParam { } } #[derive(Debug, Clone)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Notification { pub method: M, pub params: P, @@ -248,6 +272,7 @@ pub struct Notification { } #[derive(Debug, Clone)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct NotificationNoParam { pub method: M, /// extensions will carry anything possible in the context, including [`Meta`] @@ -257,14 +282,17 @@ pub struct NotificationNoParam { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct JsonRpcRequest { pub jsonrpc: JsonRpcVersion2_0, pub id: RequestId, #[serde(flatten)] pub request: R, } + type DefaultResponse = JsonObject; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct JsonRpcResponse { pub jsonrpc: JsonRpcVersion2_0, pub id: RequestId, @@ -272,6 +300,7 @@ pub struct JsonRpcResponse { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct JsonRpcError { pub jsonrpc: JsonRpcVersion2_0, pub id: RequestId, @@ -279,6 +308,7 @@ pub struct JsonRpcError { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct JsonRpcNotification { pub jsonrpc: JsonRpcVersion2_0, #[serde(flatten)] @@ -288,6 +318,7 @@ pub struct JsonRpcNotification { // Standard JSON-RPC error codes #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)] #[serde(transparent)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ErrorCode(pub i32); impl ErrorCode { @@ -301,6 +332,7 @@ impl ErrorCode { /// Error information for JSON-RPC error responses. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ErrorData { /// The error type that occurred. pub code: ErrorCode, @@ -348,6 +380,7 @@ impl ErrorData { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(untagged)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum JsonRpcBatchRequestItem { Request(JsonRpcRequest), Notification(JsonRpcNotification), @@ -364,6 +397,7 @@ impl JsonRpcBatchRequestItem { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(untagged)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum JsonRpcBatchResponseItem { Response(JsonRpcResponse), Error(JsonRpcError), @@ -380,6 +414,7 @@ impl JsonRpcBatchResponseItem { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(untagged)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum JsonRpcMessage { Request(JsonRpcRequest), Response(JsonRpcResponse), @@ -471,6 +506,7 @@ impl From for () { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CancelledNotificationParam { pub request_id: RequestId, pub reason: Option, @@ -499,6 +535,7 @@ const_string!(InitializedNotificationMethod = "notifications/initialized"); pub type InitializedNotification = NotificationNoParam; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct InitializeRequestParam { pub protocol_version: ProtocolVersion, pub capabilities: ClientCapabilities, @@ -507,6 +544,7 @@ pub struct InitializeRequestParam { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct InitializeResult { pub protocol_version: ProtocolVersion, pub capabilities: ServerCapabilities, @@ -540,6 +578,7 @@ impl Default for ClientInfo { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Implementation { pub name: String, pub version: String, @@ -562,6 +601,7 @@ impl Implementation { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct PaginatedRequestParam { #[serde(skip_serializing_if = "Option::is_none")] pub cursor: Option, @@ -572,6 +612,7 @@ pub type PingRequest = RequestNoParam; const_string!(ProgressNotificationMethod = "notifications/progress"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ProgressNotificationParam { pub progress_token: ProgressToken, /// The progress thus far. This should increase every time progress is made, even if the total is unknown. @@ -594,6 +635,7 @@ macro_rules! paginated_result { }) => { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] #[serde(rename_all = "camelCase")] + #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct $t { #[serde(skip_serializing_if = "Option::is_none")] pub next_cursor: Option, @@ -619,11 +661,13 @@ paginated_result!(ListResourceTemplatesResult { const_string!(ReadResourceRequestMethod = "resources/read"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ReadResourceRequestParam { pub uri: String, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ReadResourceResult { pub contents: Vec, } @@ -637,6 +681,7 @@ pub type ResourceListChangedNotification = const_string!(SubscribeRequestMethod = "resources/subscribe"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct SubscribeRequestParam { pub uri: String, } @@ -645,6 +690,7 @@ pub type SubscribeRequest = Request; const_string!(LoggingMessageNotificationMethod = "notifications/message"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct LoggingMessageNotificationParam { pub level: LoggingLevel, #[serde(skip_serializing_if = "Option::is_none")] @@ -719,18 +770,21 @@ pub type CreateMessageRequest = Request, #[serde(skip_serializing_if = "Option::is_none")] @@ -761,6 +816,7 @@ pub struct CreateMessageRequestParam { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ModelPreferences { #[serde(skip_serializing_if = "Option::is_none")] pub hints: Option>, @@ -773,6 +829,7 @@ pub struct ModelPreferences { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ModelHint { #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, @@ -780,6 +837,7 @@ pub struct ModelHint { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CompleteRequestParam { pub r#ref: Reference, pub argument: ArgumentInfo, @@ -789,6 +847,7 @@ pub type CompleteRequest = Request; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CompletionInfo { pub values: Vec, #[serde(skip_serializing_if = "Option::is_none")] @@ -799,12 +858,14 @@ pub struct CompletionInfo { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CompleteResult { pub completion: CompletionInfo, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(tag = "type")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum Reference { #[serde(rename = "ref/resource")] Resource(ResourceReference), @@ -813,11 +874,13 @@ pub enum Reference { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ResourceReference { pub uri: String, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct PromptReference { pub name: String, } @@ -825,6 +888,7 @@ pub struct PromptReference { const_string!(CompleteRequestMethod = "completion/complete"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ArgumentInfo { pub name: String, pub value: String, @@ -832,6 +896,7 @@ pub struct ArgumentInfo { // 根目录相关 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Root { pub uri: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -843,6 +908,7 @@ pub type ListRootsRequest = RequestNoParam; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ListRootsResult { pub roots: Vec, } @@ -852,6 +918,7 @@ pub type RootsListChangedNotification = NotificationNoParam, #[serde(skip_serializing_if = "Option::is_none")] @@ -884,6 +951,7 @@ paginated_result!( const_string!(CallToolRequestMethod = "tools/call"); #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CallToolRequestParam { pub name: Cow<'static, str>, #[serde(skip_serializing_if = "Option::is_none")] @@ -894,6 +962,7 @@ pub type CallToolRequest = Request; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct CreateMessageResult { pub model: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -910,6 +979,7 @@ impl CreateMessageResult { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct GetPromptResult { #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, @@ -923,6 +993,7 @@ macro_rules! ts_union { ) => { #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(untagged)] + #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum $U { $($V($V),)* } diff --git a/crates/rmcp/src/model/annotated.rs b/crates/rmcp/src/model/annotated.rs index 31ea65db..d0f53f75 100644 --- a/crates/rmcp/src/model/annotated.rs +++ b/crates/rmcp/src/model/annotated.rs @@ -10,6 +10,7 @@ use super::{ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Annotations { #[serde(skip_serializing_if = "Option::is_none")] pub audience: Option>, @@ -36,6 +37,7 @@ impl Annotations { } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Annotated { #[serde(flatten)] pub raw: T, diff --git a/crates/rmcp/src/model/capabilities.rs b/crates/rmcp/src/model/capabilities.rs index 7e853402..3b9863c6 100644 --- a/crates/rmcp/src/model/capabilities.rs +++ b/crates/rmcp/src/model/capabilities.rs @@ -8,6 +8,7 @@ pub type ExperimentalCapabilities = BTreeMap; #[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, @@ -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, @@ -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, @@ -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, } @@ -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, @@ -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, diff --git a/crates/rmcp/src/model/content.rs b/crates/rmcp/src/model/content.rs index a7774d8c..f21463c5 100644 --- a/crates/rmcp/src/model/content.rs +++ b/crates/rmcp/src/model/content.rs @@ -8,12 +8,14 @@ use super::{AnnotateAble, Annotated, resource::ResourceContents}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawTextContent { pub text: String, } pub type TextContent = Annotated; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawImageContent { /// The base64-encoded image pub data: String, @@ -23,6 +25,7 @@ pub struct RawImageContent { pub type ImageContent = Annotated; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawEmbeddedResource { pub resource: ResourceContents, } @@ -39,6 +42,7 @@ impl EmbeddedResource { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawAudioContent { pub data: String, pub mime_type: String, @@ -48,6 +52,7 @@ pub type AudioContent = Annotated; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum RawContent { Text(RawTextContent), Image(RawImageContent), diff --git a/crates/rmcp/src/model/extension.rs b/crates/rmcp/src/model/extension.rs index a9d78d4c..cc6afbe4 100644 --- a/crates/rmcp/src/model/extension.rs +++ b/crates/rmcp/src/model/extension.rs @@ -279,6 +279,16 @@ impl fmt::Debug for Extensions { } } +impl schemars::JsonSchema for Extensions { + fn schema_name() -> String { + "Extensions".to_string() + } + + fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { + generator.subschema_for::() + } +} + trait AnyClone: Any { fn clone_box(&self) -> Box; fn as_any(&self) -> &dyn Any; diff --git a/crates/rmcp/src/model/prompt.rs b/crates/rmcp/src/model/prompt.rs index 43973407..adba2361 100644 --- a/crates/rmcp/src/model/prompt.rs +++ b/crates/rmcp/src/model/prompt.rs @@ -10,6 +10,7 @@ use super::{ /// A prompt that can be used to generate text from a model #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Prompt { /// The name of the prompt pub name: String, @@ -42,6 +43,7 @@ impl Prompt { /// Represents a prompt argument that can be passed to customize the prompt #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct PromptArgument { /// The name of the argument pub name: String, @@ -56,6 +58,7 @@ pub struct PromptArgument { /// Represents the role of a message sender in a prompt conversation #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum PromptMessageRole { User, Assistant, @@ -64,6 +67,7 @@ pub enum PromptMessageRole { /// Content types that can be included in prompt messages #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum PromptMessageContent { /// Plain text content Text { text: String }, @@ -84,6 +88,7 @@ impl PromptMessageContent { /// A message in a prompt conversation #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct PromptMessage { /// The role of the message sender pub role: PromptMessageRole, diff --git a/crates/rmcp/src/model/resource.rs b/crates/rmcp/src/model/resource.rs index d5c1ef60..fe7d26cb 100644 --- a/crates/rmcp/src/model/resource.rs +++ b/crates/rmcp/src/model/resource.rs @@ -5,6 +5,7 @@ use super::Annotated; /// Represents a resource in the extension with metadata #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawResource { /// URI representing the resource location (e.g., "file:///path/to/file" or "str:///content") pub uri: String, @@ -28,6 +29,7 @@ pub type Resource = Annotated; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct RawResourceTemplate { pub uri_template: String, pub name: String, @@ -41,6 +43,7 @@ pub type ResourceTemplate = Annotated; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "camelCase", untagged)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum ResourceContents { TextResourceContents { uri: String, diff --git a/crates/rmcp/src/model/tool.rs b/crates/rmcp/src/model/tool.rs index ca5100d9..d392f9b8 100644 --- a/crates/rmcp/src/model/tool.rs +++ b/crates/rmcp/src/model/tool.rs @@ -10,6 +10,7 @@ use super::JsonObject; /// A tool that can be used by a model. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Tool { /// The name of the tool pub name: Cow<'static, str>, @@ -33,6 +34,7 @@ pub struct Tool { /// received from untrusted servers. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ToolAnnotations { /// A human-readable title for the tool. pub title: Option, diff --git a/crates/rmcp/tests/test_message_schema.rs b/crates/rmcp/tests/test_message_schema.rs new file mode 100644 index 00000000..fb7fd8d9 --- /dev/null +++ b/crates/rmcp/tests/test_message_schema.rs @@ -0,0 +1,22 @@ +#[cfg(feature = "schemars")] +mod tests { + use rmcp::model::{ClientJsonRpcMessage, ServerJsonRpcMessage}; + use super::*; + use schemars::schema_for; + + #[test] + fn test_client_json_rpc_message_schema() { + let schema = schema_for!(ClientJsonRpcMessage); + let schema_str = serde_json::to_string_pretty(&schema).unwrap(); + let expected = std::fs::read_to_string("tests/test_message_schema/client_json_rpc_message_schema.json").unwrap(); + assert_eq!(schema_str, expected, "Schema generation for ClientJsonRpcMessage should match expected output"); + } + + #[test] + fn test_server_json_rpc_message_schema() { + let schema = schema_for!(ServerJsonRpcMessage); + let schema_str = serde_json::to_string_pretty(&schema).unwrap(); + let expected = std::fs::read_to_string("tests/test_message_schema/server_json_rpc_message_schema.json").unwrap(); + assert_eq!(schema_str, expected, "Schema generation for ServerJsonRpcMessage should match expected output"); + } +} diff --git a/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json new file mode 100644 index 00000000..b3342902 --- /dev/null +++ b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json @@ -0,0 +1,1302 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JsonRpcMessage_for_ClientRequest_and_ClientResult_and_ClientNotification", + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcRequest_for_ClientRequest" + }, + { + "$ref": "#/definitions/JsonRpcResponse_for_ClientResult" + }, + { + "$ref": "#/definitions/JsonRpcNotification_for_ClientNotification" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/JsonRpcBatchRequestItem_for_ClientRequest_and_ClientNotification" + } + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/JsonRpcBatchResponseItem_for_ClientResult" + } + }, + { + "$ref": "#/definitions/JsonRpcError" + } + ], + "definitions": { + "Annotated_for_RawContent": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": [ + "text", + "type" + ], + "properties": { + "text": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, + { + "type": "object", + "required": [ + "data", + "mimeType", + "type" + ], + "properties": { + "data": { + "description": "The base64-encoded image", + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "image" + ] + } + } + }, + { + "type": "object", + "required": [ + "resource", + "type" + ], + "properties": { + "resource": { + "$ref": "#/definitions/ResourceContents" + }, + "type": { + "type": "string", + "enum": [ + "resource" + ] + } + } + }, + { + "type": "object", + "required": [ + "data", + "mimeType", + "type" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "data": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "audio" + ] + } + } + } + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + } + } + }, + "Annotations": { + "type": "object", + "properties": { + "audience": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Role" + } + }, + "priority": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "timestamp": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "ArgumentInfo": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "CallToolRequestMethod": { + "type": "string", + "format": "const", + "const": "tools/call" + }, + "CallToolRequestParam": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "arguments": { + "type": [ + "object", + "null" + ], + "additionalProperties": true + }, + "name": { + "type": "string" + } + } + }, + "CancelledNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/cancelled" + }, + "CancelledNotificationParam": { + "type": "object", + "required": [ + "requestId" + ], + "properties": { + "reason": { + "type": [ + "string", + "null" + ] + }, + "requestId": { + "$ref": "#/definitions/NumberOrString" + } + } + }, + "ClientCapabilities": { + "title": "Builder", + "description": "```rust # use rmcp::model::ClientCapabilities; let cap = ClientCapabilities::builder() .enable_experimental() .enable_roots() .enable_roots_list_changed() .build(); ```", + "type": "object", + "properties": { + "experimental": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "object", + "additionalProperties": true + } + }, + "roots": { + "anyOf": [ + { + "$ref": "#/definitions/RootsCapabilities" + }, + { + "type": "null" + } + ] + }, + "sampling": { + "type": [ + "object", + "null" + ], + "additionalProperties": true + } + } + }, + "ClientResult": { + "anyOf": [ + { + "$ref": "#/definitions/CreateMessageResult" + }, + { + "$ref": "#/definitions/ListRootsResult" + }, + { + "$ref": "#/definitions/EmptyObject" + } + ] + }, + "CompleteRequestMethod": { + "type": "string", + "format": "const", + "const": "completion/complete" + }, + "CompleteRequestParam": { + "type": "object", + "required": [ + "argument", + "ref" + ], + "properties": { + "argument": { + "$ref": "#/definitions/ArgumentInfo" + }, + "ref": { + "$ref": "#/definitions/Reference" + } + } + }, + "CreateMessageResult": { + "type": "object", + "required": [ + "content", + "model", + "role" + ], + "properties": { + "content": { + "$ref": "#/definitions/Annotated_for_RawContent" + }, + "model": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/Role" + }, + "stopReason": { + "type": [ + "string", + "null" + ] + } + } + }, + "EmptyObject": { + "type": "object" + }, + "ErrorData": { + "description": "Error information for JSON-RPC error responses.", + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "description": "The error type that occurred.", + "type": "integer", + "format": "int32" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + } + }, + "Extensions": true, + "GetPromptRequestMethod": { + "type": "string", + "format": "const", + "const": "prompts/get" + }, + "GetPromptRequestParam": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "arguments": { + "type": [ + "object", + "null" + ], + "additionalProperties": true + }, + "name": { + "type": "string" + } + } + }, + "Implementation": { + "type": "object", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "InitializeRequestParam": { + "type": "object", + "required": [ + "capabilities", + "clientInfo", + "protocolVersion" + ], + "properties": { + "capabilities": { + "$ref": "#/definitions/ClientCapabilities" + }, + "clientInfo": { + "$ref": "#/definitions/Implementation" + }, + "protocolVersion": { + "$ref": "#/definitions/ProtocolVersion" + } + } + }, + "InitializeResultMethod": { + "type": "string", + "format": "const", + "const": "initialize" + }, + "InitializedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/initialized" + }, + "JsonRpcBatchRequestItem_for_ClientRequest_and_ClientNotification": { + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcRequest_for_ClientRequest" + }, + { + "$ref": "#/definitions/JsonRpcNotification_for_ClientNotification" + } + ] + }, + "JsonRpcBatchResponseItem_for_ClientResult": { + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcResponse_for_ClientResult" + }, + { + "$ref": "#/definitions/JsonRpcError" + } + ] + }, + "JsonRpcError": { + "type": "object", + "required": [ + "error", + "id", + "jsonrpc" + ], + "properties": { + "error": { + "$ref": "#/definitions/ErrorData" + }, + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcNotification_for_ClientNotification": { + "type": "object", + "anyOf": [ + { + "$ref": "#/definitions/Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam" + }, + { + "$ref": "#/definitions/Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam" + }, + { + "$ref": "#/definitions/NotificationNoParam_for_InitializedNotificationMethod" + }, + { + "$ref": "#/definitions/NotificationNoParam_for_RootsListChangedNotificationMethod" + } + ], + "required": [ + "jsonrpc" + ], + "properties": { + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcRequest_for_ClientRequest": { + "type": "object", + "anyOf": [ + { + "$ref": "#/definitions/RequestNoParam_for_PingRequestMethod" + }, + { + "$ref": "#/definitions/Request_for_InitializeResultMethod_and_InitializeRequestParam" + }, + { + "$ref": "#/definitions/Request_for_CompleteRequestMethod_and_CompleteRequestParam" + }, + { + "$ref": "#/definitions/Request_for_SetLevelRequestMethod_and_SetLevelRequestParam" + }, + { + "$ref": "#/definitions/Request_for_GetPromptRequestMethod_and_GetPromptRequestParam" + }, + { + "$ref": "#/definitions/RequestOptionalParam_for_ListPromptsRequestMethod_and_PaginatedRequestParam" + }, + { + "$ref": "#/definitions/RequestOptionalParam_for_ListResourcesRequestMethod_and_PaginatedRequestParam" + }, + { + "$ref": "#/definitions/RequestOptionalParam_for_ListResourceTemplatesRequestMethod_and_PaginatedRequestParam" + }, + { + "$ref": "#/definitions/Request_for_ReadResourceRequestMethod_and_ReadResourceRequestParam" + }, + { + "$ref": "#/definitions/Request_for_SubscribeRequestMethod_and_SubscribeRequestParam" + }, + { + "$ref": "#/definitions/Request_for_UnsubscribeRequestMethod_and_UnsubscribeRequestParam" + }, + { + "$ref": "#/definitions/Request_for_CallToolRequestMethod_and_CallToolRequestParam" + }, + { + "$ref": "#/definitions/RequestOptionalParam_for_ListToolsRequestMethod_and_PaginatedRequestParam" + } + ], + "required": [ + "id", + "jsonrpc" + ], + "properties": { + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcResponse_for_ClientResult": { + "type": "object", + "required": [ + "id", + "jsonrpc", + "result" + ], + "properties": { + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + }, + "result": { + "$ref": "#/definitions/ClientResult" + } + } + }, + "JsonRpcVersion2_0": { + "type": "string", + "format": "const", + "const": "2.0" + }, + "ListPromptsRequestMethod": { + "type": "string", + "format": "const", + "const": "prompts/list" + }, + "ListResourceTemplatesRequestMethod": { + "type": "string", + "format": "const", + "const": "resources/templates/list" + }, + "ListResourcesRequestMethod": { + "type": "string", + "format": "const", + "const": "resources/list" + }, + "ListRootsResult": { + "type": "object", + "required": [ + "roots" + ], + "properties": { + "roots": { + "type": "array", + "items": { + "$ref": "#/definitions/Root" + } + } + } + }, + "ListToolsRequestMethod": { + "type": "string", + "format": "const", + "const": "tools/list" + }, + "LoggingLevel": { + "type": "string", + "enum": [ + "debug", + "info", + "notice", + "warning", + "error", + "critical", + "alert", + "emergency" + ] + }, + "NotificationNoParam_for_InitializedNotificationMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/InitializedNotificationMethod" + } + } + }, + "NotificationNoParam_for_RootsListChangedNotificationMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/RootsListChangedNotificationMethod" + } + } + }, + "Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/CancelledNotificationMethod" + }, + "params": { + "$ref": "#/definitions/CancelledNotificationParam" + } + } + }, + "Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ProgressNotificationMethod" + }, + "params": { + "$ref": "#/definitions/ProgressNotificationParam" + } + } + }, + "NumberOrString": { + "oneOf": [ + { + "type": "object", + "required": [ + "Number" + ], + "properties": { + "Number": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "String" + ], + "properties": { + "String": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "PaginatedRequestParam": { + "type": "object", + "properties": { + "cursor": { + "type": [ + "string", + "null" + ] + } + } + }, + "PingRequestMethod": { + "type": "string", + "format": "const", + "const": "ping" + }, + "ProgressNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/progress" + }, + "ProgressNotificationParam": { + "type": "object", + "required": [ + "progress", + "progressToken" + ], + "properties": { + "message": { + "description": "An optional message describing the current progress.", + "type": [ + "string", + "null" + ] + }, + "progress": { + "description": "The progress thus far. This should increase every time progress is made, even if the total is unknown.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "progressToken": { + "$ref": "#/definitions/NumberOrString" + }, + "total": { + "description": "Total number of items to process (or total progress required), if known", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + } + }, + "ProtocolVersion": { + "type": "string" + }, + "ReadResourceRequestMethod": { + "type": "string", + "format": "const", + "const": "resources/read" + }, + "ReadResourceRequestParam": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "uri": { + "type": "string" + } + } + }, + "Reference": { + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "uri" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "ref/resource" + ] + }, + "uri": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "ref/prompt" + ] + } + } + } + ] + }, + "RequestNoParam_for_PingRequestMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/PingRequestMethod" + } + } + }, + "RequestOptionalParam_for_ListPromptsRequestMethod_and_PaginatedRequestParam": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ListPromptsRequestMethod" + }, + "params": { + "anyOf": [ + { + "$ref": "#/definitions/PaginatedRequestParam" + }, + { + "type": "null" + } + ] + } + } + }, + "RequestOptionalParam_for_ListResourceTemplatesRequestMethod_and_PaginatedRequestParam": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ListResourceTemplatesRequestMethod" + }, + "params": { + "anyOf": [ + { + "$ref": "#/definitions/PaginatedRequestParam" + }, + { + "type": "null" + } + ] + } + } + }, + "RequestOptionalParam_for_ListResourcesRequestMethod_and_PaginatedRequestParam": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ListResourcesRequestMethod" + }, + "params": { + "anyOf": [ + { + "$ref": "#/definitions/PaginatedRequestParam" + }, + { + "type": "null" + } + ] + } + } + }, + "RequestOptionalParam_for_ListToolsRequestMethod_and_PaginatedRequestParam": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ListToolsRequestMethod" + }, + "params": { + "anyOf": [ + { + "$ref": "#/definitions/PaginatedRequestParam" + }, + { + "type": "null" + } + ] + } + } + }, + "Request_for_CallToolRequestMethod_and_CallToolRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/CallToolRequestMethod" + }, + "params": { + "$ref": "#/definitions/CallToolRequestParam" + } + } + }, + "Request_for_CompleteRequestMethod_and_CompleteRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/CompleteRequestMethod" + }, + "params": { + "$ref": "#/definitions/CompleteRequestParam" + } + } + }, + "Request_for_GetPromptRequestMethod_and_GetPromptRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/GetPromptRequestMethod" + }, + "params": { + "$ref": "#/definitions/GetPromptRequestParam" + } + } + }, + "Request_for_InitializeResultMethod_and_InitializeRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/InitializeResultMethod" + }, + "params": { + "$ref": "#/definitions/InitializeRequestParam" + } + } + }, + "Request_for_ReadResourceRequestMethod_and_ReadResourceRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ReadResourceRequestMethod" + }, + "params": { + "$ref": "#/definitions/ReadResourceRequestParam" + } + } + }, + "Request_for_SetLevelRequestMethod_and_SetLevelRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/SetLevelRequestMethod" + }, + "params": { + "$ref": "#/definitions/SetLevelRequestParam" + } + } + }, + "Request_for_SubscribeRequestMethod_and_SubscribeRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/SubscribeRequestMethod" + }, + "params": { + "$ref": "#/definitions/SubscribeRequestParam" + } + } + }, + "Request_for_UnsubscribeRequestMethod_and_UnsubscribeRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/UnsubscribeRequestMethod" + }, + "params": { + "$ref": "#/definitions/UnsubscribeRequestParam" + } + } + }, + "ResourceContents": { + "anyOf": [ + { + "type": "object", + "required": [ + "text", + "uri" + ], + "properties": { + "mime_type": { + "type": [ + "string", + "null" + ] + }, + "text": { + "type": "string" + }, + "uri": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "blob", + "uri" + ], + "properties": { + "blob": { + "type": "string" + }, + "mime_type": { + "type": [ + "string", + "null" + ] + }, + "uri": { + "type": "string" + } + } + } + ] + }, + "Role": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "Root": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "name": { + "type": [ + "string", + "null" + ] + }, + "uri": { + "type": "string" + } + } + }, + "RootsCapabilities": { + "type": "object", + "properties": { + "listChanged": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "RootsListChangedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/roots/list_changed" + }, + "SetLevelRequestMethod": { + "type": "string", + "format": "const", + "const": "logging/setLevel" + }, + "SetLevelRequestParam": { + "type": "object", + "required": [ + "level" + ], + "properties": { + "level": { + "$ref": "#/definitions/LoggingLevel" + } + } + }, + "SubscribeRequestMethod": { + "type": "string", + "format": "const", + "const": "resources/subscribe" + }, + "SubscribeRequestParam": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "uri": { + "type": "string" + } + } + }, + "UnsubscribeRequestMethod": { + "type": "string", + "format": "const", + "const": "resources/unsubscribe" + }, + "UnsubscribeRequestParam": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "uri": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json new file mode 100644 index 00000000..77fef38d --- /dev/null +++ b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json @@ -0,0 +1,1601 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "JsonRpcMessage_for_ServerRequest_and_ServerResult_and_ServerNotification", + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcRequest_for_ServerRequest" + }, + { + "$ref": "#/definitions/JsonRpcResponse_for_ServerResult" + }, + { + "$ref": "#/definitions/JsonRpcNotification_for_ServerNotification" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/JsonRpcBatchRequestItem_for_ServerRequest_and_ServerNotification" + } + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/JsonRpcBatchResponseItem_for_ServerResult" + } + }, + { + "$ref": "#/definitions/JsonRpcError" + } + ], + "definitions": { + "Annotated_for_RawContent": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": [ + "text", + "type" + ], + "properties": { + "text": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, + { + "type": "object", + "required": [ + "data", + "mimeType", + "type" + ], + "properties": { + "data": { + "description": "The base64-encoded image", + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "image" + ] + } + } + }, + { + "type": "object", + "required": [ + "resource", + "type" + ], + "properties": { + "resource": { + "$ref": "#/definitions/ResourceContents" + }, + "type": { + "type": "string", + "enum": [ + "resource" + ] + } + } + }, + { + "type": "object", + "required": [ + "data", + "mimeType", + "type" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "data": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "audio" + ] + } + } + } + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + } + } + }, + "Annotated_for_RawEmbeddedResource": { + "type": "object", + "required": [ + "resource" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "resource": { + "$ref": "#/definitions/ResourceContents" + } + } + }, + "Annotated_for_RawResource": { + "description": "Represents a resource in the extension with metadata", + "type": "object", + "required": [ + "name", + "uri" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "description": { + "description": "Optional description of the resource", + "type": [ + "string", + "null" + ] + }, + "mimeType": { + "description": "MIME type of the resource content (\"text\" or \"blob\")", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "Name of the resource", + "type": "string" + }, + "size": { + "description": "The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.\n\nThis can be used by Hosts to display file sizes and estimate context window us", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "uri": { + "description": "URI representing the resource location (e.g., \"file:///path/to/file\" or \"str:///content\")", + "type": "string" + } + } + }, + "Annotated_for_RawResourceTemplate": { + "type": "object", + "required": [ + "name", + "uriTemplate" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "mimeType": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "uriTemplate": { + "type": "string" + } + } + }, + "Annotations": { + "type": "object", + "properties": { + "audience": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Role" + } + }, + "priority": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "timestamp": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "CallToolResult": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/definitions/Annotated_for_RawContent" + } + }, + "isError": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "CancelledNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/cancelled" + }, + "CancelledNotificationParam": { + "type": "object", + "required": [ + "requestId" + ], + "properties": { + "reason": { + "type": [ + "string", + "null" + ] + }, + "requestId": { + "$ref": "#/definitions/NumberOrString" + } + } + }, + "CompleteResult": { + "type": "object", + "required": [ + "completion" + ], + "properties": { + "completion": { + "$ref": "#/definitions/CompletionInfo" + } + } + }, + "CompletionInfo": { + "type": "object", + "required": [ + "values" + ], + "properties": { + "hasMore": { + "type": [ + "boolean", + "null" + ] + }, + "total": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "ContextInclusion": { + "type": "string", + "enum": [ + "allServers", + "none", + "thisServer" + ] + }, + "CreateMessageRequestMethod": { + "type": "string", + "format": "const", + "const": "sampling/createMessage" + }, + "CreateMessageRequestParam": { + "type": "object", + "required": [ + "maxTokens", + "messages" + ], + "properties": { + "includeContext": { + "anyOf": [ + { + "$ref": "#/definitions/ContextInclusion" + }, + { + "type": "null" + } + ] + }, + "maxTokens": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/SamplingMessage" + } + }, + "metadata": true, + "modelPreferences": { + "anyOf": [ + { + "$ref": "#/definitions/ModelPreferences" + }, + { + "type": "null" + } + ] + }, + "stopSequences": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "systemPrompt": { + "type": [ + "string", + "null" + ] + }, + "temperature": { + "type": [ + "number", + "null" + ], + "format": "float" + } + } + }, + "EmptyObject": { + "type": "object" + }, + "ErrorData": { + "description": "Error information for JSON-RPC error responses.", + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "description": "The error type that occurred.", + "type": "integer", + "format": "int32" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + } + }, + "Extensions": true, + "GetPromptResult": { + "type": "object", + "required": [ + "messages" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/PromptMessage" + } + } + } + }, + "Implementation": { + "type": "object", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "InitializeResult": { + "type": "object", + "required": [ + "capabilities", + "protocolVersion", + "serverInfo" + ], + "properties": { + "capabilities": { + "$ref": "#/definitions/ServerCapabilities" + }, + "instructions": { + "type": [ + "string", + "null" + ] + }, + "protocolVersion": { + "$ref": "#/definitions/ProtocolVersion" + }, + "serverInfo": { + "$ref": "#/definitions/Implementation" + } + } + }, + "JsonRpcBatchRequestItem_for_ServerRequest_and_ServerNotification": { + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcRequest_for_ServerRequest" + }, + { + "$ref": "#/definitions/JsonRpcNotification_for_ServerNotification" + } + ] + }, + "JsonRpcBatchResponseItem_for_ServerResult": { + "anyOf": [ + { + "$ref": "#/definitions/JsonRpcResponse_for_ServerResult" + }, + { + "$ref": "#/definitions/JsonRpcError" + } + ] + }, + "JsonRpcError": { + "type": "object", + "required": [ + "error", + "id", + "jsonrpc" + ], + "properties": { + "error": { + "$ref": "#/definitions/ErrorData" + }, + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcNotification_for_ServerNotification": { + "type": "object", + "anyOf": [ + { + "$ref": "#/definitions/Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam" + }, + { + "$ref": "#/definitions/Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam" + }, + { + "$ref": "#/definitions/Notification_for_LoggingMessageNotificationMethod_and_LoggingMessageNotificationParam" + }, + { + "$ref": "#/definitions/Notification_for_ResourceUpdatedNotificationMethod_and_ResourceUpdatedNotificationParam" + }, + { + "$ref": "#/definitions/NotificationNoParam_for_ResourceListChangedNotificationMethod" + }, + { + "$ref": "#/definitions/NotificationNoParam_for_ToolListChangedNotificationMethod" + }, + { + "$ref": "#/definitions/NotificationNoParam_for_PromptListChangedNotificationMethod" + } + ], + "required": [ + "jsonrpc" + ], + "properties": { + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcRequest_for_ServerRequest": { + "type": "object", + "anyOf": [ + { + "$ref": "#/definitions/RequestNoParam_for_PingRequestMethod" + }, + { + "$ref": "#/definitions/Request_for_CreateMessageRequestMethod_and_CreateMessageRequestParam" + }, + { + "$ref": "#/definitions/RequestNoParam_for_ListRootsRequestMethod" + } + ], + "required": [ + "id", + "jsonrpc" + ], + "properties": { + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + } + } + }, + "JsonRpcResponse_for_ServerResult": { + "type": "object", + "required": [ + "id", + "jsonrpc", + "result" + ], + "properties": { + "id": { + "$ref": "#/definitions/NumberOrString" + }, + "jsonrpc": { + "$ref": "#/definitions/JsonRpcVersion2_0" + }, + "result": { + "$ref": "#/definitions/ServerResult" + } + } + }, + "JsonRpcVersion2_0": { + "type": "string", + "format": "const", + "const": "2.0" + }, + "ListPromptsResult": { + "type": "object", + "required": [ + "prompts" + ], + "properties": { + "nextCursor": { + "type": [ + "string", + "null" + ] + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/definitions/Prompt" + } + } + } + }, + "ListResourceTemplatesResult": { + "type": "object", + "required": [ + "resourceTemplates" + ], + "properties": { + "nextCursor": { + "type": [ + "string", + "null" + ] + }, + "resourceTemplates": { + "type": "array", + "items": { + "$ref": "#/definitions/Annotated_for_RawResourceTemplate" + } + } + } + }, + "ListResourcesResult": { + "type": "object", + "required": [ + "resources" + ], + "properties": { + "nextCursor": { + "type": [ + "string", + "null" + ] + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/definitions/Annotated_for_RawResource" + } + } + } + }, + "ListRootsRequestMethod": { + "type": "string", + "format": "const", + "const": "roots/list" + }, + "ListToolsResult": { + "type": "object", + "required": [ + "tools" + ], + "properties": { + "nextCursor": { + "type": [ + "string", + "null" + ] + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/Tool" + } + } + } + }, + "LoggingLevel": { + "type": "string", + "enum": [ + "debug", + "info", + "notice", + "warning", + "error", + "critical", + "alert", + "emergency" + ] + }, + "LoggingMessageNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/message" + }, + "LoggingMessageNotificationParam": { + "type": "object", + "required": [ + "data", + "level" + ], + "properties": { + "data": true, + "level": { + "$ref": "#/definitions/LoggingLevel" + }, + "logger": { + "type": [ + "string", + "null" + ] + } + } + }, + "ModelHint": { + "type": "object", + "properties": { + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "ModelPreferences": { + "type": "object", + "properties": { + "costPriority": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "hints": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/ModelHint" + } + }, + "intelligencePriority": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "speedPriority": { + "type": [ + "number", + "null" + ], + "format": "float" + } + } + }, + "NotificationNoParam_for_PromptListChangedNotificationMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/PromptListChangedNotificationMethod" + } + } + }, + "NotificationNoParam_for_ResourceListChangedNotificationMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ResourceListChangedNotificationMethod" + } + } + }, + "NotificationNoParam_for_ToolListChangedNotificationMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ToolListChangedNotificationMethod" + } + } + }, + "Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/CancelledNotificationMethod" + }, + "params": { + "$ref": "#/definitions/CancelledNotificationParam" + } + } + }, + "Notification_for_LoggingMessageNotificationMethod_and_LoggingMessageNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/LoggingMessageNotificationMethod" + }, + "params": { + "$ref": "#/definitions/LoggingMessageNotificationParam" + } + } + }, + "Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ProgressNotificationMethod" + }, + "params": { + "$ref": "#/definitions/ProgressNotificationParam" + } + } + }, + "Notification_for_ResourceUpdatedNotificationMethod_and_ResourceUpdatedNotificationParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ResourceUpdatedNotificationMethod" + }, + "params": { + "$ref": "#/definitions/ResourceUpdatedNotificationParam" + } + } + }, + "NumberOrString": { + "oneOf": [ + { + "type": "object", + "required": [ + "Number" + ], + "properties": { + "Number": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "String" + ], + "properties": { + "String": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "PingRequestMethod": { + "type": "string", + "format": "const", + "const": "ping" + }, + "ProgressNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/progress" + }, + "ProgressNotificationParam": { + "type": "object", + "required": [ + "progress", + "progressToken" + ], + "properties": { + "message": { + "description": "An optional message describing the current progress.", + "type": [ + "string", + "null" + ] + }, + "progress": { + "description": "The progress thus far. This should increase every time progress is made, even if the total is unknown.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "progressToken": { + "$ref": "#/definitions/NumberOrString" + }, + "total": { + "description": "Total number of items to process (or total progress required), if known", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + } + }, + "Prompt": { + "description": "A prompt that can be used to generate text from a model", + "type": "object", + "required": [ + "name" + ], + "properties": { + "arguments": { + "description": "Optional arguments that can be passed to customize the prompt", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/PromptArgument" + } + }, + "description": { + "description": "Optional description of what the prompt does", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "The name of the prompt", + "type": "string" + } + } + }, + "PromptArgument": { + "description": "Represents a prompt argument that can be passed to customize the prompt", + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "description": "A description of what the argument is used for", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "The name of the argument", + "type": "string" + }, + "required": { + "description": "Whether this argument is required", + "type": [ + "boolean", + "null" + ] + } + } + }, + "PromptListChangedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/prompts/list_changed" + }, + "PromptMessage": { + "description": "A message in a prompt conversation", + "type": "object", + "required": [ + "content", + "role" + ], + "properties": { + "content": { + "description": "The content of the message", + "allOf": [ + { + "$ref": "#/definitions/PromptMessageContent" + } + ] + }, + "role": { + "description": "The role of the message sender", + "allOf": [ + { + "$ref": "#/definitions/PromptMessageRole" + } + ] + } + } + }, + "PromptMessageContent": { + "description": "Content types that can be included in prompt messages", + "oneOf": [ + { + "description": "Plain text content", + "type": "object", + "required": [ + "text", + "type" + ], + "properties": { + "text": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, + { + "description": "Image content with base64-encoded data", + "type": "object", + "required": [ + "data", + "mimeType", + "type" + ], + "properties": { + "annotations": { + "anyOf": [ + { + "$ref": "#/definitions/Annotations" + }, + { + "type": "null" + } + ] + }, + "data": { + "description": "The base64-encoded image", + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "image" + ] + } + } + }, + { + "description": "Embedded server-side resource", + "type": "object", + "required": [ + "resource", + "type" + ], + "properties": { + "resource": { + "$ref": "#/definitions/Annotated_for_RawEmbeddedResource" + }, + "type": { + "type": "string", + "enum": [ + "resource" + ] + } + } + } + ] + }, + "PromptMessageRole": { + "description": "Represents the role of a message sender in a prompt conversation", + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "PromptsCapability": { + "type": "object", + "properties": { + "listChanged": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "ProtocolVersion": { + "type": "string" + }, + "ReadResourceResult": { + "type": "object", + "required": [ + "contents" + ], + "properties": { + "contents": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceContents" + } + } + } + }, + "RequestNoParam_for_ListRootsRequestMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/ListRootsRequestMethod" + } + } + }, + "RequestNoParam_for_PingRequestMethod": { + "type": "object", + "required": [ + "extensions", + "method" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/PingRequestMethod" + } + } + }, + "Request_for_CreateMessageRequestMethod_and_CreateMessageRequestParam": { + "type": "object", + "required": [ + "extensions", + "method", + "params" + ], + "properties": { + "extensions": { + "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", + "allOf": [ + { + "$ref": "#/definitions/Extensions" + } + ] + }, + "method": { + "$ref": "#/definitions/CreateMessageRequestMethod" + }, + "params": { + "$ref": "#/definitions/CreateMessageRequestParam" + } + } + }, + "ResourceContents": { + "anyOf": [ + { + "type": "object", + "required": [ + "text", + "uri" + ], + "properties": { + "mime_type": { + "type": [ + "string", + "null" + ] + }, + "text": { + "type": "string" + }, + "uri": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "blob", + "uri" + ], + "properties": { + "blob": { + "type": "string" + }, + "mime_type": { + "type": [ + "string", + "null" + ] + }, + "uri": { + "type": "string" + } + } + } + ] + }, + "ResourceListChangedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/resources/list_changed" + }, + "ResourceUpdatedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/resources/updated" + }, + "ResourceUpdatedNotificationParam": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "uri": { + "type": "string" + } + } + }, + "ResourcesCapability": { + "type": "object", + "properties": { + "listChanged": { + "type": [ + "boolean", + "null" + ] + }, + "subscribe": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "Role": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "SamplingMessage": { + "type": "object", + "required": [ + "content", + "role" + ], + "properties": { + "content": { + "$ref": "#/definitions/Annotated_for_RawContent" + }, + "role": { + "$ref": "#/definitions/Role" + } + } + }, + "ServerCapabilities": { + "title": "Builder", + "description": "```rust # use rmcp::model::ServerCapabilities; let cap = ServerCapabilities::builder() .enable_logging() .enable_experimental() .enable_prompts() .enable_resources() .enable_tools() .enable_tool_list_changed() .build(); ```", + "type": "object", + "properties": { + "completions": { + "type": [ + "object", + "null" + ], + "additionalProperties": true + }, + "experimental": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "object", + "additionalProperties": true + } + }, + "logging": { + "type": [ + "object", + "null" + ], + "additionalProperties": true + }, + "prompts": { + "anyOf": [ + { + "$ref": "#/definitions/PromptsCapability" + }, + { + "type": "null" + } + ] + }, + "resources": { + "anyOf": [ + { + "$ref": "#/definitions/ResourcesCapability" + }, + { + "type": "null" + } + ] + }, + "tools": { + "anyOf": [ + { + "$ref": "#/definitions/ToolsCapability" + }, + { + "type": "null" + } + ] + } + } + }, + "ServerResult": { + "anyOf": [ + { + "$ref": "#/definitions/InitializeResult" + }, + { + "$ref": "#/definitions/CompleteResult" + }, + { + "$ref": "#/definitions/GetPromptResult" + }, + { + "$ref": "#/definitions/ListPromptsResult" + }, + { + "$ref": "#/definitions/ListResourcesResult" + }, + { + "$ref": "#/definitions/ListResourceTemplatesResult" + }, + { + "$ref": "#/definitions/ReadResourceResult" + }, + { + "$ref": "#/definitions/CallToolResult" + }, + { + "$ref": "#/definitions/ListToolsResult" + }, + { + "$ref": "#/definitions/EmptyObject" + } + ] + }, + "Tool": { + "description": "A tool that can be used by a model.", + "type": "object", + "required": [ + "inputSchema", + "name" + ], + "properties": { + "annotations": { + "description": "Optional additional tool information.", + "anyOf": [ + { + "$ref": "#/definitions/ToolAnnotations" + }, + { + "type": "null" + } + ] + }, + "description": { + "description": "A description of what the tool does", + "type": [ + "string", + "null" + ] + }, + "inputSchema": { + "description": "A JSON Schema object defining the expected parameters for the tool", + "type": "object", + "additionalProperties": true + }, + "name": { + "description": "The name of the tool", + "type": "string" + } + } + }, + "ToolAnnotations": { + "description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.", + "type": "object", + "properties": { + "destructiveHint": { + "description": "If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: true A human-readable description of the tool's purpose.", + "type": [ + "boolean", + "null" + ] + }, + "idempotentHint": { + "description": "If true, calling the tool repeatedly with the same arguments will have no additional effect on the its environment.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: false.", + "type": [ + "boolean", + "null" + ] + }, + "openWorldHint": { + "description": "If true, this tool may interact with an \"open world\" of external entities. If false, the tool's domain of interaction is closed. For example, the world of a web search tool is open, whereas that of a memory tool is not.\n\nDefault: true", + "type": [ + "boolean", + "null" + ] + }, + "readOnlyHint": { + "description": "If true, the tool does not modify its environment.\n\nDefault: false", + "type": [ + "boolean", + "null" + ] + }, + "title": { + "description": "A human-readable title for the tool.", + "type": [ + "string", + "null" + ] + } + } + }, + "ToolListChangedNotificationMethod": { + "type": "string", + "format": "const", + "const": "notifications/tools/list_changed" + }, + "ToolsCapability": { + "type": "object", + "properties": { + "listChanged": { + "type": [ + "boolean", + "null" + ] + } + } + } + } +} \ No newline at end of file From d419550fd7e5ee81e90838c1fe71e3d2eceb23af Mon Sep 17 00:00:00 2001 From: Stanley Horwood Date: Thu, 15 May 2025 17:46:18 +0200 Subject: [PATCH 2/3] 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. --- crates/rmcp/src/model.rs | 27 ++++++++++++++++++- .../client_json_rpc_message_schema.json | 24 ++--------------- .../server_json_rpc_message_schema.json | 24 ++--------------- 3 files changed, 30 insertions(+), 45 deletions(-) diff --git a/crates/rmcp/src/model.rs b/crates/rmcp/src/model.rs index fc910ac1..f8c02f22 100644 --- a/crates/rmcp/src/model.rs +++ b/crates/rmcp/src/model.rs @@ -150,7 +150,6 @@ impl<'de> Deserialize<'de> for ProtocolVersion { } #[derive(Debug, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum NumberOrString { Number(u32), String(Arc), @@ -203,6 +202,32 @@ impl<'de> Deserialize<'de> for NumberOrString { } } +#[cfg(feature = "schemars")] +impl schemars::JsonSchema for NumberOrString { + fn schema_name() -> String { + "NumberOrString".to_string() + } + + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { + schemars::schema::Schema::Object(schemars::schema::SchemaObject { + subschemas: Some(Box::new(schemars::schema::SubschemaValidation { + one_of: Some(vec![ + schemars::schema::Schema::Object(schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::Number.into()), + ..Default::default() + }), + schemars::schema::Schema::Object(schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::String.into()), + ..Default::default() + }), + ]), + ..Default::default() + })), + ..Default::default() + }) + } +} + pub type RequestId = NumberOrString; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)] diff --git a/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json index b3342902..de9229fd 100644 --- a/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json +++ b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json @@ -691,30 +691,10 @@ "NumberOrString": { "oneOf": [ { - "type": "object", - "required": [ - "Number" - ], - "properties": { - "Number": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false + "type": "number" }, { - "type": "object", - "required": [ - "String" - ], - "properties": { - "String": { - "type": "string" - } - }, - "additionalProperties": false + "type": "string" } ] }, diff --git a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json index 77fef38d..cc95220a 100644 --- a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json +++ b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json @@ -966,30 +966,10 @@ "NumberOrString": { "oneOf": [ { - "type": "object", - "required": [ - "Number" - ], - "properties": { - "Number": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false + "type": "number" }, { - "type": "object", - "required": [ - "String" - ], - "properties": { - "String": { - "type": "string" - } - }, - "additionalProperties": false + "type": "string" } ] }, From e21125444eed7db6c7214584ef058f8cef6c282b Mon Sep 17 00:00:00 2001 From: Stanley Horwood Date: Thu, 15 May 2025 17:46:19 +0200 Subject: [PATCH 3/3] 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. --- crates/rmcp/src/model.rs | 5 + crates/rmcp/src/model/extension.rs | 10 -- crates/rmcp/tests/test_message_schema.rs | 30 +++- .../client_json_rpc_message_schema.json | 154 ------------------ .../server_json_rpc_message_schema.json | 91 ----------- 5 files changed, 29 insertions(+), 261 deletions(-) diff --git a/crates/rmcp/src/model.rs b/crates/rmcp/src/model.rs index f8c02f22..620c0a61 100644 --- a/crates/rmcp/src/model.rs +++ b/crates/rmcp/src/model.rs @@ -243,6 +243,7 @@ pub struct Request { /// extensions will carry anything possible in the context, including [`Meta`] /// /// this is similar with the Extensions in `http` crate + #[cfg_attr(feature = "schemars", schemars(skip))] pub extensions: Extensions, } @@ -264,6 +265,7 @@ pub struct RequestOptionalParam { /// extensions will carry anything possible in the context, including [`Meta`] /// /// this is similar with the Extensions in `http` crate + #[cfg_attr(feature = "schemars", schemars(skip))] pub extensions: Extensions, } @@ -274,6 +276,7 @@ pub struct RequestNoParam { /// extensions will carry anything possible in the context, including [`Meta`] /// /// this is similar with the Extensions in `http` crate + #[cfg_attr(feature = "schemars", schemars(skip))] pub extensions: Extensions, } @@ -293,6 +296,7 @@ pub struct Notification { /// extensions will carry anything possible in the context, including [`Meta`] /// /// this is similar with the Extensions in `http` crate + #[cfg_attr(feature = "schemars", schemars(skip))] pub extensions: Extensions, } @@ -303,6 +307,7 @@ pub struct NotificationNoParam { /// extensions will carry anything possible in the context, including [`Meta`] /// /// this is similar with the Extensions in `http` crate + #[cfg_attr(feature = "schemars", schemars(skip))] pub extensions: Extensions, } diff --git a/crates/rmcp/src/model/extension.rs b/crates/rmcp/src/model/extension.rs index cc6afbe4..a9d78d4c 100644 --- a/crates/rmcp/src/model/extension.rs +++ b/crates/rmcp/src/model/extension.rs @@ -279,16 +279,6 @@ impl fmt::Debug for Extensions { } } -impl schemars::JsonSchema for Extensions { - fn schema_name() -> String { - "Extensions".to_string() - } - - fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { - generator.subschema_for::() - } -} - trait AnyClone: Any { fn clone_box(&self) -> Box; fn as_any(&self) -> &dyn Any; diff --git a/crates/rmcp/tests/test_message_schema.rs b/crates/rmcp/tests/test_message_schema.rs index fb7fd8d9..71c21f8f 100644 --- a/crates/rmcp/tests/test_message_schema.rs +++ b/crates/rmcp/tests/test_message_schema.rs @@ -1,22 +1,40 @@ -#[cfg(feature = "schemars")] mod tests { use rmcp::model::{ClientJsonRpcMessage, ServerJsonRpcMessage}; - use super::*; use schemars::schema_for; #[test] fn test_client_json_rpc_message_schema() { let schema = schema_for!(ClientJsonRpcMessage); let schema_str = serde_json::to_string_pretty(&schema).unwrap(); - let expected = std::fs::read_to_string("tests/test_message_schema/client_json_rpc_message_schema.json").unwrap(); - assert_eq!(schema_str, expected, "Schema generation for ClientJsonRpcMessage should match expected output"); + let expected = std::fs::read_to_string( + "tests/test_message_schema/client_json_rpc_message_schema.json", + ) + .unwrap(); + + // Parse both strings to JSON values for more robust comparison + let schema_json: serde_json::Value = serde_json::from_str(&schema_str).unwrap(); + let expected_json: serde_json::Value = serde_json::from_str(&expected).unwrap(); + assert_eq!( + schema_json, expected_json, + "Schema generation for ClientJsonRpcMessage should match expected output" + ); } #[test] fn test_server_json_rpc_message_schema() { let schema = schema_for!(ServerJsonRpcMessage); let schema_str = serde_json::to_string_pretty(&schema).unwrap(); - let expected = std::fs::read_to_string("tests/test_message_schema/server_json_rpc_message_schema.json").unwrap(); - assert_eq!(schema_str, expected, "Schema generation for ServerJsonRpcMessage should match expected output"); + let expected = std::fs::read_to_string( + "tests/test_message_schema/server_json_rpc_message_schema.json", + ) + .unwrap(); + + // Parse both strings to JSON values for more robust comparison + let schema_json: serde_json::Value = serde_json::from_str(&schema_str).unwrap(); + let expected_json: serde_json::Value = serde_json::from_str(&expected).unwrap(); + assert_eq!( + schema_json, expected_json, + "Schema generation for ServerJsonRpcMessage should match expected output" + ); } } diff --git a/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json index de9229fd..81189407 100644 --- a/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json +++ b/crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json @@ -341,7 +341,6 @@ } } }, - "Extensions": true, "GetPromptRequestMethod": { "type": "string", "format": "const", @@ -603,18 +602,9 @@ "NotificationNoParam_for_InitializedNotificationMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/InitializedNotificationMethod" } @@ -623,18 +613,9 @@ "NotificationNoParam_for_RootsListChangedNotificationMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/RootsListChangedNotificationMethod" } @@ -643,19 +624,10 @@ "Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/CancelledNotificationMethod" }, @@ -667,19 +639,10 @@ "Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ProgressNotificationMethod" }, @@ -815,18 +778,9 @@ "RequestNoParam_for_PingRequestMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/PingRequestMethod" } @@ -835,18 +789,9 @@ "RequestOptionalParam_for_ListPromptsRequestMethod_and_PaginatedRequestParam": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ListPromptsRequestMethod" }, @@ -865,18 +810,9 @@ "RequestOptionalParam_for_ListResourceTemplatesRequestMethod_and_PaginatedRequestParam": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ListResourceTemplatesRequestMethod" }, @@ -895,18 +831,9 @@ "RequestOptionalParam_for_ListResourcesRequestMethod_and_PaginatedRequestParam": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ListResourcesRequestMethod" }, @@ -925,18 +852,9 @@ "RequestOptionalParam_for_ListToolsRequestMethod_and_PaginatedRequestParam": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ListToolsRequestMethod" }, @@ -955,19 +873,10 @@ "Request_for_CallToolRequestMethod_and_CallToolRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/CallToolRequestMethod" }, @@ -979,19 +888,10 @@ "Request_for_CompleteRequestMethod_and_CompleteRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/CompleteRequestMethod" }, @@ -1003,19 +903,10 @@ "Request_for_GetPromptRequestMethod_and_GetPromptRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/GetPromptRequestMethod" }, @@ -1027,19 +918,10 @@ "Request_for_InitializeResultMethod_and_InitializeRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/InitializeResultMethod" }, @@ -1051,19 +933,10 @@ "Request_for_ReadResourceRequestMethod_and_ReadResourceRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ReadResourceRequestMethod" }, @@ -1075,19 +948,10 @@ "Request_for_SetLevelRequestMethod_and_SetLevelRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/SetLevelRequestMethod" }, @@ -1099,19 +963,10 @@ "Request_for_SubscribeRequestMethod_and_SubscribeRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/SubscribeRequestMethod" }, @@ -1123,19 +978,10 @@ "Request_for_UnsubscribeRequestMethod_and_UnsubscribeRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/UnsubscribeRequestMethod" }, diff --git a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json index cc95220a..e0378db3 100644 --- a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json +++ b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json @@ -455,7 +455,6 @@ } } }, - "Extensions": true, "GetPromptResult": { "type": "object", "required": [ @@ -810,18 +809,9 @@ "NotificationNoParam_for_PromptListChangedNotificationMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/PromptListChangedNotificationMethod" } @@ -830,18 +820,9 @@ "NotificationNoParam_for_ResourceListChangedNotificationMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ResourceListChangedNotificationMethod" } @@ -850,18 +831,9 @@ "NotificationNoParam_for_ToolListChangedNotificationMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ToolListChangedNotificationMethod" } @@ -870,19 +842,10 @@ "Notification_for_CancelledNotificationMethod_and_CancelledNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/CancelledNotificationMethod" }, @@ -894,19 +857,10 @@ "Notification_for_LoggingMessageNotificationMethod_and_LoggingMessageNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/LoggingMessageNotificationMethod" }, @@ -918,19 +872,10 @@ "Notification_for_ProgressNotificationMethod_and_ProgressNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ProgressNotificationMethod" }, @@ -942,19 +887,10 @@ "Notification_for_ResourceUpdatedNotificationMethod_and_ResourceUpdatedNotificationParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ResourceUpdatedNotificationMethod" }, @@ -1221,18 +1157,9 @@ "RequestNoParam_for_ListRootsRequestMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/ListRootsRequestMethod" } @@ -1241,18 +1168,9 @@ "RequestNoParam_for_PingRequestMethod": { "type": "object", "required": [ - "extensions", "method" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/PingRequestMethod" } @@ -1261,19 +1179,10 @@ "Request_for_CreateMessageRequestMethod_and_CreateMessageRequestParam": { "type": "object", "required": [ - "extensions", "method", "params" ], "properties": { - "extensions": { - "description": "extensions will carry anything possible in the context, including [`Meta`]\n\nthis is similar with the Extensions in `http` crate", - "allOf": [ - { - "$ref": "#/definitions/Extensions" - } - ] - }, "method": { "$ref": "#/definitions/CreateMessageRequestMethod" },