From eba6ab0518fa3685935c7dc97bce907ab08394df Mon Sep 17 00:00:00 2001 From: Dale Seo <5466341+DaleSeo@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:50:55 -0400 Subject: [PATCH] docs: align README examples with v2 model API --- README.md | 222 +++++++++++++++--------------------- docs/readme/README.zh-cn.md | 222 +++++++++++++++--------------------- 2 files changed, 188 insertions(+), 256 deletions(-) diff --git a/README.md b/README.md index 7ec71ac6a..68f3343c9 100644 --- a/README.md +++ b/README.md @@ -239,12 +239,11 @@ struct MyServer; impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_resources() .build(), - ..Default::default() - } + ) } async fn list_resources( @@ -254,8 +253,8 @@ impl ServerHandler for MyServer { ) -> Result { Ok(ListResourcesResult { resources: vec![ - RawResource::new("file:///config.json", "config").no_annotation(), - RawResource::new("memo://insights", "insights").no_annotation(), + Resource::new("file:///config.json", "config"), + Resource::new("memo://insights", "insights"), ], next_cursor: None, meta: None, @@ -268,12 +267,12 @@ impl ServerHandler for MyServer { _context: RequestContext, ) -> Result { match request.uri.as_str() { - "file:///config.json" => Ok(ReadResourceResult { - contents: vec![ResourceContents::text(r#"{"key": "value"}"#, &request.uri)], - }), - "memo://insights" => Ok(ReadResourceResult { - contents: vec![ResourceContents::text("Analysis results...", &request.uri)], - }), + "file:///config.json" => Ok(ReadResourceResult::new(vec![ + ResourceContents::text(r#"{"key": "value"}"#, &request.uri), + ])), + "memo://insights" => Ok(ReadResourceResult::new(vec![ + ResourceContents::text("Analysis results...", &request.uri), + ])), _ => Err(McpError::resource_not_found( "resource_not_found", Some(json!({ "uri": request.uri })), @@ -304,10 +303,9 @@ use rmcp::model::{ReadResourceRequestParams}; let resources = client.list_all_resources().await?; // Read a specific resource by URI -let result = client.read_resource(ReadResourceRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +let result = client.read_resource( + ReadResourceRequestParams::new("file:///config.json"), +).await?; // List resource templates let templates = client.list_all_resource_templates().await?; @@ -322,9 +320,9 @@ Servers can notify clients when the resource list changes or when a specific res context.peer.notify_resource_list_changed().await?; // Notify that a specific resource was updated -context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { - uri: "file:///config.json".into(), -}).await?; +context.peer.notify_resource_updated( + ResourceUpdatedNotificationParam::new("file:///config.json"), +).await?; ``` Clients handle these via `ClientHandler`: @@ -397,7 +395,7 @@ impl MyServer { #[prompt(name = "greeting", description = "A simple greeting")] async fn greeting(&self) -> Vec { vec![PromptMessage::new_text( - PromptMessageRole::User, + Role::User, "Hello! How can you help me today?", )] } @@ -411,25 +409,20 @@ impl MyServer { let focus = args.focus_areas .unwrap_or_else(|| vec!["correctness".into()]); - Ok(GetPromptResult { - description: Some(format!("Code review for {}", args.language)), - messages: vec![ - PromptMessage::new_text( - PromptMessageRole::User, - format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), - ), - ], - }) + Ok(GetPromptResult::new(vec![ + PromptMessage::new_text( + Role::User, + format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), + ), + ]) + .with_description(format!("Code review for {}", args.language))) } } #[prompt_handler] impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder().enable_prompts().build(), - ..Default::default() - } + ServerInfo::new(ServerCapabilities::builder().enable_prompts().build()) } } ``` @@ -485,25 +478,22 @@ Access the client's sampling capability through `context.peer.create_message()`: use rmcp::model::*; // Inside a ServerHandler method (e.g., call_tool): -let response = context.peer.create_message(CreateMessageRequestParams { - meta: None, - task: None, - messages: vec![SamplingMessage::user_text("Explain this error: connection refused")], - model_preferences: Some(ModelPreferences { - hints: Some(vec![ModelHint { name: Some("claude".into()) }]), - cost_priority: Some(0.3), - speed_priority: Some(0.8), - intelligence_priority: Some(0.7), - }), - system_prompt: Some("You are a helpful assistant.".into()), - include_context: Some(ContextInclusion::None), - temperature: Some(0.7), - max_tokens: 150, - stop_sequences: None, - metadata: None, - tools: None, - tool_choice: None, -}).await?; +let response = context.peer.create_message( + CreateMessageRequestParams::new( + vec![SamplingMessage::user_text("Explain this error: connection refused")], + 150, + ) + .with_model_preferences( + ModelPreferences::new() + .with_hints(vec![ModelHint::new("claude")]) + .with_cost_priority(0.3) + .with_speed_priority(0.8) + .with_intelligence_priority(0.7), + ) + .with_system_prompt("You are a helpful assistant.") + .with_include_context(ContextInclusion::None) + .with_temperature(0.7), +).await?; // Extract the response text let text = response.message.content @@ -531,11 +521,11 @@ impl ClientHandler for MyClient { // Forward to your LLM, or return a mock response: let response_text = call_your_llm(¶ms.messages).await; - Ok(CreateMessageResult { - message: SamplingMessage::assistant_text(response_text), - model: "my-model".into(), - stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.into()), - }) + Ok(CreateMessageResult::new( + SamplingMessage::assistant_text(response_text), + "my-model".into(), + ) + .with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN)) } } ``` @@ -593,14 +583,9 @@ impl ClientHandler for MyClient { &self, _context: RequestContext, ) -> Result { - Ok(ListRootsResult { - roots: vec![ - Root { - uri: "file:///home/user/project".into(), - name: Some("My Project".into()), - }, - ], - }) + Ok(ListRootsResult::new(vec![ + Root::new("file:///home/user/project").with_name("My Project"), + ])) } } ``` @@ -631,12 +616,11 @@ use rmcp::{ServerHandler, model::*, service::RequestContext}; impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_logging() .build(), - ..Default::default() - } + ) } // Client sets the minimum log level @@ -651,14 +635,16 @@ impl ServerHandler for MyServer { } // Send a log message from any handler with access to the peer: -context.peer.notify_logging_message(LoggingMessageNotificationParam { - level: LoggingLevel::Info, - logger: Some("my-server".into()), - data: serde_json::json!({ - "message": "Processing completed", - "items_processed": 42 - }), -}).await?; +context.peer.notify_logging_message( + LoggingMessageNotificationParam::new( + LoggingLevel::Info, + serde_json::json!({ + "message": "Processing completed", + "items_processed": 42 + }), + ) + .with_logger("my-server"), +).await?; ``` Available log levels (from least to most severe): `Debug`, `Info`, `Notice`, `Warning`, `Error`, `Critical`, `Alert`, `Emergency`. @@ -683,10 +669,7 @@ impl ClientHandler for MyClient { Clients can also set the server's log level: ```rust -client.set_level(SetLevelRequestParams { - level: LoggingLevel::Warning, - meta: None, -}).await?; +client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?; ``` --- @@ -706,13 +689,12 @@ use rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestConte impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_completions() .enable_prompts() .build(), - ..Default::default() - } + ) } async fn complete( @@ -750,13 +732,9 @@ impl ServerHandler for MyServer { .filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase())) .collect(); - Ok(CompleteResult { - completion: CompletionInfo { - values: filtered, - total: None, - has_more: Some(false), - }, - }) + let completion = CompletionInfo::with_pagination(filtered, None, false) + .map_err(|e| McpError::internal_error(e, None))?; + Ok(CompleteResult::new(completion)) } } ``` @@ -766,17 +744,10 @@ impl ServerHandler for MyServer { ```rust use rmcp::model::*; -let result = client.complete(CompleteRequestParams { - meta: None, - r#ref: Reference::Prompt(PromptReference { - name: "sql_query".into(), - }), - argument: ArgumentInfo { - name: "operation".into(), - value: "SEL".into(), - }, - context: None, -}).await?; +let result = client.complete(CompleteRequestParams::new( + Reference::for_prompt("sql_query"), + ArgumentInfo::new("operation", "SEL"), +)).await?; // result.completion.values contains suggestions like ["SELECT"] ``` @@ -802,12 +773,14 @@ use rmcp::model::*; for i in 0..total_items { process_item(i).await; - context.peer.notify_progress(ProgressNotificationParam { - progress_token: ProgressToken(NumberOrString::Number(i as i64)), - progress: i as f64, - total: Some(total_items as f64), - message: Some(format!("Processing item {}/{}", i + 1, total_items)), - }).await?; + context.peer.notify_progress( + ProgressNotificationParam::new( + ProgressToken(NumberOrString::Number(i as i64)), + i as f64, + ) + .with_total(total_items as f64) + .with_message(format!("Processing item {}/{}", i + 1, total_items)), + ).await?; } ``` @@ -817,10 +790,10 @@ Either side can cancel an in-progress request: ```rust // Send a cancellation -context.peer.notify_cancelled(CancelledNotificationParam { - request_id: the_request_id, - reason: Some("User requested cancellation".into()), -}).await?; +context.peer.notify_cancelled(CancelledNotificationParam::new( + Some(the_request_id), + Some("User requested cancellation".into()), +)).await?; ``` Handle cancellation in `ServerHandler` or `ClientHandler`: @@ -891,13 +864,12 @@ struct MyServer { impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_resources() .enable_resources_subscribe() .build(), - ..Default::default() - } + ) } async fn subscribe( @@ -924,9 +896,9 @@ When a subscribed resource changes, notify the client: ```rust // Check if the resource has subscribers, then notify -context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { - uri: "file:///config.json".into(), -}).await?; +context.peer.notify_resource_updated( + ResourceUpdatedNotificationParam::new("file:///config.json"), +).await?; ``` ### Client-side @@ -935,16 +907,10 @@ context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { use rmcp::model::*; // Subscribe to updates for a resource -client.subscribe(SubscribeRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +client.subscribe(SubscribeRequestParams::new("file:///config.json")).await?; // Unsubscribe when no longer needed -client.unsubscribe(UnsubscribeRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +client.unsubscribe(UnsubscribeRequestParams::new("file:///config.json")).await?; ``` Handle update notifications in `ClientHandler`: diff --git a/docs/readme/README.zh-cn.md b/docs/readme/README.zh-cn.md index 5ddfaee5d..84393849a 100644 --- a/docs/readme/README.zh-cn.md +++ b/docs/readme/README.zh-cn.md @@ -237,12 +237,11 @@ struct MyServer; impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_resources() .build(), - ..Default::default() - } + ) } async fn list_resources( @@ -252,8 +251,8 @@ impl ServerHandler for MyServer { ) -> Result { Ok(ListResourcesResult { resources: vec![ - RawResource::new("file:///config.json", "config").no_annotation(), - RawResource::new("memo://insights", "insights").no_annotation(), + Resource::new("file:///config.json", "config"), + Resource::new("memo://insights", "insights"), ], next_cursor: None, meta: None, @@ -266,12 +265,12 @@ impl ServerHandler for MyServer { _context: RequestContext, ) -> Result { match request.uri.as_str() { - "file:///config.json" => Ok(ReadResourceResult { - contents: vec![ResourceContents::text(r#"{"key": "value"}"#, &request.uri)], - }), - "memo://insights" => Ok(ReadResourceResult { - contents: vec![ResourceContents::text("Analysis results...", &request.uri)], - }), + "file:///config.json" => Ok(ReadResourceResult::new(vec![ + ResourceContents::text(r#"{"key": "value"}"#, &request.uri), + ])), + "memo://insights" => Ok(ReadResourceResult::new(vec![ + ResourceContents::text("Analysis results...", &request.uri), + ])), _ => Err(McpError::resource_not_found( "resource_not_found", Some(json!({ "uri": request.uri })), @@ -302,10 +301,9 @@ use rmcp::model::{ReadResourceRequestParams}; let resources = client.list_all_resources().await?; // 通过 URI 读取特定资源 -let result = client.read_resource(ReadResourceRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +let result = client.read_resource( + ReadResourceRequestParams::new("file:///config.json"), +).await?; // 列出资源模板 let templates = client.list_all_resource_templates().await?; @@ -320,9 +318,9 @@ let templates = client.list_all_resource_templates().await?; context.peer.notify_resource_list_changed().await?; // 通知特定资源已更新 -context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { - uri: "file:///config.json".into(), -}).await?; +context.peer.notify_resource_updated( + ResourceUpdatedNotificationParam::new("file:///config.json"), +).await?; ``` 客户端通过 `ClientHandler` 处理这些通知: @@ -395,7 +393,7 @@ impl MyServer { #[prompt(name = "greeting", description = "A simple greeting")] async fn greeting(&self) -> Vec { vec![PromptMessage::new_text( - PromptMessageRole::User, + Role::User, "Hello! How can you help me today?", )] } @@ -409,25 +407,20 @@ impl MyServer { let focus = args.focus_areas .unwrap_or_else(|| vec!["correctness".into()]); - Ok(GetPromptResult { - description: Some(format!("Code review for {}", args.language)), - messages: vec![ - PromptMessage::new_text( - PromptMessageRole::User, - format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), - ), - ], - }) + Ok(GetPromptResult::new(vec![ + PromptMessage::new_text( + Role::User, + format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), + ), + ]) + .with_description(format!("Code review for {}", args.language))) } } #[prompt_handler] impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder().enable_prompts().build(), - ..Default::default() - } + ServerInfo::new(ServerCapabilities::builder().enable_prompts().build()) } } ``` @@ -481,25 +474,22 @@ context.peer.notify_prompt_list_changed().await?; use rmcp::model::*; // 在 ServerHandler 方法内部(例如 call_tool): -let response = context.peer.create_message(CreateMessageRequestParams { - meta: None, - task: None, - messages: vec![SamplingMessage::user_text("Explain this error: connection refused")], - model_preferences: Some(ModelPreferences { - hints: Some(vec![ModelHint { name: Some("claude".into()) }]), - cost_priority: Some(0.3), - speed_priority: Some(0.8), - intelligence_priority: Some(0.7), - }), - system_prompt: Some("You are a helpful assistant.".into()), - include_context: Some(ContextInclusion::None), - temperature: Some(0.7), - max_tokens: 150, - stop_sequences: None, - metadata: None, - tools: None, - tool_choice: None, -}).await?; +let response = context.peer.create_message( + CreateMessageRequestParams::new( + vec![SamplingMessage::user_text("Explain this error: connection refused")], + 150, + ) + .with_model_preferences( + ModelPreferences::new() + .with_hints(vec![ModelHint::new("claude")]) + .with_cost_priority(0.3) + .with_speed_priority(0.8) + .with_intelligence_priority(0.7), + ) + .with_system_prompt("You are a helpful assistant.") + .with_include_context(ContextInclusion::None) + .with_temperature(0.7), +).await?; // 提取响应文本 let text = response.message.content @@ -527,11 +517,11 @@ impl ClientHandler for MyClient { // 转发到你的 LLM,或返回模拟响应: let response_text = call_your_llm(¶ms.messages).await; - Ok(CreateMessageResult { - message: SamplingMessage::assistant_text(response_text), - model: "my-model".into(), - stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.into()), - }) + Ok(CreateMessageResult::new( + SamplingMessage::assistant_text(response_text), + "my-model".into(), + ) + .with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN)) } } ``` @@ -587,14 +577,9 @@ impl ClientHandler for MyClient { &self, _context: RequestContext, ) -> Result { - Ok(ListRootsResult { - roots: vec![ - Root { - uri: "file:///home/user/project".into(), - name: Some("My Project".into()), - }, - ], - }) + Ok(ListRootsResult::new(vec![ + Root::new("file:///home/user/project").with_name("My Project"), + ])) } } ``` @@ -623,12 +608,11 @@ use rmcp::{ServerHandler, model::*, service::RequestContext}; impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_logging() .build(), - ..Default::default() - } + ) } // 客户端设置最低日志级别 @@ -643,14 +627,16 @@ impl ServerHandler for MyServer { } // 在任何可以访问 peer 的处理器中发送日志消息: -context.peer.notify_logging_message(LoggingMessageNotificationParam { - level: LoggingLevel::Info, - logger: Some("my-server".into()), - data: serde_json::json!({ - "message": "Processing completed", - "items_processed": 42 - }), -}).await?; +context.peer.notify_logging_message( + LoggingMessageNotificationParam::new( + LoggingLevel::Info, + serde_json::json!({ + "message": "Processing completed", + "items_processed": 42 + }), + ) + .with_logger("my-server"), +).await?; ``` 可用日志级别(从低到高):`Debug`、`Info`、`Notice`、`Warning`、`Error`、`Critical`、`Alert`、`Emergency`。 @@ -675,10 +661,7 @@ impl ClientHandler for MyClient { 客户端也可以设置服务端的日志级别: ```rust -client.set_level(SetLevelRequestParams { - level: LoggingLevel::Warning, - meta: None, -}).await?; +client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?; ``` --- @@ -698,13 +681,12 @@ use rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestConte impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_completions() .enable_prompts() .build(), - ..Default::default() - } + ) } async fn complete( @@ -742,13 +724,9 @@ impl ServerHandler for MyServer { .filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase())) .collect(); - Ok(CompleteResult { - completion: CompletionInfo { - values: filtered, - total: None, - has_more: Some(false), - }, - }) + let completion = CompletionInfo::with_pagination(filtered, None, false) + .map_err(|e| McpError::internal_error(e, None))?; + Ok(CompleteResult::new(completion)) } } ``` @@ -758,17 +736,10 @@ impl ServerHandler for MyServer { ```rust use rmcp::model::*; -let result = client.complete(CompleteRequestParams { - meta: None, - r#ref: Reference::Prompt(PromptReference { - name: "sql_query".into(), - }), - argument: ArgumentInfo { - name: "operation".into(), - value: "SEL".into(), - }, - context: None, -}).await?; +let result = client.complete(CompleteRequestParams::new( + Reference::for_prompt("sql_query"), + ArgumentInfo::new("operation", "SEL"), +)).await?; // result.completion.values 包含建议,例如 ["SELECT"] ``` @@ -794,12 +765,14 @@ use rmcp::model::*; for i in 0..total_items { process_item(i).await; - context.peer.notify_progress(ProgressNotificationParam { - progress_token: ProgressToken(NumberOrString::Number(i as i64)), - progress: i as f64, - total: Some(total_items as f64), - message: Some(format!("Processing item {}/{}", i + 1, total_items)), - }).await?; + context.peer.notify_progress( + ProgressNotificationParam::new( + ProgressToken(NumberOrString::Number(i as i64)), + i as f64, + ) + .with_total(total_items as f64) + .with_message(format!("Processing item {}/{}", i + 1, total_items)), + ).await?; } ``` @@ -809,10 +782,10 @@ for i in 0..total_items { ```rust // 发送取消通知 -context.peer.notify_cancelled(CancelledNotificationParam { - request_id: the_request_id, - reason: Some("User requested cancellation".into()), -}).await?; +context.peer.notify_cancelled(CancelledNotificationParam::new( + Some(the_request_id), + Some("User requested cancellation".into()), +)).await?; ``` 在 `ServerHandler` 或 `ClientHandler` 中处理取消: @@ -883,13 +856,12 @@ struct MyServer { impl ServerHandler for MyServer { fn get_info(&self) -> ServerInfo { - ServerInfo { - capabilities: ServerCapabilities::builder() + ServerInfo::new( + ServerCapabilities::builder() .enable_resources() .enable_resources_subscribe() .build(), - ..Default::default() - } + ) } async fn subscribe( @@ -916,9 +888,9 @@ impl ServerHandler for MyServer { ```rust // 检查资源是否有订阅者,然后通知 -context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { - uri: "file:///config.json".into(), -}).await?; +context.peer.notify_resource_updated( + ResourceUpdatedNotificationParam::new("file:///config.json"), +).await?; ``` ### 客户端 @@ -927,16 +899,10 @@ context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { use rmcp::model::*; // 订阅资源更新 -client.subscribe(SubscribeRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +client.subscribe(SubscribeRequestParams::new("file:///config.json")).await?; // 不再需要时取消订阅 -client.unsubscribe(UnsubscribeRequestParams { - meta: None, - uri: "file:///config.json".into(), -}).await?; +client.unsubscribe(UnsubscribeRequestParams::new("file:///config.json")).await?; ``` 在 `ClientHandler` 中处理更新通知: