@@ -152,6 +152,7 @@ impl std::fmt::Display for ProtocolVersion {
152152}
153153
154154impl ProtocolVersion {
155+ pub const V_2026_07_28 : Self = Self ( Cow :: Borrowed ( "2026-07-28" ) ) ;
155156 pub const V_2025_11_25 : Self = Self ( Cow :: Borrowed ( "2025-11-25" ) ) ;
156157 pub const V_2025_06_18 : Self = Self ( Cow :: Borrowed ( "2025-06-18" ) ) ;
157158 pub const V_2025_03_26 : Self = Self ( Cow :: Borrowed ( "2025-03-26" ) ) ;
@@ -164,6 +165,7 @@ impl ProtocolVersion {
164165 Self :: V_2025_03_26 ,
165166 Self :: V_2025_06_18 ,
166167 Self :: V_2025_11_25 ,
168+ Self :: V_2026_07_28 ,
167169 ] ;
168170
169171 /// Returns the string representation of this protocol version.
@@ -193,6 +195,7 @@ impl<'de> Deserialize<'de> for ProtocolVersion {
193195 "2025-03-26" => return Ok ( ProtocolVersion :: V_2025_03_26 ) ,
194196 "2025-06-18" => return Ok ( ProtocolVersion :: V_2025_06_18 ) ,
195197 "2025-11-25" => return Ok ( ProtocolVersion :: V_2025_11_25 ) ,
198+ "2026-07-28" => return Ok ( ProtocolVersion :: V_2026_07_28 ) ,
196199 _ => { }
197200 }
198201 Ok ( ProtocolVersion ( Cow :: Owned ( s) ) )
@@ -541,9 +544,12 @@ impl ErrorData {
541544 data,
542545 }
543546 }
547+ /// Resource-not-found error (`-32002`). The server upgrades this to `INVALID_PARAMS`
548+ /// (`-32602`) for peers negotiating protocol `2026-07-28` or newer (SEP-2164).
544549 pub fn resource_not_found ( message : impl Into < Cow < ' static , str > > , data : Option < Value > ) -> Self {
545550 Self :: new ( ErrorCode :: RESOURCE_NOT_FOUND , message, data)
546551 }
552+
547553 pub fn parse_error ( message : impl Into < Cow < ' static , str > > , data : Option < Value > ) -> Self {
548554 Self :: new ( ErrorCode :: PARSE_ERROR , message, data)
549555 }
@@ -2838,7 +2844,55 @@ impl CallToolResult {
28382844 meta : None ,
28392845 }
28402846 }
2841- /// Create an error tool result with unstructured content
2847+
2848+ /// Create a tool-level error result with caller-visible content.
2849+ ///
2850+ /// # When to use this vs `Err(ErrorData)`
2851+ ///
2852+ /// MCP distinguishes two failure modes for a `call_tool` invocation, and
2853+ /// the right one to use depends on **whose problem it is**:
2854+ ///
2855+ /// - **Tool-level error** — `Ok(CallToolResult::error(...))`.
2856+ /// The request was valid and routed to your tool, but executing the
2857+ /// tool failed in a way the caller should see (a query returned no
2858+ /// rows, an external API returned 500, the user's input is plausible
2859+ /// but produced no result, etc.). The caller's MCP client renders the
2860+ /// `content` you provide; your message reaches the user. **This is the
2861+ /// right choice for almost every "the tool ran and didn't work" case.**
2862+ ///
2863+ /// - **Protocol error** — `Err(ErrorData)` with a JSON-RPC code.
2864+ /// The server cannot route the request at all, or an infrastructure
2865+ /// error makes the server itself unusable
2866+ /// ([`ErrorCode::INTERNAL_ERROR`], `-32603`). MCP clients typically
2867+ /// render protocol errors opaquely (e.g. "Tool result missing due to
2868+ /// internal error") — the caller does **not** see your message.
2869+ ///
2870+ /// # Example
2871+ ///
2872+ /// ```rust,ignore
2873+ /// use rmcp::model::{CallToolResult, Content, ErrorData};
2874+ ///
2875+ /// async fn lookup(query: &str) -> Result<CallToolResult, ErrorData> {
2876+ /// // Caller passed a malformed query — the server can't run anything.
2877+ /// // This is a protocol error, the caller's client will render it
2878+ /// // as -32602 invalid_params:
2879+ /// if query.is_empty() {
2880+ /// return Err(ErrorData::invalid_params("query must be non-empty", None));
2881+ /// }
2882+ ///
2883+ /// // Tool ran, no result. Caller should see the explanation:
2884+ /// let rows = run_query(query).await;
2885+ /// if rows.is_empty() {
2886+ /// return Ok(CallToolResult::error(vec![Content::text(
2887+ /// format!("no rows matched '{query}'"),
2888+ /// )]));
2889+ /// }
2890+ ///
2891+ /// Ok(CallToolResult::success(vec![Content::text(format_rows(&rows))]))
2892+ /// }
2893+ /// # async fn run_query(_: &str) -> Vec<&'static str> { vec![] }
2894+ /// # fn format_rows(_: &[&str]) -> String { String::new() }
2895+ /// ```
28422896 pub fn error ( content : Vec < Content > ) -> Self {
28432897 CallToolResult {
28442898 content,
0 commit comments