docs: align README examples with v2 model API (#928)

This commit is contained in:
Dale Seo 2026-06-25 20:00:51 -04:00 committed by GitHub
parent f1daa9277e
commit f07ee4ae1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 188 additions and 256 deletions

210
README.md
View file

@ -239,12 +239,11 @@ struct MyServer;
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_resources() .enable_resources()
.build(), .build(),
..Default::default() )
}
} }
async fn list_resources( async fn list_resources(
@ -254,8 +253,8 @@ impl ServerHandler for MyServer {
) -> Result<ListResourcesResult, McpError> { ) -> Result<ListResourcesResult, McpError> {
Ok(ListResourcesResult { Ok(ListResourcesResult {
resources: vec![ resources: vec![
RawResource::new("file:///config.json", "config").no_annotation(), Resource::new("file:///config.json", "config"),
RawResource::new("memo://insights", "insights").no_annotation(), Resource::new("memo://insights", "insights"),
], ],
next_cursor: None, next_cursor: None,
meta: None, meta: None,
@ -268,12 +267,12 @@ impl ServerHandler for MyServer {
_context: RequestContext<RoleServer>, _context: RequestContext<RoleServer>,
) -> Result<ReadResourceResult, McpError> { ) -> Result<ReadResourceResult, McpError> {
match request.uri.as_str() { match request.uri.as_str() {
"file:///config.json" => Ok(ReadResourceResult { "file:///config.json" => Ok(ReadResourceResult::new(vec![
contents: vec![ResourceContents::text(r#"{"key": "value"}"#, &request.uri)], ResourceContents::text(r#"{"key": "value"}"#, &request.uri),
}), ])),
"memo://insights" => Ok(ReadResourceResult { "memo://insights" => Ok(ReadResourceResult::new(vec![
contents: vec![ResourceContents::text("Analysis results...", &request.uri)], ResourceContents::text("Analysis results...", &request.uri),
}), ])),
_ => Err(McpError::resource_not_found( _ => Err(McpError::resource_not_found(
"resource_not_found", "resource_not_found",
Some(json!({ "uri": request.uri })), Some(json!({ "uri": request.uri })),
@ -304,10 +303,9 @@ use rmcp::model::{ReadResourceRequestParams};
let resources = client.list_all_resources().await?; let resources = client.list_all_resources().await?;
// Read a specific resource by URI // Read a specific resource by URI
let result = client.read_resource(ReadResourceRequestParams { let result = client.read_resource(
meta: None, ReadResourceRequestParams::new("file:///config.json"),
uri: "file:///config.json".into(), ).await?;
}).await?;
// List resource templates // List resource templates
let templates = client.list_all_resource_templates().await?; 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?; context.peer.notify_resource_list_changed().await?;
// Notify that a specific resource was updated // Notify that a specific resource was updated
context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { context.peer.notify_resource_updated(
uri: "file:///config.json".into(), ResourceUpdatedNotificationParam::new("file:///config.json"),
}).await?; ).await?;
``` ```
Clients handle these via `ClientHandler`: Clients handle these via `ClientHandler`:
@ -397,7 +395,7 @@ impl MyServer {
#[prompt(name = "greeting", description = "A simple greeting")] #[prompt(name = "greeting", description = "A simple greeting")]
async fn greeting(&self) -> Vec<PromptMessage> { async fn greeting(&self) -> Vec<PromptMessage> {
vec![PromptMessage::new_text( vec![PromptMessage::new_text(
PromptMessageRole::User, Role::User,
"Hello! How can you help me today?", "Hello! How can you help me today?",
)] )]
} }
@ -411,25 +409,20 @@ impl MyServer {
let focus = args.focus_areas let focus = args.focus_areas
.unwrap_or_else(|| vec!["correctness".into()]); .unwrap_or_else(|| vec!["correctness".into()]);
Ok(GetPromptResult { Ok(GetPromptResult::new(vec![
description: Some(format!("Code review for {}", args.language)),
messages: vec![
PromptMessage::new_text( PromptMessage::new_text(
PromptMessageRole::User, Role::User,
format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")),
), ),
], ])
}) .with_description(format!("Code review for {}", args.language)))
} }
} }
#[prompt_handler] #[prompt_handler]
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(ServerCapabilities::builder().enable_prompts().build())
capabilities: ServerCapabilities::builder().enable_prompts().build(),
..Default::default()
}
} }
} }
``` ```
@ -485,25 +478,22 @@ Access the client's sampling capability through `context.peer.create_message()`:
use rmcp::model::*; use rmcp::model::*;
// Inside a ServerHandler method (e.g., call_tool): // Inside a ServerHandler method (e.g., call_tool):
let response = context.peer.create_message(CreateMessageRequestParams { let response = context.peer.create_message(
meta: None, CreateMessageRequestParams::new(
task: None, vec![SamplingMessage::user_text("Explain this error: connection refused")],
messages: vec![SamplingMessage::user_text("Explain this error: connection refused")], 150,
model_preferences: Some(ModelPreferences { )
hints: Some(vec![ModelHint { name: Some("claude".into()) }]), .with_model_preferences(
cost_priority: Some(0.3), ModelPreferences::new()
speed_priority: Some(0.8), .with_hints(vec![ModelHint::new("claude")])
intelligence_priority: Some(0.7), .with_cost_priority(0.3)
}), .with_speed_priority(0.8)
system_prompt: Some("You are a helpful assistant.".into()), .with_intelligence_priority(0.7),
include_context: Some(ContextInclusion::None), )
temperature: Some(0.7), .with_system_prompt("You are a helpful assistant.")
max_tokens: 150, .with_include_context(ContextInclusion::None)
stop_sequences: None, .with_temperature(0.7),
metadata: None, ).await?;
tools: None,
tool_choice: None,
}).await?;
// Extract the response text // Extract the response text
let text = response.message.content let text = response.message.content
@ -531,11 +521,11 @@ impl ClientHandler for MyClient {
// Forward to your LLM, or return a mock response: // Forward to your LLM, or return a mock response:
let response_text = call_your_llm(&params.messages).await; let response_text = call_your_llm(&params.messages).await;
Ok(CreateMessageResult { Ok(CreateMessageResult::new(
message: SamplingMessage::assistant_text(response_text), SamplingMessage::assistant_text(response_text),
model: "my-model".into(), "my-model".into(),
stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.into()), )
}) .with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN))
} }
} }
``` ```
@ -593,14 +583,9 @@ impl ClientHandler for MyClient {
&self, &self,
_context: RequestContext<RoleClient>, _context: RequestContext<RoleClient>,
) -> Result<ListRootsResult, ErrorData> { ) -> Result<ListRootsResult, ErrorData> {
Ok(ListRootsResult { Ok(ListRootsResult::new(vec![
roots: vec![ Root::new("file:///home/user/project").with_name("My Project"),
Root { ]))
uri: "file:///home/user/project".into(),
name: Some("My Project".into()),
},
],
})
} }
} }
``` ```
@ -631,12 +616,11 @@ use rmcp::{ServerHandler, model::*, service::RequestContext};
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_logging() .enable_logging()
.build(), .build(),
..Default::default() )
}
} }
// Client sets the minimum log level // 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: // Send a log message from any handler with access to the peer:
context.peer.notify_logging_message(LoggingMessageNotificationParam { context.peer.notify_logging_message(
level: LoggingLevel::Info, LoggingMessageNotificationParam::new(
logger: Some("my-server".into()), LoggingLevel::Info,
data: serde_json::json!({ serde_json::json!({
"message": "Processing completed", "message": "Processing completed",
"items_processed": 42 "items_processed": 42
}), }),
}).await?; )
.with_logger("my-server"),
).await?;
``` ```
Available log levels (from least to most severe): `Debug`, `Info`, `Notice`, `Warning`, `Error`, `Critical`, `Alert`, `Emergency`. 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: Clients can also set the server's log level:
```rust ```rust
client.set_level(SetLevelRequestParams { client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?;
level: LoggingLevel::Warning,
meta: None,
}).await?;
``` ```
--- ---
@ -706,13 +689,12 @@ use rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestConte
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_completions() .enable_completions()
.enable_prompts() .enable_prompts()
.build(), .build(),
..Default::default() )
}
} }
async fn complete( async fn complete(
@ -750,13 +732,9 @@ impl ServerHandler for MyServer {
.filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase())) .filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase()))
.collect(); .collect();
Ok(CompleteResult { let completion = CompletionInfo::with_pagination(filtered, None, false)
completion: CompletionInfo { .map_err(|e| McpError::internal_error(e, None))?;
values: filtered, Ok(CompleteResult::new(completion))
total: None,
has_more: Some(false),
},
})
} }
} }
``` ```
@ -766,17 +744,10 @@ impl ServerHandler for MyServer {
```rust ```rust
use rmcp::model::*; use rmcp::model::*;
let result = client.complete(CompleteRequestParams { let result = client.complete(CompleteRequestParams::new(
meta: None, Reference::for_prompt("sql_query"),
r#ref: Reference::Prompt(PromptReference { ArgumentInfo::new("operation", "SEL"),
name: "sql_query".into(), )).await?;
}),
argument: ArgumentInfo {
name: "operation".into(),
value: "SEL".into(),
},
context: None,
}).await?;
// result.completion.values contains suggestions like ["SELECT"] // result.completion.values contains suggestions like ["SELECT"]
``` ```
@ -802,12 +773,14 @@ use rmcp::model::*;
for i in 0..total_items { for i in 0..total_items {
process_item(i).await; process_item(i).await;
context.peer.notify_progress(ProgressNotificationParam { context.peer.notify_progress(
progress_token: ProgressToken(NumberOrString::Number(i as i64)), ProgressNotificationParam::new(
progress: i as f64, ProgressToken(NumberOrString::Number(i as i64)),
total: Some(total_items as f64), i as f64,
message: Some(format!("Processing item {}/{}", i + 1, total_items)), )
}).await?; .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 ```rust
// Send a cancellation // Send a cancellation
context.peer.notify_cancelled(CancelledNotificationParam { context.peer.notify_cancelled(CancelledNotificationParam::new(
request_id: the_request_id, Some(the_request_id),
reason: Some("User requested cancellation".into()), Some("User requested cancellation".into()),
}).await?; )).await?;
``` ```
Handle cancellation in `ServerHandler` or `ClientHandler`: Handle cancellation in `ServerHandler` or `ClientHandler`:
@ -891,13 +864,12 @@ struct MyServer {
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_resources() .enable_resources()
.enable_resources_subscribe() .enable_resources_subscribe()
.build(), .build(),
..Default::default() )
}
} }
async fn subscribe( async fn subscribe(
@ -924,9 +896,9 @@ When a subscribed resource changes, notify the client:
```rust ```rust
// Check if the resource has subscribers, then notify // Check if the resource has subscribers, then notify
context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { context.peer.notify_resource_updated(
uri: "file:///config.json".into(), ResourceUpdatedNotificationParam::new("file:///config.json"),
}).await?; ).await?;
``` ```
### Client-side ### Client-side
@ -935,16 +907,10 @@ context.peer.notify_resource_updated(ResourceUpdatedNotificationParam {
use rmcp::model::*; use rmcp::model::*;
// Subscribe to updates for a resource // Subscribe to updates for a resource
client.subscribe(SubscribeRequestParams { client.subscribe(SubscribeRequestParams::new("file:///config.json")).await?;
meta: None,
uri: "file:///config.json".into(),
}).await?;
// Unsubscribe when no longer needed // Unsubscribe when no longer needed
client.unsubscribe(UnsubscribeRequestParams { client.unsubscribe(UnsubscribeRequestParams::new("file:///config.json")).await?;
meta: None,
uri: "file:///config.json".into(),
}).await?;
``` ```
Handle update notifications in `ClientHandler`: Handle update notifications in `ClientHandler`:

View file

@ -237,12 +237,11 @@ struct MyServer;
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_resources() .enable_resources()
.build(), .build(),
..Default::default() )
}
} }
async fn list_resources( async fn list_resources(
@ -252,8 +251,8 @@ impl ServerHandler for MyServer {
) -> Result<ListResourcesResult, McpError> { ) -> Result<ListResourcesResult, McpError> {
Ok(ListResourcesResult { Ok(ListResourcesResult {
resources: vec![ resources: vec![
RawResource::new("file:///config.json", "config").no_annotation(), Resource::new("file:///config.json", "config"),
RawResource::new("memo://insights", "insights").no_annotation(), Resource::new("memo://insights", "insights"),
], ],
next_cursor: None, next_cursor: None,
meta: None, meta: None,
@ -266,12 +265,12 @@ impl ServerHandler for MyServer {
_context: RequestContext<RoleServer>, _context: RequestContext<RoleServer>,
) -> Result<ReadResourceResult, McpError> { ) -> Result<ReadResourceResult, McpError> {
match request.uri.as_str() { match request.uri.as_str() {
"file:///config.json" => Ok(ReadResourceResult { "file:///config.json" => Ok(ReadResourceResult::new(vec![
contents: vec![ResourceContents::text(r#"{"key": "value"}"#, &request.uri)], ResourceContents::text(r#"{"key": "value"}"#, &request.uri),
}), ])),
"memo://insights" => Ok(ReadResourceResult { "memo://insights" => Ok(ReadResourceResult::new(vec![
contents: vec![ResourceContents::text("Analysis results...", &request.uri)], ResourceContents::text("Analysis results...", &request.uri),
}), ])),
_ => Err(McpError::resource_not_found( _ => Err(McpError::resource_not_found(
"resource_not_found", "resource_not_found",
Some(json!({ "uri": request.uri })), Some(json!({ "uri": request.uri })),
@ -302,10 +301,9 @@ use rmcp::model::{ReadResourceRequestParams};
let resources = client.list_all_resources().await?; let resources = client.list_all_resources().await?;
// 通过 URI 读取特定资源 // 通过 URI 读取特定资源
let result = client.read_resource(ReadResourceRequestParams { let result = client.read_resource(
meta: None, ReadResourceRequestParams::new("file:///config.json"),
uri: "file:///config.json".into(), ).await?;
}).await?;
// 列出资源模板 // 列出资源模板
let templates = client.list_all_resource_templates().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_list_changed().await?;
// 通知特定资源已更新 // 通知特定资源已更新
context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { context.peer.notify_resource_updated(
uri: "file:///config.json".into(), ResourceUpdatedNotificationParam::new("file:///config.json"),
}).await?; ).await?;
``` ```
客户端通过 `ClientHandler` 处理这些通知: 客户端通过 `ClientHandler` 处理这些通知:
@ -395,7 +393,7 @@ impl MyServer {
#[prompt(name = "greeting", description = "A simple greeting")] #[prompt(name = "greeting", description = "A simple greeting")]
async fn greeting(&self) -> Vec<PromptMessage> { async fn greeting(&self) -> Vec<PromptMessage> {
vec![PromptMessage::new_text( vec![PromptMessage::new_text(
PromptMessageRole::User, Role::User,
"Hello! How can you help me today?", "Hello! How can you help me today?",
)] )]
} }
@ -409,25 +407,20 @@ impl MyServer {
let focus = args.focus_areas let focus = args.focus_areas
.unwrap_or_else(|| vec!["correctness".into()]); .unwrap_or_else(|| vec!["correctness".into()]);
Ok(GetPromptResult { Ok(GetPromptResult::new(vec![
description: Some(format!("Code review for {}", args.language)),
messages: vec![
PromptMessage::new_text( PromptMessage::new_text(
PromptMessageRole::User, Role::User,
format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")), format!("Review my {} code. Focus on: {}", args.language, focus.join(", ")),
), ),
], ])
}) .with_description(format!("Code review for {}", args.language)))
} }
} }
#[prompt_handler] #[prompt_handler]
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(ServerCapabilities::builder().enable_prompts().build())
capabilities: ServerCapabilities::builder().enable_prompts().build(),
..Default::default()
}
} }
} }
``` ```
@ -481,25 +474,22 @@ context.peer.notify_prompt_list_changed().await?;
use rmcp::model::*; use rmcp::model::*;
// 在 ServerHandler 方法内部(例如 call_tool // 在 ServerHandler 方法内部(例如 call_tool
let response = context.peer.create_message(CreateMessageRequestParams { let response = context.peer.create_message(
meta: None, CreateMessageRequestParams::new(
task: None, vec![SamplingMessage::user_text("Explain this error: connection refused")],
messages: vec![SamplingMessage::user_text("Explain this error: connection refused")], 150,
model_preferences: Some(ModelPreferences { )
hints: Some(vec![ModelHint { name: Some("claude".into()) }]), .with_model_preferences(
cost_priority: Some(0.3), ModelPreferences::new()
speed_priority: Some(0.8), .with_hints(vec![ModelHint::new("claude")])
intelligence_priority: Some(0.7), .with_cost_priority(0.3)
}), .with_speed_priority(0.8)
system_prompt: Some("You are a helpful assistant.".into()), .with_intelligence_priority(0.7),
include_context: Some(ContextInclusion::None), )
temperature: Some(0.7), .with_system_prompt("You are a helpful assistant.")
max_tokens: 150, .with_include_context(ContextInclusion::None)
stop_sequences: None, .with_temperature(0.7),
metadata: None, ).await?;
tools: None,
tool_choice: None,
}).await?;
// 提取响应文本 // 提取响应文本
let text = response.message.content let text = response.message.content
@ -527,11 +517,11 @@ impl ClientHandler for MyClient {
// 转发到你的 LLM或返回模拟响应 // 转发到你的 LLM或返回模拟响应
let response_text = call_your_llm(&params.messages).await; let response_text = call_your_llm(&params.messages).await;
Ok(CreateMessageResult { Ok(CreateMessageResult::new(
message: SamplingMessage::assistant_text(response_text), SamplingMessage::assistant_text(response_text),
model: "my-model".into(), "my-model".into(),
stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.into()), )
}) .with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN))
} }
} }
``` ```
@ -587,14 +577,9 @@ impl ClientHandler for MyClient {
&self, &self,
_context: RequestContext<RoleClient>, _context: RequestContext<RoleClient>,
) -> Result<ListRootsResult, ErrorData> { ) -> Result<ListRootsResult, ErrorData> {
Ok(ListRootsResult { Ok(ListRootsResult::new(vec![
roots: vec![ Root::new("file:///home/user/project").with_name("My Project"),
Root { ]))
uri: "file:///home/user/project".into(),
name: Some("My Project".into()),
},
],
})
} }
} }
``` ```
@ -623,12 +608,11 @@ use rmcp::{ServerHandler, model::*, service::RequestContext};
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_logging() .enable_logging()
.build(), .build(),
..Default::default() )
}
} }
// 客户端设置最低日志级别 // 客户端设置最低日志级别
@ -643,14 +627,16 @@ impl ServerHandler for MyServer {
} }
// 在任何可以访问 peer 的处理器中发送日志消息: // 在任何可以访问 peer 的处理器中发送日志消息:
context.peer.notify_logging_message(LoggingMessageNotificationParam { context.peer.notify_logging_message(
level: LoggingLevel::Info, LoggingMessageNotificationParam::new(
logger: Some("my-server".into()), LoggingLevel::Info,
data: serde_json::json!({ serde_json::json!({
"message": "Processing completed", "message": "Processing completed",
"items_processed": 42 "items_processed": 42
}), }),
}).await?; )
.with_logger("my-server"),
).await?;
``` ```
可用日志级别(从低到高):`Debug`、`Info`、`Notice`、`Warning`、`Error`、`Critical`、`Alert`、`Emergency`。 可用日志级别(从低到高):`Debug`、`Info`、`Notice`、`Warning`、`Error`、`Critical`、`Alert`、`Emergency`。
@ -675,10 +661,7 @@ impl ClientHandler for MyClient {
客户端也可以设置服务端的日志级别: 客户端也可以设置服务端的日志级别:
```rust ```rust
client.set_level(SetLevelRequestParams { client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?;
level: LoggingLevel::Warning,
meta: None,
}).await?;
``` ```
--- ---
@ -698,13 +681,12 @@ use rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestConte
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_completions() .enable_completions()
.enable_prompts() .enable_prompts()
.build(), .build(),
..Default::default() )
}
} }
async fn complete( async fn complete(
@ -742,13 +724,9 @@ impl ServerHandler for MyServer {
.filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase())) .filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase()))
.collect(); .collect();
Ok(CompleteResult { let completion = CompletionInfo::with_pagination(filtered, None, false)
completion: CompletionInfo { .map_err(|e| McpError::internal_error(e, None))?;
values: filtered, Ok(CompleteResult::new(completion))
total: None,
has_more: Some(false),
},
})
} }
} }
``` ```
@ -758,17 +736,10 @@ impl ServerHandler for MyServer {
```rust ```rust
use rmcp::model::*; use rmcp::model::*;
let result = client.complete(CompleteRequestParams { let result = client.complete(CompleteRequestParams::new(
meta: None, Reference::for_prompt("sql_query"),
r#ref: Reference::Prompt(PromptReference { ArgumentInfo::new("operation", "SEL"),
name: "sql_query".into(), )).await?;
}),
argument: ArgumentInfo {
name: "operation".into(),
value: "SEL".into(),
},
context: None,
}).await?;
// result.completion.values 包含建议,例如 ["SELECT"] // result.completion.values 包含建议,例如 ["SELECT"]
``` ```
@ -794,12 +765,14 @@ use rmcp::model::*;
for i in 0..total_items { for i in 0..total_items {
process_item(i).await; process_item(i).await;
context.peer.notify_progress(ProgressNotificationParam { context.peer.notify_progress(
progress_token: ProgressToken(NumberOrString::Number(i as i64)), ProgressNotificationParam::new(
progress: i as f64, ProgressToken(NumberOrString::Number(i as i64)),
total: Some(total_items as f64), i as f64,
message: Some(format!("Processing item {}/{}", i + 1, total_items)), )
}).await?; .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 ```rust
// 发送取消通知 // 发送取消通知
context.peer.notify_cancelled(CancelledNotificationParam { context.peer.notify_cancelled(CancelledNotificationParam::new(
request_id: the_request_id, Some(the_request_id),
reason: Some("User requested cancellation".into()), Some("User requested cancellation".into()),
}).await?; )).await?;
``` ```
`ServerHandler``ClientHandler` 中处理取消: `ServerHandler``ClientHandler` 中处理取消:
@ -883,13 +856,12 @@ struct MyServer {
impl ServerHandler for MyServer { impl ServerHandler for MyServer {
fn get_info(&self) -> ServerInfo { fn get_info(&self) -> ServerInfo {
ServerInfo { ServerInfo::new(
capabilities: ServerCapabilities::builder() ServerCapabilities::builder()
.enable_resources() .enable_resources()
.enable_resources_subscribe() .enable_resources_subscribe()
.build(), .build(),
..Default::default() )
}
} }
async fn subscribe( async fn subscribe(
@ -916,9 +888,9 @@ impl ServerHandler for MyServer {
```rust ```rust
// 检查资源是否有订阅者,然后通知 // 检查资源是否有订阅者,然后通知
context.peer.notify_resource_updated(ResourceUpdatedNotificationParam { context.peer.notify_resource_updated(
uri: "file:///config.json".into(), ResourceUpdatedNotificationParam::new("file:///config.json"),
}).await?; ).await?;
``` ```
### 客户端 ### 客户端
@ -927,16 +899,10 @@ context.peer.notify_resource_updated(ResourceUpdatedNotificationParam {
use rmcp::model::*; use rmcp::model::*;
// 订阅资源更新 // 订阅资源更新
client.subscribe(SubscribeRequestParams { client.subscribe(SubscribeRequestParams::new("file:///config.json")).await?;
meta: None,
uri: "file:///config.json".into(),
}).await?;
// 不再需要时取消订阅 // 不再需要时取消订阅
client.unsubscribe(UnsubscribeRequestParams { client.unsubscribe(UnsubscribeRequestParams::new("file:///config.json")).await?;
meta: None,
uri: "file:///config.json".into(),
}).await?;
``` ```
`ClientHandler` 中处理更新通知: `ClientHandler` 中处理更新通知: