diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 012d826..f54d4ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,16 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Cache Rust + uses: actions/cache@v4 + with: + path: | + ~/.rustup/toolchains + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-rust-${{ steps.toolchain.outputs.cachekey }} + restore-keys: ${{ runner.os }}-rust- - name: Install Rust Toolchain uses: dtolnay/rust-toolchain@master diff --git a/Cargo.toml b/Cargo.toml index dd1ead5..5ba013a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ features = ["2024_11_05", "schema_utils"] [features] # defalt features -default = ["2024_11_05", "schema_utils"] # Default features +default = ["2025_03_26", "schema_utils"] # Default features # activates the latest MCP schema version, this will be updated once a new version of schema is published latest = ["2025_03_26"] diff --git a/README.md b/README.md index 3ceb274..d8fe5eb 100644 --- a/README.md +++ b/README.md @@ -77,15 +77,15 @@ This repository provides all official released versions the schema , including d ### How to switch between different schema versions? Each schema version has a corresponding Cargo feature that can be enabled in your project's Cargo.toml. -By default, the version `2024_11_05` of the schema is active. +By default, the version `2025_03_26` of the schema is active. -Example: enable `2025_03_26` version of the shema: +Example: enable `2024_11_05` version of the shema: ```toml # Cargo.toml -rust-mcp-schema = { version: 0.4.0 , features=["2025_03_26"] } +rust-mcp-schema = { version: 0.4.0 , features=["2024_11_05"] } ``` Example: enable `latest` version of the shema: @@ -95,11 +95,11 @@ Example: enable `latest` version of the shema: rust-mcp-schema = { version: 0.4.0 , features=["latest"] } ``` -Example: enable specific version of the shema (2024_11_05) : +Example: enable `draft`` version of the shema (2024_11_05) : ```toml #Cargo.toml -rust-mcp-schema = { version: 0.4.0 , features=["2024_11_05"] } +rust-mcp-schema = { version: 0.4.0 , features=["draft"] } ``` @@ -324,7 +324,7 @@ fn handle_message(message_payload: &str) -> std::result::Result<(), AppError> { We welcome everyone who wishes to contribute! Please refer to the [contributing guidelines](CONTRIBUTING.md) for more details. -All contributions, including issues and pull requests, must follow +All contributions, including issues and pull requests, must follow [Rust's Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). Unless explicitly stated otherwise, any contribution you submit for inclusion in `rust-mcp-schema` is provided under the terms of the MIT License, without any additional conditions or restrictions. diff --git a/examples/mcp_client_handle_message.rs b/examples/mcp_client_handle_message.rs index b0e5379..afa1857 100644 --- a/examples/mcp_client_handle_message.rs +++ b/examples/mcp_client_handle_message.rs @@ -122,9 +122,18 @@ fn handle_message(message_payload: &str) -> std::result::Result<(), AppError> { ServerResult::ListToolsResult(list_tools_result) => { dbg!(list_tools_result); } + #[cfg(any(feature = "2025_03_26", feature = "2024_11_05"))] ServerResult::CallToolResult(call_tool_result) => { dbg!(call_tool_result); } + #[cfg(feature = "draft")] + ServerResult::CallToolUnstructuredResult(call_tool_unstructured_result) => { + dbg!(call_tool_unstructured_result); + } + #[cfg(feature = "draft")] + ServerResult::CallToolStructuredResult(call_tool_structured_result) => { + dbg!(call_tool_structured_result); + } ServerResult::CompleteResult(complete_result) => { dbg!(complete_result); } diff --git a/src/generated_schema.rs b/src/generated_schema.rs index f95ede3..e2348fa 100644 --- a/src/generated_schema.rs +++ b/src/generated_schema.rs @@ -1,44 +1,35 @@ -/// Schema Version : 2024_11_05 +/// Schema Version: 2024_11_05 #[cfg(feature = "2024_11_05")] #[path = "generated_schema/2024_11_05/mcp_schema.rs"] -mod schema_2024_11_05; +mod mcp_schema; #[cfg(feature = "2024_11_05")] -pub use schema_2024_11_05::*; +pub use mcp_schema::*; #[cfg(all(feature = "schema_utils", feature = "2024_11_05"))] #[path = "generated_schema/2024_11_05/schema_utils.rs"] pub mod schema_utils; -/// Schema Version : 2025_03_26 +/// Schema Version: 2025_03_26 #[cfg(feature = "2025_03_26")] -#[cfg(not(feature = "2024_11_05"))] #[path = "generated_schema/2025_03_26/mcp_schema.rs"] -mod schema_2025_03_26; +mod mcp_schema; #[cfg(feature = "2025_03_26")] -#[cfg(not(feature = "2024_11_05"))] -pub use schema_2025_03_26::*; +pub use mcp_schema::*; #[cfg(all(feature = "schema_utils", feature = "2025_03_26"))] -#[cfg(not(feature = "2024_11_05"))] #[path = "generated_schema/2025_03_26/schema_utils.rs"] pub mod schema_utils; -/// Schema Version : draft +/// Schema Version: draft #[cfg(feature = "draft")] -#[cfg(not(feature = "2024_11_05"))] -#[cfg(not(feature = "2025_03_26"))] #[path = "generated_schema/draft/mcp_schema.rs"] -mod schema_draft; +mod mcp_schema; #[cfg(feature = "draft")] -#[cfg(not(feature = "2024_11_05"))] -#[cfg(not(feature = "2025_03_26"))] -pub use schema_draft::*; +pub use mcp_schema::*; #[cfg(all(feature = "schema_utils", feature = "draft"))] -#[cfg(not(feature = "2024_11_05"))] -#[cfg(not(feature = "2025_03_26"))] #[path = "generated_schema/draft/schema_utils.rs"] pub mod schema_utils; diff --git a/src/generated_schema/2024_11_05/mcp_schema.rs b/src/generated_schema/2024_11_05/mcp_schema.rs index 369e1d2..9dfad90 100644 --- a/src/generated_schema/2024_11_05/mcp_schema.rs +++ b/src/generated_schema/2024_11_05/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.2.0. +/// This file is auto-generated by mcp-schema-gen v0.3.0. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 5da5bac89165d68cad24a211119e4c1b61178d5a -/// Generated at : 2025年04月26日 18:56:03 +/// Hash : UNKNOWN +/// Generated at : 2025年05月20日 20:52:14 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version diff --git a/src/generated_schema/2025_03_26/mcp_schema.rs b/src/generated_schema/2025_03_26/mcp_schema.rs index 6d95e5b..1bd75f3 100644 --- a/src/generated_schema/2025_03_26/mcp_schema.rs +++ b/src/generated_schema/2025_03_26/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.2.0. +/// This file is auto-generated by mcp-schema-gen v0.3.0. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 5da5bac89165d68cad24a211119e4c1b61178d5a -/// Generated at : 2025年04月26日 18:56:03 +/// Hash : UNKNOWN +/// Generated at : 2025年05月20日 20:52:15 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version diff --git a/src/generated_schema/2025_03_26/schema_utils.rs b/src/generated_schema/2025_03_26/schema_utils.rs index 4ac6368..e5d1d50 100644 --- a/src/generated_schema/2025_03_26/schema_utils.rs +++ b/src/generated_schema/2025_03_26/schema_utils.rs @@ -15,7 +15,7 @@ pub enum MessageTypes { /// Implements the `Display` trait for the `MessageTypes` enum, /// allowing it to be converted into a human-readable string. impl Display for MessageTypes { - /// Formats the `MessageTypes` enum variant as a string. + /// Formats the `MessageTypes` enum variant as a string. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -1071,6 +1071,7 @@ impl FromStr for ServerJsonrpcResponse { /// To determine standard and custom results from the server side /// Custom results (CustomResult) are of type serde_json::Value and can be deserialized into any custom type. +#[allow(clippy::large_enum_variant)] #[derive(::serde::Serialize, Clone, Debug)] #[serde(untagged)] pub enum ResultFromServer { diff --git a/src/generated_schema/draft/mcp_schema.rs b/src/generated_schema/draft/mcp_schema.rs index 36bc1d4..c58be77 100644 --- a/src/generated_schema/draft/mcp_schema.rs +++ b/src/generated_schema/draft/mcp_schema.rs @@ -1,12 +1,12 @@ /// ---------------------------------------------------------------------------- -/// This file is auto-generated by mcp-schema-gen v0.2.0. +/// This file is auto-generated by mcp-schema-gen v0.3.0. /// WARNING: /// It is not recommended to modify this file directly. You are free to /// modify or extend the implementations as needed, but please do so at your own risk. /// /// Generated from : -/// Hash : 5da5bac89165d68cad24a211119e4c1b61178d5a -/// Generated at : 2025年04月26日 18:56:03 +/// Hash : UNKNOWN +/// Generated at : 2025年05月20日 20:52:15 /// ---------------------------------------------------------------------------- /// /// MCP Protocol Version @@ -263,6 +263,160 @@ should be reported as an MCP error response.*/ /// ```json ///{ /// "description": "The server's response to a tool call.\n\nAny errors that originate from the tool SHOULD be reported inside the result\nobject, with isError set to true, _not_ as an MCP protocol-level error\nresponse. Otherwise, the LLM would not be able to see that an error occurred\nand self-correct.\n\nHowever, any errors in _finding_ the tool, an error indicating that the\nserver does not support tool calls, or any other exceptional conditions,\nshould be reported as an MCP error response.", +/// "anyOf": [ +/// { +/// "$ref": "#/definitions/CallToolUnstructuredResult" +/// }, +/// { +/// "$ref": "#/definitions/CallToolStructuredResult" +/// } +/// ] +///} +/// ``` +/// +#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum CallToolResult { + UnstructuredResult(CallToolUnstructuredResult), + StructuredResult(CallToolStructuredResult), +} +impl ::std::convert::From for CallToolResult { + fn from(value: CallToolUnstructuredResult) -> Self { + Self::UnstructuredResult(value) + } +} +impl ::std::convert::From for CallToolResult { + fn from(value: CallToolStructuredResult) -> Self { + Self::StructuredResult(value) + } +} +///Tool result for tools that do declare an outputSchema. +/// +///
JSON schema +/// +/// ```json +///{ +/// "description": "Tool result for tools that do declare an outputSchema.", +/// "type": "object", +/// "required": [ +/// "structuredContent" +/// ], +/// "properties": { +/// "_meta": { +/// "description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.", +/// "type": "object", +/// "additionalProperties": {} +/// }, +/// "content": { +/// "description": "If the Tool defines an outputSchema, this field MAY be present in the result.\nTools should use this field to provide compatibility with older clients that do not support structured content.\nClients that support structured content should ignore this field.", +/// "type": "array", +/// "items": { +/// "anyOf": [ +/// { +/// "$ref": "#/definitions/TextContent" +/// }, +/// { +/// "$ref": "#/definitions/ImageContent" +/// }, +/// { +/// "$ref": "#/definitions/AudioContent" +/// }, +/// { +/// "$ref": "#/definitions/EmbeddedResource" +/// } +/// ] +/// } +/// }, +/// "isError": { +/// "description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).", +/// "type": "boolean" +/// }, +/// "structuredContent": { +/// "description": "An object containing structured tool output.\n\nIf the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.", +/// "type": "object", +/// "additionalProperties": {} +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct CallToolStructuredResult { + /**If the Tool defines an outputSchema, this field MAY be present in the result. + Tools should use this field to provide compatibility with older clients that do not support structured content. + Clients that support structured content should ignore this field.*/ + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub content: ::std::vec::Vec, + /**Whether the tool call ended in an error. + If not set, this is assumed to be false (the call was successful).*/ + #[serde(rename = "isError", default, skip_serializing_if = "::std::option::Option::is_none")] + pub is_error: ::std::option::Option, + ///This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses. + #[serde(rename = "_meta", default, skip_serializing_if = "::std::option::Option::is_none")] + pub meta: ::std::option::Option<::serde_json::map<::std::string::string, ::serde_json::Value>>, + /**An object containing structured tool output. + If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.*/ + #[serde(rename = "structuredContent")] + pub structured_content: ::serde_json::Map<::std::string::string, ::serde_json::Value>, +} +///CallToolStructuredResultContentItem +/// +///
JSON schema +/// +/// ```json +///{ +/// "anyOf": [ +/// { +/// "$ref": "#/definitions/TextContent" +/// }, +/// { +/// "$ref": "#/definitions/ImageContent" +/// }, +/// { +/// "$ref": "#/definitions/AudioContent" +/// }, +/// { +/// "$ref": "#/definitions/EmbeddedResource" +/// } +/// ] +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum CallToolStructuredResultContentItem { + TextContent(TextContent), + ImageContent(ImageContent), + AudioContent(AudioContent), + EmbeddedResource(EmbeddedResource), +} +impl ::std::convert::From for CallToolStructuredResultContentItem { + fn from(value: TextContent) -> Self { + Self::TextContent(value) + } +} +impl ::std::convert::From for CallToolStructuredResultContentItem { + fn from(value: ImageContent) -> Self { + Self::ImageContent(value) + } +} +impl ::std::convert::From for CallToolStructuredResultContentItem { + fn from(value: AudioContent) -> Self { + Self::AudioContent(value) + } +} +impl ::std::convert::From for CallToolStructuredResultContentItem { + fn from(value: EmbeddedResource) -> Self { + Self::EmbeddedResource(value) + } +} +///Tool result for tools that do not declare an outputSchema. +/// +///
JSON schema +/// +/// ```json +///{ +/// "description": "Tool result for tools that do not declare an outputSchema.", /// "type": "object", /// "required": [ /// "content" @@ -274,6 +428,7 @@ should be reported as an MCP error response.*/ /// "additionalProperties": {} /// }, /// "content": { +/// "description": "A list of content objects that represent the result of the tool call.\n\nIf the Tool does not define an outputSchema, this field MUST be present in the result.", /// "type": "array", /// "items": { /// "anyOf": [ @@ -301,8 +456,10 @@ should be reported as an MCP error response.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] -pub struct CallToolResult { - pub content: ::std::vec::Vec, +pub struct CallToolUnstructuredResult { + /**A list of content objects that represent the result of the tool call. + If the Tool does not define an outputSchema, this field MUST be present in the result.*/ + pub content: ::std::vec::Vec, /**Whether the tool call ended in an error. If not set, this is assumed to be false (the call was successful).*/ #[serde(rename = "isError", default, skip_serializing_if = "::std::option::Option::is_none")] @@ -311,7 +468,7 @@ pub struct CallToolResult { #[serde(rename = "_meta", default, skip_serializing_if = "::std::option::Option::is_none")] pub meta: ::std::option::Option<::serde_json::map<::std::string::string, ::serde_json::Value>>, } -///CallToolResultContentItem +///CallToolUnstructuredResultContentItem /// ///
JSON schema /// @@ -336,28 +493,28 @@ pub struct CallToolResult { ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(untagged)] -pub enum CallToolResultContentItem { +pub enum CallToolUnstructuredResultContentItem { TextContent(TextContent), ImageContent(ImageContent), AudioContent(AudioContent), EmbeddedResource(EmbeddedResource), } -impl ::std::convert::From for CallToolResultContentItem { +impl ::std::convert::From for CallToolUnstructuredResultContentItem { fn from(value: TextContent) -> Self { Self::TextContent(value) } } -impl ::std::convert::From for CallToolResultContentItem { +impl ::std::convert::From for CallToolUnstructuredResultContentItem { fn from(value: ImageContent) -> Self { Self::ImageContent(value) } } -impl ::std::convert::From for CallToolResultContentItem { +impl ::std::convert::From for CallToolUnstructuredResultContentItem { fn from(value: AudioContent) -> Self { Self::AudioContent(value) } } -impl ::std::convert::From for CallToolResultContentItem { +impl ::std::convert::From for CallToolUnstructuredResultContentItem { fn from(value: EmbeddedResource) -> Self { Self::EmbeddedResource(value) } @@ -1035,6 +1192,86 @@ pub struct CompleteResultCompletion { ///An array of completion values. Must not exceed 100 items. pub values: ::std::vec::Vec<::std::string::string>, } +///ContentList +/// +///
JSON schema +/// +/// ```json +///{ +/// "type": "array", +/// "items": { +/// "anyOf": [ +/// { +/// "$ref": "#/definitions/TextContent" +/// }, +/// { +/// "$ref": "#/definitions/ImageContent" +/// }, +/// { +/// "$ref": "#/definitions/AudioContent" +/// }, +/// { +/// "$ref": "#/definitions/EmbeddedResource" +/// } +/// ] +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct ContentList(pub ::std::vec::Vec); +///ContentListItem +/// +///
JSON schema +/// +/// ```json +///{ +/// "anyOf": [ +/// { +/// "$ref": "#/definitions/TextContent" +/// }, +/// { +/// "$ref": "#/definitions/ImageContent" +/// }, +/// { +/// "$ref": "#/definitions/AudioContent" +/// }, +/// { +/// "$ref": "#/definitions/EmbeddedResource" +/// } +/// ] +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum ContentListItem { + TextContent(TextContent), + ImageContent(ImageContent), + AudioContent(AudioContent), + EmbeddedResource(EmbeddedResource), +} +impl ::std::convert::From for ContentListItem { + fn from(value: TextContent) -> Self { + Self::TextContent(value) + } +} +impl ::std::convert::From for ContentListItem { + fn from(value: ImageContent) -> Self { + Self::ImageContent(value) + } +} +impl ::std::convert::From for ContentListItem { + fn from(value: AudioContent) -> Self { + Self::AudioContent(value) + } +} +impl ::std::convert::From for ContentListItem { + fn from(value: EmbeddedResource) -> Self { + Self::EmbeddedResource(value) + } +} ///A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it. /// ///
JSON schema @@ -5175,7 +5412,10 @@ impl ::std::convert::From for ServerRequest { /// "$ref": "#/definitions/ListToolsResult" /// }, /// { -/// "$ref": "#/definitions/CallToolResult" +/// "$ref": "#/definitions/CallToolUnstructuredResult" +/// }, +/// { +/// "$ref": "#/definitions/CallToolStructuredResult" /// }, /// { /// "$ref": "#/definitions/CompleteResult" @@ -5194,7 +5434,8 @@ pub enum ServerResult { ListPromptsResult(ListPromptsResult), GetPromptResult(GetPromptResult), ListToolsResult(ListToolsResult), - CallToolResult(CallToolResult), + CallToolUnstructuredResult(CallToolUnstructuredResult), + CallToolStructuredResult(CallToolStructuredResult), CompleteResult(CompleteResult), Result(Result), } @@ -5233,9 +5474,14 @@ impl ::std::convert::From for ServerResult { Self::ListToolsResult(value) } } -impl ::std::convert::From for ServerResult { - fn from(value: CallToolResult) -> Self { - Self::CallToolResult(value) +impl ::std::convert::From for ServerResult { + fn from(value: CallToolUnstructuredResult) -> Self { + Self::CallToolUnstructuredResult(value) + } +} +impl ::std::convert::From for ServerResult { + fn from(value: CallToolStructuredResult) -> Self { + Self::CallToolStructuredResult(value) } } impl ::std::convert::From for ServerResult { @@ -5545,6 +5791,32 @@ pub struct TextResourceContents { /// "name": { /// "description": "The name of the tool.", /// "type": "string" +/// }, +/// "outputSchema": { +/// "description": "An optional JSON Schema object defining the structure of the tool's output.\n\nIf set, a CallToolResult for this Tool MUST contain a structuredContent field whose contents validate against this schema.\nIf not set, a CallToolResult for this Tool MUST contain a content field.", +/// "type": "object", +/// "required": [ +/// "type" +/// ], +/// "properties": { +/// "properties": { +/// "type": "object", +/// "additionalProperties": { +/// "type": "object", +/// "additionalProperties": true +/// } +/// }, +/// "required": { +/// "type": "array", +/// "items": { +/// "type": "string" +/// } +/// }, +/// "type": { +/// "type": "string", +/// "const": "object" +/// } +/// } /// } /// } ///} @@ -5563,6 +5835,8 @@ pub struct Tool { pub input_schema: ToolInputSchema, ///The name of the tool. pub name: ::std::string::String, + #[serde(rename = "outputSchema", default, skip_serializing_if = "::std::option::Option::is_none")] + pub output_schema: ::std::option::Option, } /**Additional properties describing a Tool to clients. NOTE: all properties in ToolAnnotations are **hints**. @@ -5775,6 +6049,75 @@ pub struct ToolListChangedNotificationParams { #[serde(flatten, default, skip_serializing_if = "::std::option::Option::is_none")] pub extra: ::std::option::Option<::serde_json::map<::std::string::string, ::serde_json::Value>>, } +/**An optional JSON Schema object defining the structure of the tool's output. +If set, a CallToolResult for this Tool MUST contain a structuredContent field whose contents validate against this schema. +If not set, a CallToolResult for this Tool MUST contain a content field.*/ +/// +///
JSON schema +/// +/// ```json +///{ +/// "description": "An optional JSON Schema object defining the structure of the tool's output.\n\nIf set, a CallToolResult for this Tool MUST contain a structuredContent field whose contents validate against this schema.\nIf not set, a CallToolResult for this Tool MUST contain a content field.", +/// "type": "object", +/// "required": [ +/// "type" +/// ], +/// "properties": { +/// "properties": { +/// "type": "object", +/// "additionalProperties": { +/// "type": "object", +/// "additionalProperties": true +/// } +/// }, +/// "required": { +/// "type": "array", +/// "items": { +/// "type": "string" +/// } +/// }, +/// "type": { +/// "type": "string", +/// "const": "object" +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct ToolOutputSchema { + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub properties: ::std::option::Option< + ::std::collections::HashMap<::std::string::string, ::serde_json::Map<::std::string::string, ::serde_json::Value>>, +>, + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub required: ::std::vec::Vec<::std::string::string>, + #[serde(rename = "type")] + type_: ::std::string::String, +} +impl ToolOutputSchema { + pub fn new( + required: ::std::vec::Vec<::std::string::string>, + properties: ::std::option::Option< + ::std::collections::HashMap< + ::std::string::String, + ::serde_json::Map<::std::string::string, ::serde_json::Value>, +>, +>, + ) -> Self { + Self { + properties, + required, + type_: "object".to_string(), + } + } + pub fn type_(&self) -> &::std::string::String { + &self.type_ + } + pub fn type_name() -> ::std::string::String { + "object".to_string() + } +} ///Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request. /// ///
JSON schema diff --git a/src/generated_schema/draft/schema_utils.rs b/src/generated_schema/draft/schema_utils.rs index 4ac6368..a440f96 100644 --- a/src/generated_schema/draft/schema_utils.rs +++ b/src/generated_schema/draft/schema_utils.rs @@ -15,7 +15,7 @@ pub enum MessageTypes { /// Implements the `Display` trait for the `MessageTypes` enum, /// allowing it to be converted into a human-readable string. impl Display for MessageTypes { - /// Formats the `MessageTypes` enum variant as a string. + /// Formats the `MessageTypes` enum variant as a string. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -1071,6 +1071,7 @@ impl FromStr for ServerJsonrpcResponse { /// To determine standard and custom results from the server side /// Custom results (CustomResult) are of type serde_json::Value and can be deserialized into any custom type. +#[allow(clippy::large_enum_variant)] #[derive(::serde::Serialize, Clone, Debug)] #[serde(untagged)] pub enum ResultFromServer { @@ -1421,11 +1422,11 @@ impl std::error::Error for CallToolError { } } -/// Conversion of `CallToolError` into a `CallToolResult` with an error. -impl From for CallToolResult { +/// Conversion of `CallToolError` into a `CallToolUnstructuredResult` with an error. +impl From for CallToolUnstructuredResult { fn from(value: CallToolError) -> Self { - // Convert `CallToolError` to a `CallToolResult` by using the `with_error` method - CallToolResult::with_error(value) + // Convert `CallToolError` to a `CallToolUnstructuredResult` by using the `with_error` method + CallToolUnstructuredResult::with_error(value) } } @@ -2542,8 +2543,13 @@ impl From for ResultFromServer { Self::ServerResult(value.into()) } } -impl From for ResultFromServer { - fn from(value: CallToolResult) -> Self { +impl From for ResultFromServer { + fn from(value: CallToolUnstructuredResult) -> Self { + Self::ServerResult(value.into()) + } +} +impl From for ResultFromServer { + fn from(value: CallToolStructuredResult) -> Self { Self::ServerResult(value.into()) } } @@ -2592,8 +2598,13 @@ impl From for MessageFromServer { MessageFromServer::ResultFromServer(value.into()) } } -impl From for MessageFromServer { - fn from(value: CallToolResult) -> Self { +impl From for MessageFromServer { + fn from(value: CallToolUnstructuredResult) -> Self { + MessageFromServer::ResultFromServer(value.into()) + } +} +impl From for MessageFromServer { + fn from(value: CallToolStructuredResult) -> Self { MessageFromServer::ResultFromServer(value.into()) } } @@ -3028,8 +3039,11 @@ impl ToMessage for ListToolsResult { ServerMessage::from_message(self, request_id) } } -impl FromMessage for ServerMessage { - fn from_message(message: CallToolResult, request_id: Option) -> std::result::Result { +impl FromMessage for ServerMessage { + fn from_message( + message: CallToolUnstructuredResult, + request_id: Option, + ) -> std::result::Result { let request_id = request_id.ok_or_else(|| RpcError::internal_error().with_message("request_id is None!".to_string()))?; Ok(ServerMessage::Response(ServerJsonrpcResponse::new( @@ -3038,7 +3052,25 @@ impl FromMessage for ServerMessage { ))) } } -impl ToMessage for CallToolResult { +impl ToMessage for CallToolUnstructuredResult { + fn to_message(self, request_id: Option) -> std::result::Result { + ServerMessage::from_message(self, request_id) + } +} +impl FromMessage for ServerMessage { + fn from_message( + message: CallToolStructuredResult, + request_id: Option, + ) -> std::result::Result { + let request_id = + request_id.ok_or_else(|| RpcError::internal_error().with_message("request_id is None!".to_string()))?; + Ok(ServerMessage::Response(ServerJsonrpcResponse::new( + request_id, + message.into(), + ))) + } +} +impl ToMessage for CallToolStructuredResult { fn to_message(self, request_id: Option) -> std::result::Result { ServerMessage::from_message(self, request_id) } @@ -3519,14 +3551,25 @@ impl TryFrom for ListToolsResult { } } } -impl TryFrom for CallToolResult { +impl TryFrom for CallToolUnstructuredResult { + type Error = RpcError; + fn try_from(value: ResultFromServer) -> std::result::Result { + let matched_type: ServerResult = value.try_into()?; + if let ServerResult::CallToolUnstructuredResult(result) = matched_type { + Ok(result) + } else { + Err(RpcError::internal_error().with_message("Not a CallToolUnstructuredResult".to_string())) + } + } +} +impl TryFrom for CallToolStructuredResult { type Error = RpcError; fn try_from(value: ResultFromServer) -> std::result::Result { let matched_type: ServerResult = value.try_into()?; - if let ServerResult::CallToolResult(result) = matched_type { + if let ServerResult::CallToolStructuredResult(result) = matched_type { Ok(result) } else { - Err(RpcError::internal_error().with_message("Not a CallToolResult".to_string())) + Err(RpcError::internal_error().with_message("Not a CallToolStructuredResult".to_string())) } } } @@ -3618,12 +3661,12 @@ impl TryFrom for LoggingMessageNotification { } } } -impl CallToolResultContentItem { - ///Create a CallToolResultContentItem::TextContent +impl CallToolUnstructuredResultContentItem { + ///Create a CallToolUnstructuredResultContentItem::TextContent pub fn text_content(text: ::std::string::String, annotations: ::std::option::Option) -> Self { TextContent::new(text, annotations).into() } - ///Create a CallToolResultContentItem::ImageContent + ///Create a CallToolUnstructuredResultContentItem::ImageContent pub fn image_content( data: ::std::string::String, mime_type: ::std::string::String, @@ -3631,7 +3674,7 @@ impl CallToolResultContentItem { ) -> Self { ImageContent::new(data, mime_type, annotations).into() } - ///Create a CallToolResultContentItem::AudioContent + ///Create a CallToolUnstructuredResultContentItem::AudioContent pub fn audio_content( data: ::std::string::String, mime_type: ::std::string::String, @@ -3639,23 +3682,23 @@ impl CallToolResultContentItem { ) -> Self { AudioContent::new(data, mime_type, annotations).into() } - ///Create a CallToolResultContentItem::EmbeddedResource + ///Create a CallToolUnstructuredResultContentItem::EmbeddedResource pub fn embedded_resource(resource: EmbeddedResourceResource, annotations: ::std::option::Option) -> Self { EmbeddedResource::new(resource, annotations).into() } /// Returns the content type as a string based on the variant of `CallToolResultContentItem`. pub fn content_type(&self) -> &str { match self { - CallToolResultContentItem::TextContent(text_content) => text_content.type_(), - CallToolResultContentItem::ImageContent(image_content) => image_content.type_(), - CallToolResultContentItem::AudioContent(audio_content) => audio_content.type_(), - CallToolResultContentItem::EmbeddedResource(embedded_resource) => embedded_resource.type_(), + CallToolUnstructuredResultContentItem::TextContent(text_content) => text_content.type_(), + CallToolUnstructuredResultContentItem::ImageContent(image_content) => image_content.type_(), + CallToolUnstructuredResultContentItem::AudioContent(audio_content) => audio_content.type_(), + CallToolUnstructuredResultContentItem::EmbeddedResource(embedded_resource) => embedded_resource.type_(), } } /// Converts the content to a reference to `TextContent`, returning an error if the conversion is invalid. pub fn as_text_content(&self) -> std::result::Result<&textcontent, RpcError> { match &self { - CallToolResultContentItem::TextContent(text_content) => Ok(text_content), + CallToolUnstructuredResultContentItem::TextContent(text_content) => Ok(text_content), _ => Err(RpcError::internal_error().with_message(format!( "Invalid conversion, \"{}\" is not a {}", self.content_type(), @@ -3666,7 +3709,7 @@ impl CallToolResultContentItem { /// Converts the content to a reference to `TextContent`, returning an error if the conversion is invalid. pub fn as_image_content(&self) -> std::result::Result<&imagecontent, RpcError> { match &self { - CallToolResultContentItem::ImageContent(image_content) => Ok(image_content), + CallToolUnstructuredResultContentItem::ImageContent(image_content) => Ok(image_content), _ => Err(RpcError::internal_error().with_message(format!( "Invalid conversion, \"{}\" is not a {}", self.content_type(), @@ -3677,7 +3720,7 @@ impl CallToolResultContentItem { /// Converts the content to a reference to `TextContent`, returning an error if the conversion is invalid. pub fn as_audio_content(&self) -> std::result::Result<&audiocontent, RpcError> { match &self { - CallToolResultContentItem::AudioContent(audio_content) => Ok(audio_content), + CallToolUnstructuredResultContentItem::AudioContent(audio_content) => Ok(audio_content), _ => Err(RpcError::internal_error().with_message(format!( "Invalid conversion, \"{}\" is not a {}", self.content_type(), @@ -3688,7 +3731,7 @@ impl CallToolResultContentItem { /// Converts the content to a reference to `TextContent`, returning an error if the conversion is invalid. pub fn as_embedded_resource(&self) -> std::result::Result<&embeddedresource, RpcError> { match &self { - CallToolResultContentItem::EmbeddedResource(embedded_resource) => Ok(embedded_resource), + CallToolUnstructuredResultContentItem::EmbeddedResource(embedded_resource) => Ok(embedded_resource), _ => Err(RpcError::internal_error().with_message(format!( "Invalid conversion, \"{}\" is not a {}", self.content_type(), @@ -3697,7 +3740,8 @@ impl CallToolResultContentItem { } } } -impl CallToolResult { + +impl CallToolUnstructuredResult { pub fn text_content(text: ::std::string::String, annotations: ::std::option::Option) -> Self { Self { content: vec![TextContent::new(text, annotations).into()], @@ -3737,7 +3781,7 @@ impl CallToolResult { /// Create a `CallToolResult` with an error, containing an error message in the content pub fn with_error(error: CallToolError) -> Self { Self { - content: vec![CallToolResultContentItem::TextContent(TextContent::new( + content: vec![CallToolUnstructuredResultContentItem::TextContent(TextContent::new( error.to_string(), None, ))], diff --git a/src/rust-mcp-schema.rs b/src/rust-mcp-schema.rs index 77108e0..b875747 100644 --- a/src/rust-mcp-schema.rs +++ b/src/rust-mcp-schema.rs @@ -2,5 +2,6 @@ mod generated_schema; /// re-exports +#[cfg(feature = "schema_utils")] pub use generated_schema::schema_utils; pub use generated_schema::*; diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index 59bef77..3868d87 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -197,6 +197,8 @@ mod test_deserialize { )); } + //TODO: add test case for DRAFT version + #[cfg(any(feature = "2025_03_26", feature = "2024_11_05"))] #[test] fn test_server_call_tool_result() { let message = get_message("res_tools_call_1"); diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 94a05a2..69ba073 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -368,6 +368,7 @@ mod test_serialize { )); } + #[cfg(any(feature = "2025_03_26", feature = "2024_11_05"))] #[test] fn test_server_call_tool_result() { let message: ServerMessage = ServerMessage::Response(ServerJsonrpcResponse::new( @@ -387,6 +388,26 @@ mod test_serialize { )); } + #[cfg(feature = "draft")] + #[test] + fn test_server_call_tool_result() { + let message: ServerMessage = ServerMessage::Response(ServerJsonrpcResponse::new( + RequestId::Integer(15), + ResultFromServer::ServerResult(ServerResult::CallToolUnstructuredResult(CallToolUnstructuredResult { + meta: None, + content: vec![], + is_error: None, + })), + )); + + let message: ServerMessage = re_serialize(message); + + assert!(matches!(message, ServerMessage::Response(server_message) + if matches!(&server_message.result, ResultFromServer::ServerResult(server_result) + if matches!(server_result, ServerResult::CallToolUnstructuredResult(_))) + )); + } + #[test] fn test_server_custom_result() { let custom_result: serde_json::Map = json!({

AltStyle によって変換されたページ (->オリジナル) /